“static-rendered AI.”

The latency complaint cracked open into the framework’s next move. The operator’s phrasing, after I called per-turn latency hardware-bound: “WHAT IF ITS NOT ‘Hardware-bound’…..what if we we break that door fucking down. think -http static web -> cheng lou pretext…..(breakthrough)”. That line is what this day is named for.

Three sprints in one session. Brainstorm two; plan-mode one; ship both. The cache works in production.

Curriculum SE.3 lands first, sets the tone

werbos curriculum ships a host-side daemon that picks coding problems from a curated bank (15 problems × 5 levels), routes them to werbos’s local LLM via docker exec, and judges the solution via claude -p on the SR8 host. Difficulty adapts: three consecutive passes → level up; two fails → level down, clamped 1-5. Outcomes accumulate in outcomes.csv. (d8fe602)

First live cycle:

cycle=1 level=1 problem=sum-list verdict=pass solve=15.34s judge=6.02s

Werbos solved its first problem. Claude validated it. Pattern locked.

That set the framing for everything that came next: the framework around the local model can be made smart enough that the underlying model stops being the bottleneck. Same model. More structure. More compounded value per inference call.

The “is latency actually hardware-bound?” thread

Mid-conversation. I’d just said the chat-time latency is the one gap framework can’t close on its own — silicon, not cleverness. The operator pushed back. Twenty minutes of riffing later we’d named three layers:

  1. Semantic cache (everyone already touches this).
  2. Offline pre-compute: the big slow model populates the cache overnight; chat-time is lookup.
  3. Radical version: the library stops being prompt instructions and becomes pre-rendered response templates. The chat surface is mail merge with a curated library.

Then the operator named the sharper version: “thats a api call -> fill in blank -> serve…. ( thats not really a good case for AI too…)”. Right. At runtime, with the cache in place, there’s no AI involved at all. SQLite lookup. String interpolation. Serve.

Werbos becomes a static-site generator with an LLM at build time, not a live generator. Frontier-grade UX on local hardware without buying a GPU.

Parsetongue (SE.6) — the operator coined the name

“token parse… my parsetounge….. ‘i have idea’…. -> parsetounge = parse + find intent protocol…. the idea give it anything… it will figure out the intent and pass the data to the ai or lookup tree.” — operator, mid-jive.

Parse + parseltongue. The language that lets you speak to systems most people can’t talk to directly. The name does real work.

What it is: the input layer that takes any operator-typed string and emits a structured Intent object the rest of werbos routes on. The chat surface stops being a syntax accepter (slash commands); it becomes a conversational dispatcher (“my back hurts” → /stretch). With the cache layer behind it, common intents hash to cache rows and serve instantly. Without the cache, parsetongue is still useful — it eats the syntax barrier (the input-layer-gap memory entry’s predicted bridge, landed in code).

SE.6 took plan-mode discipline. Three architecture decisions needed locking before code: where parsetongue lives (in-werbos module, not sibling repo), the security tier (full Day-23 inheritance from day 1 — strip_format_codepoints, trace_turn, PermissionAskRequired, the destructive-action gate), and the versioning strictness (SPEC.md first, observe- style, with _schema = "parsetongue/1" as the load-bearing TIMELESS marker).

Then four days of code in one stretch:

  • Day 1 — SPEC.md + VERSIONING.md + the schema package (Intent frozen dataclass, IntentKind closed enum, OperatorContext, canonical_cache_key). (51860a1)
  • Day 2 — parse() (fast path for /slash, slow path for natural language via LLM classifier with graceful degradation) + route() (per-IntentKind dispatch + destructive-action gate). (b0d4b9e)
  • Day 3 — werbos parsetongue parse CLI + server integration in app.py (env-gated behind WERBOS_ENABLE_PARSETONGUE for safe rollout). (5282540)
  • Day 4 — Deploy to SR8, verify the subcommand reachable and existing skill-smoke + curriculum CLIs unaffected.

72 new tests, every SPEC invariant covered by a regression that names the doc section it’s enforcing.

SE.5 precook — same session, second sprint

The lookup target parsetongue was naming had to exist for the lookup-routing branch to do anything. SE.5 v1 = the cache it points to.

Three days of code:

  • Day 1 — werbos/precook/key.py (canonical key derivation: lowercase + strip + collapse + SHA-256) + werbos/precook/cache.py (SQLite-backed store, WAL mode, TTL eviction, hit-count instrumentation, cache_stats snapshot). (92ce625)
  • Day 2 — PromptSkill.precookable: bool = False opt-in field + cache hooks in run_prompt_skill (check before live inference, write after success, never break the skill on cache error). Starter set: summarize, eli5, quote (knowledge skills, low variance — creative + wellness stay live to preserve freshness). (05f7957)
  • Day 3 — werbos precook operator CLI: stats, evict, clear --yes. Deploy + proof-of-life on SR8. (f65d0fb)

The proof-of-life:

$ time docker exec ... werbos eli5 "binary search"
... live LLM call ...
real    0m10.366s

$ time docker exec ... werbos eli5 "binary search"
... cache hit ...
real    0m0.416s

Same query twice. Same toaster metaphor for binary search both times (proves the cache served, didn’t regenerate). 10.4s → 0.4s, and most of the 0.4s is docker-exec overhead — the SQLite lookup itself is single-digit milliseconds.

Static-rendered AI is real on local hardware. With one SQLite file.

The harness was feeding its own cache

After the merge, werbos precook stats on SR8 showed 4 cache entries and 4 hits — already populated. From who? The SE.1.1 skill-smoke daemon. It runs summarize, eli5, quote every 30 minutes as part of grading skills against format markers, and those happen to be the three skills opted into precook.

The harness has been warming the cache automatically. Same input every cycle, same response from cache after the first miss. The smoke run that used to cost ~30s/skill of live inference now costs sub-second for the opted-in skills.

The systems compose. SE.1.1 produces test data; SE.5 caches identical repeats; the harness gets cheaper to run as it runs more.

Merging both to main

Both feature branches landed cleanly on main via --no-ff merges. One predictable conflict in werbos/__main__.py — both sprints registered new subcommands after curriculum — resolved by keeping both registration blocks. (ab14647 SE.6 merge, bbef0b0 SE.5 merge.)

Full sweep after merge: 884 tests across parsetongue + precook + cli + eval + curriculum, all green.

SR8 deploy pulled merged main and rebuilt; both subcommands present in the container; precook cache entries persisted across the rebuild via the /data volume mount; both daemons recovered (curriculum on host, skill-smoke restarted by systemd).

Numbers worth keeping

  • SE.6 v1 lines shipped: ~1,700 (parser + router + schema + SPEC + VERSIONING + CLI + server integration)
  • SE.5 v1 lines shipped: ~750 (cache + key + integration + CLI)
  • Combined new tests: 120 (72 parsetongue + 48 precook incl. integration)
  • Test suite after merge: 884 pass across parsetongue + precook + cli + eval + curriculum
  • Cache speedup measured on SR8: 10.4s → 0.4s, ~25× (SQLite lookup dominated by docker-exec overhead)
  • Sprints in one session: 3 (SE.5 brainstorm, SE.6 brainstorm+plan+ship, SE.5 ship)
  • Days the operator was away earlier in the week that don’t count toward the 30-day plan: 4

Aphorisms

“frontier model gets smarter every six months; werbos gets a new capability every Tuesday afternoon AND finishes most of the work before the operator asks for it.”

“the chat surface stops being where the AI runs. it’s the delivery mechanism for work that’s already done.”

“the harness was feeding the cache the whole time — the systems compose.”

“parsetongue is parse + parseltongue: the language that lets you speak to systems most people can’t talk to directly.”

Carryover into Day 27

  • Enable parsetongue in the chat surface. Currently gated behind WERBOS_ENABLE_PARSETONGUE=1 in the compose env. Once enabled, "tell me a joke" rewrites to /joke via the server’s diag log; existing slash dispatcher handles the rest.
  • Expand the precook opt-in set based on real hit-rate data. Three starter skills today. The trend CSV from SE.1.1 already knows which other format-stable skills are cache candidates (tip-calc, password-gen, cbt-reframe look right at first glance).
  • Schedule werbos precook evict --older-than 7d as a nightly systemd timer. Without it the table grows monotonically. Lazy-fill never cleans up.
  • The SE.5.1 offline pre-compute layer — overnight batch that walks PROMPT_SKILLS × likely_query_patterns and primes the cache before the operator types. The daemon infrastructure already exists; this is one more loop on top of it.