The map answers the what is questions: training, adapters, hardware, the four operations, the off-grid economic argument. It’s the companion to the log, which answers what just changed.

Big picture (one diagram)

+--------------------------------------------------------------+
|                       BASE MODEL                             |
|       (e.g. Llama-3.2-3B-Instruct, weights frozen)           |
+--------------------------------------------------------------+
                          |  inference time
                          v
+--------------------------------------------------------------+
|     +ADAPTER 1 (~30 MB LoRA delta, your data, your style)    |
|     +ADAPTER 2 (optional, stack as many as you like)         |
+--------------------------------------------------------------+
                          |
                          v
+--------------------------------------------------------------+
|  YOUR HARDWARE: M1 (dev/train, 3B max),                      |
|  SR8 Ryzen (inference, 13B+), Pi 5 (always-on orchestrator)  |
+--------------------------------------------------------------+

If you only memorize one diagram, that’s it. The brain is the base. The skills are the adapters. You stack them at inference. Like Neo plugging in “I know kung fu.”

The four operations

OperationWhat it doesCapacity change
TRAININGNudges weight values via gradient descentSame number of slots, better-tuned values
MERGINGAverages two models’ weights cell-by-cellSame size; new behavior is a blend
CONCATENATIONAdds new layers (Frankenmerge / depth-up)Bigger model, more slots
DISTILLATIONTrains a smaller model to mimic a bigger oneSmaller model, ~most behavior

Merging averages, doesn’t add. Merge a 10B + 10B and you get 10B, not 20B. The way to grow capacity is concatenation.

The five doors on one corpus (Day 105–106)

375 libraries and 167,493 graded cards are one artifact. Everything else is an access pattern over it — which is the whole “the library is the product” claim, made concrete:

DoorQuestion it answersWhere
ANSWER“what does abort() do?” → the one best card, citedcompose/library_lookup.py
READ“what do we know about Spanish?” → every card, grouped/knowledge · compose/knowledge_hub.py
TEACH“teach me Spanish” → a syllabus, a sitting, a Leitner schedule/teacher · compose/course.py
EXPORT“put it in our LMS” → a SCORM 1.2 zipwerbos scorm export · compose/scorm.py
VERIFY“does anything back what was just said?” → GROUNDED / UNSUPPORTED / UNCHECKEDpersonas/truth.py (Day 106)

VERIFY is the door that points inward. The other four answer a person; this one judges a reply, and it is the verdict a model grading its own output structurally cannot produce — a 3B judging itself has no corpus to check against, so its verdict is an opinion about an opinion. This one consults evidence, which is what makes it un-bribable. It convicts only inside a scoped world (a capsule naming its world_library): in an open corpus absence means nothing, which is how a persona came to insist Lisbon was invented. In a bounded one it means everything — no hole 19 in the putt-putt library means there is no hole 19.

And the corpus now has a root. compose/libmerkle.py hashes 167k cards into one number that is identical on two machines in 2.5 seconds. libpath.found() answers how many libraries are visible, which is true of a corpus whose contents are wrong; a root can only agree if the bytes agree. werbos deploy status compares it inside the container, where the cards are actually read — the exact place the ten-day zero-cards failure lived.

None of the five adds content. Teaching was free three times over because the cards already paid for it: correct is explanation-grade, every card carries exactly two distractors (so 3-way multiple choice costs nothing), and Sonnet emits libraries in syllabus order rather than as a bag — so file order is the curriculum and course.py never sorts a topic list.

Two doors make a diagnostic neither one is. library_lookup returns the single best card and discards the ranking, so a near-miss and a genuine absence produce the identical None. knowledge_hub is a second, independent reader with no 0.50 cosine gate, so asking both splits an abstain into honest gap (mint cards) and unreachable (fix retrieval) — opposite fixes that were indistinguishable until there were two readers (scripts/reachability.py).

EXPORT is the distribution wedge. The other three require someone to come to werbos; a SCORM zip rides in on infrastructure the customer already bought, on a budget line that already exists.

The intent hierarchy — default to play, descend on contextual confidence (Day 139). Routing used to fire the heavy lanes (advice, empathy, crisis) on a per-prompt keyword, so it over-escalated: “my team lost the game” got crisis-toned comfort, “what should I do in Hawaii” got a life-decision lecture, “I can’t go on” fell to a random library card. The fix is an inverted-Maslow prior — a person poking a chatbot lives at the top of the hierarchy (play, curiosity), rarely the bottom (crisis) — so routing defaults to play, and each descent to a heavier lane must clear a confidence that is contextual: a running distress trajectory over the conversation, not one message. The crisis gate runs before retrieval and is graded — explicit self-harm → a 988 referral always; an ambiguous “i want to end it” → the trajectory decides (a dark arc escalates to 988, a rage-quit “end this level” stays light, an isolated phrase earns a soft check-in). One contextual signal (compose/intent_hierarchy.py) replaced a pile of per-lane guards. docs/intent-hierarchy.md.

werbosOS — the honest tools (Day 111–112)

The chat app grew a second kind of surface: feature screens — small, client-side tools that take the engine’s one rule and turn it on everyday text. Measure what’s observable; refuse to guess what isn’t.

ToolWhat it measuresWhat it refuses
Prose Fingerprinthow text is written — caps, emoji, rhythm, vocabulary, the words you reach forto say who wrote it, or that they’re anxious / creative / hiding something
Relationship Lensa conversation’s communication regime over time — warmth, tension, distance, each from observable signals (emoji, message length, reply latency, who-initiates)to score how anyone feels — it “records the tremor, doesn’t diagnose the fault”

Prose Fingerprint is the front door of the persona engine — the same style.fingerprint that writes a capsule, made visible. The Lens is a communication seismograph: a scrubbable month timeline where silent months show as shaded gaps and a volume lane keeps a busy reunion from reading as “cold.” Both run entirely in the browser — a private conversation never leaves the machine, which is the local-first promise applied to the most sensitive data there is.

Each screen is the same six pieces (a View, a view-kind, App wiring, a Sidebar button + icon), so the next tool slots in without touching the last — the marketplace pattern, turned on the app itself.

Serving honestly — the launch stack + honest readers (Day 135)

Three tools shipped that all share one shape: do the thing correctly, or refuse out loud.

  • The launch stack — prepping a password-gated public launch meant bounding the box. SR8 is memory-bandwidth bound (~8 concurrent owned generations before the knee), so a concurrency gate caps owned-gen there and queues honestly (“you’re #N in line”); a per-session rate limiter is the guest flood valve (operator exempt); a live pressure gauge on GET :8097/ reports the fall-through rate — the master capacity dial. And the one that matters most: the owned-brain server can never fall through to the operator’s silo — a sid-less public request mints a fresh isolated silo, never lands in the operator’s chats.
  • The OCR reader (werbos ocr) — a small ONNX engine reads text off an image with a confidence per box, so a region it can’t read abstains instead of fabricating. Same honesty the whole system runs on, applied to pixels.
  • Topic images (topic_image) — fill a page’s image slot from a topic (real photo → generated → keep the placeholder), SSRF-guarded and inlined. “A website about dogs” gets actual dogs, or an honest empty box.

Why local-first wins economically

SetupCost @ 24h continuous agentNotes
Cloud LLM API~$50/dayToken-billed; you stop using when you sleep
Your laptop / SR8~$0.03/dayJust electricity; runs while you sleep

Three orders of magnitude. That’s the whole thesis behind werbos.

The MMM forest — change the library, not the model

The four operations above all change the model. The MMM (Micro-Model-Forest) direction is a fifth lever: leave the model fixed and change the library it walks. A forest is a content-addressed library of leaves — retrieved at the point of need and injected into a small model’s context, so a 7B uses the right fact instead of half-remembering it.

leaf typewhat it ishow it proves itself
nounretrieved content (a wiki article, an API signature)a Merkle hash — the content is exactly what it claims
verba gradeable operation (add-test, fix-type-error)a free grader — compile, test, run; no grader → it’s a vibe

The coding forest (mmm-poc) points this at code: 600+ real JS/Node API signatures + operation capsules, routed outside the model, graded by tools that can’t be sweet-talked. The benchmarks (B.1–B.6) measure the one question that matters — does the library make a small model beat its raw self? — and the answer holds: it wins where the answer is underivable (your repo, a stale API, a footgun), ties where the model already knows, and never loses once the retrieval is gated.

The dogfood loop makes the library learn. Every graded run is an experience; the library grows (crystallize a blind-spot win into a new alias/skill) and prunes (garbage-collect the unused) — both review-gated and reversible — while passing runs bank certified training pairs. The newest of these loops, HAIRLy, drives the eval through the product: Claude simulates a real user in the chat UI, grades the reply, and reduces two judges to one verdict (the Y). It’s a self-fuzzer — Claude paraphrases each seed into the messy ways real people ask, so phrasing-sensitivity bugs surface on their own — and it runs multi-turn: a roster of user personas (Danielle and five others — the ones asking, each a different typing voice, distinct from werbos’s own cleo/trump/dickinson output voices) holds a whole conversation, graded on the arc (context retention, consistency, boundary-over-time), not just single replies. Varied voices are the point: the same question in a bubbly vs a terse register caught tone hijacking the router. Being internal tooling, it runs on the subscription (claude -p), never the metered API. Crucially its grades are labels and test cases, never weights — a reject routes to a fix layer and becomes a new scenario, so the loop finds bugs a robotic query never would (its first turn caught the teacher lane eating a fact question, and fixing it unmasked a confidently-wrong poisoned card) without ever training werbos to imitate the grader. The endgame is the north star: move enough work from the model into the library that the generator can shrink from a borrowed open-weight model to a small model we own, then drop the borrowed weights entirely. Stated as a target you can hold us to: the day the forest wraps a model we trained and still beats the open-weight baseline on verifiable coding. The Benchmarks page is the scoreboard for that migration, run in the open.

Composer-only — how small can the model get? (B.7). If the forest is the brain, the model is only the constructor — it doesn’t need to know how to code, just which verbs and leaves hold the rules, and then it stitches. So the inverse of the question above: fix the library, shrink the model, and find the floor. Swept 7B → 0.5B, the forest beats blind at every size and a 3B-in-forest ≈ 7B-in-forest — the library buys back the size — down to a minimum-composer floor around 3B. A knowledge-leak test (a fact only the library holds, library removed → the model must fail) stays SEALED, and on the chat side the answers are zero-UNSOUND: when right, they’re right from the leaves, not the weights. The consequence: the model commoditizes, the curated brain becomes the moat — and unlike weights, the library compounds every Tuesday.

The library grows itself — seek-compute-cache (Day 67, compose/resolve.py). The forest above grounds against a fixed library; resolve() lets the brain grow one from the open web. A query walks LOOKUP → SEEK → COMPUTE → VERIFY → CACHE behind three gates, and only verified results enter the library — learning is a durable, cited cache write, never a weight nudge. On top sits the newest evidence for “the model commoditizes, the library is the moat”: an owned byte-level conversation model, trained from scratch on the GPU, now answers the dashboard’s Custom-model toggle live on the homelab (CPU) — and a GPU size-sweep found the crossover (size is dead weight on thin data, the lever once the corpus is rich: 5M 70%→46% as data tripled, 30M→79%). The honest counterweight: a from-scratch reader over a fresh JS+TS library hit the comprehension wall at chance, and a TF-IDF baseline at chance proved it’s the task, not the size. So the split holds by measurement — the owned model carries conversation, the library carries knowledge.

The machine became fully owned (Day 68, compose/{codegen,execute,owned}.py). A creation tier added code generation graded by EXECUTION (run it in a hardened sandbox, return only what ran green, else abstain) with owned patterns tried first, and a domain-spec factory made new libraries a JSON spec. Then the closer: an offline/lite mode giving all three rented seams owned, model-free fallbacks — extractive read, deterministic grounding grader, library seek — so --net off runs the whole loop with the web AND Claude unplugged. The milestone isn’t “owned and as good as the frontier” (offline quality drops magnitudes, by design); it’s that everything still rented is rented by choice, not by necessity — pull every external cord and the machine still answers, or honestly abstains. That is the definition of owning it. The remaining gap is coverage, a minting problem, not a wall. Story: Wrapper to Owner.

Reasoning — search against a verifier (v0). The forest is brain storage; it doesn’t, alone, think. The reasoning brick turns thinking into search against a validator, the one thing MMM is uniquely built for. Decomposed: REASON proposes a step (generative, fallible), LOGIC validates it (external, sound — a type checker, node --test, a property check), and THINK is the search over both. It runs as proof-of-work mining — spawn N miners down different paths, a sound chain is hard to find but cheap to validate, first to surface a validator-passing block wins, else abstain. v0 (one ply, no search depth yet) proved the shape on a 13-task verifiable benchmark, and surfaced the key move: a miner can propose a program instead of a prose answer — executed and graded like a verb leaf — so enumeration tasks a 7B can’t do in its head (count the combinations) get computed and certified. That’s the reasoning↔forest bridge: the implement-function verb pointed at thought. Airtight exactly where the validator is hard-formal; honest floor where there’s no verifier (taste, open leaps). Lives in mmm-poc; not yet wired into a live chat turn.

Library at scale — mmm-brain. The sibling that varies the library instead of the model. Three findings, all frozen: the noise that drowns a fact is a property of semantic retrieval, not library size (lexical shrugs off 160× distractors); routing to a domain sub-tree never improves retrieval (it removes cross-domain noise that never competed — the noise that hurts is same-domain look-alikes, Array.toSorted vs Array.sort); and the lever that does move is leaf enrichment — a capable model, working offline and blind to the eval, writes “what you’d ask for this” onto each leaf, lifting a small stack’s recall from 3/10 to 9/10 with the online model unchanged. The librarian is a frontier model run once, offline; the reader stays tiny and local; the gold grades it, never the librarian.

The kernel — recursive completion. The generalization the whole forest turned out to be an instance of. A query is a silhouette: every node opens into a subset of information it implies but never stated — “a park” implies daylight, green, clothed people — and you recurse into the library, inheriting that context downward, until no hole remains. That completion is what makes an image, a story, a sentence real — real = fully grounded, no unfilled implication left. One structure, different leaves: image, story, person (the personas), code (the verb-forest), memory. That’s the domain-blind engine, proven by the shape reappearing every time something works — and the bet it implies: realness scales with the depth of the library and the recursion, not the size of the model. The tree was never a search structure; it’s a completion structure — a generative grammar grounded in a living, cited library. It is now running code: werbos/compose/ completes a silhouette into a grounded tree and can re-resolve a single failed node without re-rolling the whole artifact (the man isn’t smiling — fix the man, not the park), with an image and a story falling out of the same engine. (Written up in full at docs/vision/recursive-completion-kernel.md.)

The kernel gets a reader — and learns to think (Day 58). Every move the kernel made was arithmetic over the library, so it was blind to negation and paraphrase and stamped GROUNDED on whatever shared words. So it got the organ it lacked: a fenced reader — a small local model that reads the retrieved candidates and picks the one cited leaf that answers, or abstains (a made-up pick reads as abstain), with a separate grader that may only ever downgrade a pass, never invent one (cursor, not knower, per VERDICTS). Same corpus, swap only the reader: arithmetic baseline 45% / 6 lies → 7B reader 55% / 0 lies — retrieval already held the answer 91% of the time, so the win is reading, not retrieving. Then the reader learned to think: reason.py decomposes a query into the sub-questions it implies, recurses, grounds each hole or names it as a gap — a node is real only when every sub-hole is. This is the same search-against-a-verifier move as the reasoning brick above, ported from formal code to prose: the “validator” is the fenced grader plus honest-abstain instead of a type checker, and the answer is composed from cited leaves or refused. Day 107 swapped who decomposes: a typed reasoning card states its own sub-questions in needs, so the library supplies the split deterministically and the model is only asked when no card matches — and each card carries a check that rejects its own output, so a failed step becomes an abstain instead of an answer. On our pinned 336M that moved confident wrong answers 32 → 1 while capability stayed put: capability is bought with parameters, honesty with a harness. Driven to failure on the real 2342-chunk client corpus it grounds confident garbage — and that is the point. The binding chain is corpus quality → retrieval recall → reader → grader → loop, the loop at the end; the fence is a near-free honesty win on open corpora but on a closed high-recall lookup an always-commit re-ranker leads on accuracy. Refined thinking, pushed to its edge, points a finger at exactly where the real constraint lives — the library — which is the whole bet, stated one more way: vary the library, not the model.

Day 110 made reasoning a primitive — and gave it a forward gear. compose/reason_tree.py content-addresses every step (Merkle), so the decomposition converges to base cases, a repeated subgoal is proven once, and an unprovable branch is an honest ∅ gap. Its sequel, the synthesis tier (compose/synthesize.py / synthesize_reasoned.py), inverts the same loop to build past what’s stored: an intent decomposes to eternal primitives, composes upward, and is RUN — a verified artifact (“leaderboard v99” from parts that exist) or an abstain, never a faked one. Retrieval is what exists, abstain is what I don’t know, and this is the tier above — what doesn’t exist yet, derived and verified. Same honest spine, pointed forward. Day 124 hardened this into the chat’s live path — the engine does the work, the model gets out of the way. compose/puzzle_solver.py handles finite constraint puzzles the way honesty demands: don’t generate a proof (a 1B hallucinated a gibberish one for 77 s), enumerate every arrangement and verify — reporting the unique solution, or “underdetermined” / “contradictory” when the puzzle itself is broken (it caught two such puzzles in milliseconds). compose/session_memory.py makes the running conversation its own retrievable card library — the user’s words about their world outrank any hub card, so a fact stated ten turns ago resurfaces grounded, constant-memory not context-window. And compose/grounding_guard.py gates every voiced answer on the fact’s anchors (numbers, proper names strict; framing words loose), so a looser mouth can paraphrase but can’t drift off the fact or ground on an off-topic card. All three are the same move as the reasoning brick — retrieve, verify, enumerate; never generate-and-hope — the shape of the 30B fight: out-structure, don’t out-generate. Day 143 extended the same spine to conversation itself: compose/topic_extract.py finds the topic in any phrasing not by matching frames (a losing game against gen-z, slang, typos) but by subtracting the finite wrapper — tag each token filler/intent/connector/stopword, the residue is the topic — then grounds the residue, so “yo vibe about 2jz fr fr” answers from cards while a bare share is never force-grounded; compose/var_memory.py lets a variable declared one turn be used the next and a place named one turn resolve later; and the whole session is now forwarded front-door → brain so every conversation’s memory is its own (a fresh chat inherits nothing), with a deterministic guard that refuses any riff claiming lived history werbos can’t have. And the whole stack finally has a body plan: senses + tongue in the head, a four-container brain, a pacemaker heart — the tongue in the head, not the brain, because speaking is not knowing.

And then the cursor became swappable (Day 60). With the loop refined, the last gap was that the reader was welded to a weak local model. But the reader is a cursor, not a knower — so its model is config, not code. make_reader_chat(spec) now drives the same library with local Ollama, the Anthropic API, or the claude CLI (reusing Claude Code auth, no key); the library never leaves the box, only the query + retrieved leaves do. That closes the loop on the thesis: keep the curated, cited, local library as the moat, and turn the model into a dial you set — as cheap and as sharp as you like — rather than a thing you’re stuck with. (A deterministic corpus refiner raised the library into clean fact-leaves, and a frozen reasoning bench now keeps the whole thing honest by number, not anecdote — it twice overruled a plausible plan the week it shipped.)

And then the reader became a brain (Day 61). One reader over one corpus became a runtime pipeline over many libraries: a reflex cache answers common turns with no model; a model-free intent weld routes a question to the library it’s most characteristic of (or abstains at the door); the fenced reader grounds it; and a fenced fluent renderer phrases the facts naturally without letting fluency smuggle in a hallucination. Around it runs the Honest Loop — use → judge → grow a living gold set → diagnose the miss by fix layer → fix it (enrich the query from the leaves, or measure the local↔frontier reader gap and distill) → gate — the feedback loop that made a frontier model’s weights good, run cheaply over daily use with the operator as the un-bribable grader. Its Month 2–3 finding: a better question only banks once the reader can hold the answer — fused retrieval is a wash on the local reader and a win on the frontier, and that gap is distillable. The framing underneath it: the brain is a thin wrapper, the sibling repos are its organs, and the one part you can’t hand-roll — the reasoning weld — is a thing to shrink, not to out-pretrain (docs/brain-nervous-system.md, docs/honest-loop-plan.md). Use it now: werbos brain "<question>" --registry libs.json.

And then we stopped borrowing the model (Day 63). “A thing to shrink, not out-pretrain” is an invitation — so we took it, and built the reader from nothing. werbos/weld/ is a hand-rolled model stack with no open weights and no ML framework (stdlib + numpy): an owned byte-level tokenizer trained on your corpus (lossless by construction), a numpy transformer runtime (the weld: cursor at the same make_reader_chat seam), a reverse-mode autograd engine + Adam trainer (every op checked against a finite-difference gradient), a distiller that trains the model on the frontier teacher’s picks — gated by the reader-gap, student lies ≤ teacher — and a freeze step that seals weights + tokenizer + the trust scorecard into one content-addressed, signed, fail-closed brain. It kept the one rule that makes any of it trustworthy: even an untrained, obviously-not-good-enough model can only ever abstain at the fence, never lie. Not GPT-4 — but GPT-3-level on your domain, ours end to end, because the library carries the knowledge and the weld only has to read. The ladder is built; what’s left is empirical — grow the teachable set from real use and measure whether owned-local matches the teacher on-domain. This is the werbos thesis reaching its end state: own the whole stack, keep the model small, let the library be the moat.

And then anyone could mint one (Day 65). The whole ladder collapsed into the Factory — werbos weld dashboard|mint, one call and one live page that streams a mint end to end (tokenizer → reader-gap → grade → distill → gate → freeze), with a bring-your-own-corpus on-ramp that turns your docx/pdf/xlsx/json into the feedstock. The thesis, made operable. And the honest measurement landed the same day: a GPU-scaled sweep — 8k synthetic pairs, models 3.4M–57M, adversarial decoy data — all sat at 3–6/19, half the 1M-param champion’s 12/19, proving the lever is data quality (real teacher-picked fences over real leaves), not model size or data volume. The v2 ruler closes two buried questions so a perfect 19 is honestly reachable; relate (opposites) remains the wall no from-scratch reader clears — champion included.

And then we trained it — and built a ruler to keep ourselves honest (Day 63). Fed real questions, the from-scratch reader learned — 15 of 16 held-out questions it had never seen, which is generalization, not a lookup table. But the grader (does this passage answer, yes/no?) refused to learn — it memorized and collapsed to a constant even at six times the data. That split is the whole design constraint (docs/memory-and-learning.md): the weld should hold skills, the library should hold facts, and memorization in the weights is a smell — abstention, it turns out, is a memory-boundary judgment to compose from cheap retrieval pieces, not a skill to bake in. To measure any of this without fooling ourselves, we built the Gauntlet — a frozen, held-out, deterministically-scored reasoning ladder (retrieve → read → relate → chain) that grades any cursor on two axes: how far it reaches, and — the werbos crown jewel as a number — whether it abstains or lies when it fails. Its first verdict was against us: a general weld reached ~L1.5 at 12% honesty, between the arithmetic floor (L1.75 / 0%) and the Claude ceiling (L1.99 / 100%) — it generalizes but reads no better than retrieval and bluffs, so don’t wire it yet. That is the point of building the un-bribable grader first: it tells you the truth even when the truth is “not good enough, and here’s exactly why.” The loop — train on a separate hub, measure on the sealed vault, never cross the two — is now the trust curve we get to watch climb.

And then it learned to never lie, and to improve itself (Day 64). Two organs closed the loop into something you can leave running. First, honesty: a tiny model can’t learn to abstain, so we made the system honest with an adversarial cascade — cheap local checks escalating to Claude reviewers in separate contexts whose only job is to refute the pick (an idea straight off a Fireship video on adversarial code review). The picker is biased to commit; the reviewers are biased to reject; the gap is the honesty. On the sealed Gauntlet it took honesty from 12% to 100% — seven lies to zero — with capability untouched. Second, self-improvement: with a gate that can’t be fooled, the old stability-harness question — does self-modifying build up or tear down? — finally became safe to run. The daemon does a cycle at a time: the teacher writes new questions on the weak levels, the model distills them, and it’s adopted only if the sealed Gauntlet says it didn’t get worse. Live, it took capability from 9 to 13, then threw out a regression on the next cycle while the champion held — up, then up, then held; never down. So the owned stack now learns, never lies, and gets smarter each day without being able to degrade — every claim certified by a ruler it never trained on. It still doesn’t wake up conversational (that wall is a bigger model on a GPU, honestly deferred), but grounded, honest, sovereign reading that improves on its own is no longer a plan — it’s running. Milestones: docs/ACHIEVEMENTS.md.

The training-fuel factory — how the corpus gets made (Day 108)

The MMM forest is about using the library; this is about making it. One domain map (the 374 /graph domains) drives three data pipelines, all seeded from the same subjects, all governed by one rule — cards are retrieval, prose is fluency, and neither leaks into the other:

pipelinewhat it produceswhere it lands
fluency corpus (wiki_fluency, stackexchange_fluency, gutenberg_fiction)three registers of PROSE — expository, conversational-technical, narrativethe tongue’s base weights (babble, never retrieval)
conversation mint (scenario_matrix + mint_grounded)card-grounded dialogue in US-weighted attributed personas with regional vernacularfine-tune pairs for the tongue
card factory (mint_cards: expand / grow-topics / new-domains)new concept cards — deepening topics, widening domainsthe retrieval library (graded first, never weights)

Each runs against any OpenAI-compatible teacher, so a burst-rented GPU (~$3–4/hr) mints at concurrency and tears down — the expensive-to-get data, gathered cheaply. The teacher is a factory tool that never ships; it distills into the owned model and the graded library. The moat line holds through all three: the conversations teach the tongue how to talk about a domain; the facts stay in retrieval. This factory is the 2.5 → 3.0 fuel.

The marketplace — compose your model from packs

“Change the library, not the model” becomes something the user does. If capability is cursor × library, then the product is the model you assemble: your model = base + /skills + knowledges + models(others'). Everything is one primitive — a pack (a knowledge library, a skill, or a whole saved recipe) with a small manifest (kind, visibility, verified).

  • Compose — werbos pack new/add snaps packs onto the base cursor; a model’s paths are exactly what resolve() answers from, so it genuinely knows its packs and abstains on the rest. Upgrading is just adding a pack — no retrain, non-destructive.
  • Publish + install — a serverless shared catalog (catalog.json + a source; filesystem or http tarball). Public listing is gated on verification — you can’t advertise a pack you haven’t graded, so the grader is the catalog’s bouncer.
  • Kinds of pack — knowledge (facts, graded by the cold-check grader) and skill / capability (things it can do, verified by execution or rules). The first capability pack is tic-tac-toe: a minimax engine that plays perfectly, verified by rules not a model, and pack-gated — a model can play only if it composed the pack.
  • A third kind — speak packs (Day 83, compose/speak_packs.py). A way of talking you snap on: pirate, lolcat, shakespeare, cockney, gen-z, corporate. Each is a StylePack (lexicon + tics + interjections + its own detector), applied to owned source text at a blend (0 → full) and gated by two graders — does it read as the style, and does it still mean the source (round-trip). New register = ~15 lines of data, engine untouched. capability = model × library for voice.
  • Why it’s uncopyable — sovereignty is permission. Frontier labs win the head; werbos wins the tail they’re forbidden to touch (your niche, your stance, your game). Local-first is the liability shield: werbos is the compose layer, not the host. See docs/ideas/the-marketplace.md.

And then the store grew a body (Day 70). The pack system got a Compose Workbench — load a model, snap on packs, extend it, and talk to it live on one page wired to the real resolve(). The offline reader grew a conscience (abstain when a question’s subject isn’t in the library, never echo the question back — the honest-abstain moat, held on the offline path too). werbos scan <path> learned to crawl a folder into a small grounded memory card of what it is — no ingest, no model, no bluff — the first brick of a tree of little models, one per project folder (the original “Merkel Mini Models” idea maturing). And the conversational wall from Day 64 started coming down the honest way: a two-lane conversation-corpus engine — a GPU box bursting high-quality turns while the homelab drips a disjoint topic set 24/7, both into one deduped file — minting the tens of thousands of natural pairs a GPT-2-size talk model needs. Teacher models are factory tools, never shipped. The blueprint for selling all this — Minting-as-a-Service (login → mint → download a model that’s yours, small enough to run offline) — is mapped seam by seam in docs/ideas/minting-as-a-service.md.

And then it got trained, and the ruler judged (Day 71). The compose→mint→talk experience went live at /demo — pick from the real library or import a ~5-page document (in-browser .docx, no claude), then chat with the composed model via a client-side honest-abstain reader that answers from what you gave it and refuses the rest. And the owned talk model got trained for real: a size sweep on the 77k-pair corpus (werbos convo pull gathers + grades both mint lanes into it) gave an honest verdict against the obvious plan — the 30M won (held-out 1.183); 85M and 125M got worse. Not overfitting (their train loss was higher too) but undertrained — a 135M model starved of steps by a CPU-bound loader that made it take 2.36 hours for 6k steps. The lesson is pure werbos: ship the 30M (smaller, faster, best), and fix the pipeline before scaling — measurement over ambition, every time.

And then it learned what kind of question it was holding (Day 75). Everything above assumes the input is a lookup — and a flood of real chat turns showed that assumption is where the lies come from. Asked “what is in the bucket besides 2 apples?”, a retrieval brain keyword-matched a token bucket networking card and said it with a straight face. Keyword overlap always returns something: confidence is free, being right isn’t. So the chat gained a discrimination cascade — figurative → speech-act → small talk → code → reasoning → resolve() — where each gate classifies the move before anything reaches retrieval. The new brick is the intelligence layer (compose/comprehension.py): a word problem is computed from the sentence, not stored in a card, so a reasoning gate catches state/count/negation asks and hands the model a state-tracking scaffold (decompose → track state → answer only what’s literally asked) that resists the “besides 2” distractor — “3 apples in, one out, what’s in there besides 2 apples?” → “1 apple.” Same 3B, no new weights: intelligence is a scaffold, not a weight — the “vary the library, not the model” thesis extended one rung, from what it knows to how it thinks. And when the scaffold can’t crack it, it abstains instead of falling through — falling through to retrieval is exactly how you get a token bucket. The same day, tarot stopped being a rented freewheel (qwen2.5:14b improvising a spread) and became what everything else here already is: 480 gradeable cards and a seeded, exact-hit composer that runs offline. Honest boundary: brick 1 is a discriminator plus one scaffold — temporal, self-referential, and multi-hop reasoning are still open.

The system, end to end

The diagrams above are about LLMs in general. This section is about werbos specifically — the actual piece of software that runs on your laptop and your SR8 and (eventually) your phone.

Five layers in one diagram

+--------------------------------------------------------------+
|  CLIENTS                                                     |
|    CLI   |   Dashboard SPA   |   Slack   |   MCP   |   API   |
+--------------------------------------------------------------+
                          | HTTP / stdio
                          v
+--------------------------------------------------------------+
|  SERVER  (werbos serve -- Starlette + uvicorn)               |
|    /api/chats   /api/agents   /api/tasks   /api/runs         |
|    /api/budget  /api/activity /api/models  /api/channels     |
+--------------------------------------------------------------+
                          |
                          v
+--------------------------------------------------------------+
|  SESSION                                                     |
|    ChatSession -> Agent loop -> ContextBuilder               |
|    persona | memory | tools | mirror | leash | budget gate   |
+--------------------------------------------------------------+
                          |
                          v
+--------------------------------------------------------------+
|  AGENT LOOP  (pitts)                                         |
|    think -> act (tools) -> observe -> repeat                 |
+--------------------------------------------------------------+
                          |
                          v
+--------------------------------------------------------------+
|  BACKEND                                                     |
|    Ollama (default) | MLX | Bellman streaming HTTP           |
|    -> base model + LoRA adapter (see diagram above)          |
+--------------------------------------------------------------+

A request comes in at the top. Each layer narrows the job. The backend at the bottom is the only thing that touches GPU/CPU weights. Everything else is plumbing — deliberately, so the weights can be swapped (Llama / Qwen / Mistral / your fine-tune) without re-plumbing the rest.

The input + output layers (Sprints SE.5 + SE.6, shipped 2026-05-30)

Two more layers landed late in the arc, both about closing the gap between “local LLM is slow” and “local LLM feels fast for the operator.”

       operator types anything
                |
                v
+--------------------------------------------------------+
|  PARSETONGUE   (SE.6 -- werbos.parsetongue)            |
|    parse + parseltongue                                |
|    raw string -> structured Intent                     |
|    fast path: "/joke ..." -> kind=skill, name=joke     |
|    slow path: "my back hurts" -> kind=skill,           |
|                                  name=stretch          |
|    low confidence -> kind=unclear + clarify options    |
+--------------------------------------------------------+
                |
                v
+--------------------------------------------------------+
|  PRECOOK CACHE  (SE.5 -- werbos.precook)               |
|    SQLite key/value, TTL-evicted, opt-in per skill     |
|    cache hit  -> serve in <50 ms (no LLM)              |
|    cache miss -> fall through to live inference,       |
|                  write result back for next time       |
+--------------------------------------------------------+
                |
                v
        [ existing SERVER / SESSION / AGENT LOOP / BACKEND ]

Together they implement static-rendered AI: the chat-time path stops being where the model runs for the 80% of operator usage that repeats. Parsetongue eats the syntax barrier; precook eats the latency barrier. Live inference fires only on genuinely novel input.

Parsetongue is the input layer. Type “tell me a joke about ssh tunnels” and it resolves to kind=skill, name=joke, high confidence, with the rest as slots. Type “i have idea” and it returns kind=unclear with three buttons. The slash commands you already know are the fast path; the natural-language path is the new ergonomics. SPEC-locked at parsetongue/1; full design at /docs/parsetongue/.

Precook is the output cache. A skill opts in by setting PromptSkill.precookable=True; the cache hooks slot into run_prompt_skill before live inference. v1 starters: summarize, eli5, quote — knowledge skills with the right shape (same input → same response). Creative (/tarot, /haiku, /joke) and wellness (/cbt-reframe) stay live to preserve freshness.

Measured on SR8: eli5 "binary search" took 10.4 s live, then 0.4 s cached — ~25× faster, and most of the 0.4 s is docker-exec overhead. The actual SQLite lookup is single-digit milliseconds.

A small but lovely emergent property: the SE.1.1 skill-smoke daemon already runs the precookable skills every 30 minutes for format grading. The harness warms its own cache. After the first cycle, every subsequent harness run is a cache hit. The systems compose without anyone wiring them together.

Storage — what lives where

WhereWhatWhy local
PFM archive (~/werbos/chats/*.pfm)Every chat turn, append-onlyYour conversations, your file. Survives reboots.
tasks.db (SQLite)Tasks, pending actions, budgetsOperational state for the agent plane.
agents.db (SQLite)Agent definitions, channel routingThe cast of personas you talk to.
memory dir (~/.claude/.../memory/)Cross-conversation memory filesWhat I remember about you between sessions.
user.md (~/werbos/user.md)Your profile, hand-editedSix-section template. Injected into every system prompt.
working memory (append-only JSONL)Per-session conversation turnsRetrieval-as-memory: recall what scrolled out of the window instead of holding a 1M context.
brains (~/werbos/brains/, or $WERBOS_BRAINS)Every talk model we ever trained, plus a current symlinkThe models are OURS, so they are an artifact you keep, not a download you can re-fetch. Kept deliberately even when superseded: each is a point on the benchmark timeline, and deleting one invalidates a published number. Listed on the dashboard’s Models page.
corpus + vocab (train.bin, book_chat_bpe_*.json)Tokenized pretraining stream and the BPE that made itA vocab is load-bearing forever: it is not a preference but part of the model, and re-segmenting with a different one turns the weights into noise. The .bin is a flat uint16 array, so a corpus that grows is a file APPEND rather than a re-tokenize.

Local-first means your data lives on your box. Inference can route to whatever model fits the agent (cloud is fine for the rented brain; the data stays home).

The sibling repos — one job each

werbos is a wrapper. It composes a dozen sibling libraries. Each is small, independently testable, and has one job.

RepoRoleStatus
werbosThe orchestrator. CLI, server, sessions, scheduler, channels.shipping
pittsThe agent loop primitive: think → act → observe. Backend-agnostic.v0.0.2
werbos-librariesThe content moat, decoupled 2026-08-01. 374 graded card libraries (163,563 cards) as their own private repo — the library versions on its own clock and pulls on its own. libpath resolves it as a sibling with no env var, and libpath.found() is the assertion a deploy should fail on: the brain container ran ten days with a mount pointing at the emptied pre-decoupling path, serving zero cards behind a passing health check.building
werbos-personasPersona capsules, split out 2026-08-25. profile.json + prompt.md + exemplars.jsonl + grader.md per character — a capsule is content, versioned and graded like a card library. Her memory of YOU is state and lives under rosterpath.state_root(), never in this repo and never in the work brain’s MemoryStore.default(). rosterpath is libpath’s twin: explicit config wins unconditionally so a failed mount is VISIBLY empty rather than quietly served from somewhere else. Day 108: capsules can now be derived from a corpus — personas/style.py fingerprints how someone writes (format-agnostic across chat and verse; confidence scales with corpus size) and capsule_from_corpus.py writes the four files, so a transcript or a book becomes a chattable persona. The roster grew 4→10: Emily Dickinson (public-domain verse) and Trump (public-style pastiche) shipped in-repo, and Day 111 added a hand-authored werbos house-voice capsule — the 12-year ride-or-die coworker who is the default when no style is named and the honest fallback when a named style has no capsule (invoked discovery-free via compose/style_select.py: “in the style of X”, no menu); a persona built from real personal texts deploys off-repo (untracked, gitignored) so its words never enter git. An optional nsfw.md sidecar mounts on an SFW base per-session — off can only remove permission, never a hard limit.private
pfmPersonal Field Map — append-only at-rest archive for chats.locked
mccullochEvaluation harness. Bench suites for code/debate/games.locked
partyparrot-pyLive wire. Streaming primitives shared across sessions.locked
observeThe see layer. Telemetry events with discriminated kinds.v1.0.0
watchtowerThe summon layer. HTTP / shell / fn dispatch with allow-lists.v1.0.0
wardenThe defend layer. Rate / pattern / predicate / allowlist rules + alerts.v1.0.0
beaconThe signal layer. Probes + transitions (edges, not levels).v1.0.0
watchtower-uiThe SPA front for the orchestration suite.v0.1.0
glasshouseThe inspect layer. Reads the trace log; renders per-trace timelines + per-day stats.v0.1.0
somaThe puzzle bin — a thin index that re-exports the loop’s primitives (from soma import capture, grade, fence). Owns no logic; maps each piece to its own small repo.building
captureThe shared experience store. Append-only JSONL log + query, carved from autopilot’s ExperienceStore so every loop logs one shape.ready
learnThe champion/challenger gate. gate(experiences, champion, train=, score=) — refine a prior from experience, never promote a worse one. Surface-agnostic.ready

The five-piece orchestration suite at the bottom (observe → watchtower → warden → beacon, plus the UI) shipped on 2026-05-08. They embed into werbos or run standalone — that’s the point of keeping them library-shaped.

glasshouse is the diagnostic surface, shipped on 2026-05-26 as the eighth Phase-3 sibling. Pure stdlib reader for ~/werbos/traces/<YYYY-MM-DD>.jsonl; the writer side (werbos.tracing) emits per-turn UUIDv7 trace_ids and instruments slash dispatch, LLM calls, intent_compiler, and tool invocations. Operator asks glasshouse trace <id> and sees the whole chain join up. Trace JSONL files are self-describing (a _schema header row declares the on-disk shape) so a future archaeologist can parse them without the werbos source on hand.

soma + capture are the loop-as-library carve-out, started 2026-06-16. Every loop (autopilot, mythos, dogfood) had re-implemented the same primitives — an experience log, a grader, a fence. soma is a thin index that re-exports them from one import surface while each stays its own small repo (grade=mcculloch, fence=warden, capture=the new append-only store). On Day 48 ExperienceStore became the first consumer: it adopts capture as a soft dependency — the capture engine when the sibling is installed, a byte-identical inline fallback otherwise — so the container deploy is unaffected while the loops converge on one shape. The same day learn was carved (the champion/challenger gate generalised out of the autopilot policy) and run_gate soft-adopted it the same way. Five pieces are ready now (grade/trigger/fence/capture/learn); gate and search are the last planned ones, and asking soma for one names the repo to carve next.

Three places it runs

Deploy modeAudienceShape
CLI (pip install werbos)The author + early userswerbos chat, werbos code, werbos serve. One process.
Docker stack (orchestration-deploy/)Self-hosted on your own box5 containers: werbos + watchtower + warden + beacon + nginx.
SR8 (always-on)The author’s workstationTailscale Funnel → nginx → werbos serve on host net.

All three speak the same HTTP API. The dashboard SPA, Slack adapter, and MCP server attach to whichever one is running.

Agent plane — what V1 actually shipped

The dashboard isn’t a chat window with a sidebar — it’s an agent control surface. Five things were stood up between 2026-05-09 and 2026-05-13:

  • Agents (V1.4) — cast of personas, per-agent persona/voice, tag derivation, mirror slider per turn.
  • Permissions (V1.5) — tool registry perm-check, verb classification, pending-action ask flow.
  • Models (V1.6) — Test/Pull(SSE)/Remove for /api/models/{id}, backend inferred from id.
  • Scheduler (V1.7) — in-process asyncio daemon, hand-rolled cron, FakeClock for tests, SessionRegistry.create(agent_id=...) wrap so scheduled runs use the right persona.
  • Channels (V1.8) — channel_routing table, in-band /bind slash command, AgentDetail “Connected channels” list.
  • Activity (V1.9) — /api/activity aggregator across chats + tasks + runs, Home feed component.

V1 is shippable. Code-via-channels (CC.1) and multi-adapter Slack (SC.1) are queued for Phase 16.

Autopilot (2026-06-09) is the agent plane’s self-directed turn. The dashboard configures background agents; the autopilot is werbos acting on its own. It watches <inbox>/requests/ and runs a predict → act → observe → error → correct loop over its skill library, then a slow loop trains a routing policy from the accumulated experience and promotes it only if it beats the champion on held-out data (the same gate the model trainer uses). Fail-closed (safe-skill allowlist + append-only revert), opt-in, and it reflects on itself — what it knows, what it’s missing, what it would improve. The deep idea: the prediction error is both the real-time correction and the learning signal. Diagram on the flow page.

The library is the product (2026-06-09). The catalog the autopilot draws from — and the same skills you reach via /slash or werbos <name> — grew from 137 to ~294 prompt skills in a single day: a hand-built developer block (error-decode, git-undo, regex-build, …) plus 157 more authored by a multi-agent workflow across 18 categories, each adversarially verified. This is the curated-breadth thesis in motion: werbos doesn’t get smarter by swapping the model; it gets a new capability by adding to the library. Frontier models improve every six months; werbos got a hundred and sixty-nine capabilities in an afternoon.

The capability was in the decoder, not the weights (Day 77, compose/focus.py, weld/torch_talk.py). Two results that sharpen the thesis from opposite directions. First, a contrastive-focus resolver: “I never said he ate my sandwich” is seven claims depending on which word is stressed, and the mapping is mechanical — a lexicon and word position, no model at all. It scores 20/20 where llama3.2:3b scores 4/20 (chance), at 2.5µs against 469ms. The 3B ignores the accent entirely, because a fluent model has no reason to represent that relation. Second, the owned talk model’s monotony turned out not to be a data problem: the corpus sits at 96.6% of maximum opener entropy with its top opener at 0.26%, while the model emitted its own top opener 10.4% of the time — a 40× amplification caused by greedy decoding taking the mode every step. Seeded sampling moved input-sensitivity 0.65 → 0.94, past the 3B, with no retraining. And the 85M was tested directly and is worse on every axis than the 30M. Both point the same way: capability lives in the structure around the weights, and “make the model bigger” has now lost three times here.

The ask gets parsed before anything looks it up (Day 80, compose/askparse.py). Every tier was reading the raw sentence with its own regex, which is four opinions about one question. Now one parse produces four slots — intent, action, topic, target — and the tiers read the slots. “How would i set display none for li” is a SOLUTION about the topic display none applied to li; “what is display none” shares every content word and is a different request entirely. The opener decides the tier, and it is the cheapest signal in the sentence. It also fixes retrieval: the topic is the query, not the sentence, because six words of scaffolding is how a question about display finds a card about how.

And retrieval learned to weigh rather than grab. The ring ceiling existed because a loose ring with first-hit-wins returned something arbitrary. Every candidate is now scored — topic overlap, how much of the card is about the ask, and the card’s own topic field, which every card carries and the index had been discarding. The abstain survives, but on a better rule: a close second is only ambiguous if it disagrees. Sixty cards filed under const scoring within 0.06 of each other is abundance, not uncertainty.

The third answer (Day 80, compose/jsshape.py). A JS construct is an object with slots, so it renders at any level of fill and every stage runs. Between “here is the code” and an abstain there is now “this much I verified, and here is where I stop” — which is what a structure that is right in every part but one should have been saying all along, instead of being shown to the user as if it were fully right.

The composer spine — understand → plan → gather → speak (Day 82–84)

The runtime spine reorders everything: the model speaks last, not first. A message is UNDERSTOOD (interpret.py reads intent + emotion), PLANNED into the NEEDS it declares (plan.py — empathy / code / facts / transform / …), GATHERED (retrieve exactly those), and only then SPOKEN. The weights’ whole job shrinks to the last step; the knowing lives in the owned, deterministic composer. Each lane is a fully-wired seam, and each carries its own verifier:

  • Style transfer (speak_packs.py) — verifiable, blendable register shifts (pirate → gen-z); the whole 31,095-verse Bible into pirate in 4s, meaning-graded.
  • The emotion lane (empathy.py) — nine states (grief, health, rejection, setback, fear, guilt, confused, gratitude, pride, relief, hype, anger + crisis→988), each a composed stance a verifier enforces: no cheering at grief, no defending against anger, no wet-blanketing hype. Reads valence from words and events (“I broke my arm”), and tells “FUCK YES” (hype) from “FUCK YOU” (anger) by what follows. The composer-layer answer to B.18 — a 5M can’t hold valence in its weights, so it lives here.
  • The reasoning stack (multistep.py → tools.py → planner.py) — a question decomposes into a recursive step-TREE; leaves EXECUTE (calc/code/sandbox), RETRIEVE (library), or ABSTAIN; state carries across steps and status propagates up, so a step werbos can’t run stays ✗ (honest partial — the “then hack the mainframe” branch never gets a checkmark). Reasoning by execution, not chain-of-thought narration — every step actually ran, or it’s honestly unchecked.

The through-line, and the whole bet stated one more way: the composer is where the mind lives — the weights only render what an owned, verifiable stage already decided.

Two more composition engines (Day 137): knowledge in, language out

The brick idea — typed pieces that interlock into a verified whole — isn’t just for computation. It runs both other sides of the system, mirror images of each other:

  • Knowledge acquisition (werbos/knowledge/). Not APIs-for-questions but adapters for domains: a capability index of ~100 free sources across two-dozen domains, each tagged by what it covers and how to reach it (hosted-offline / consumed-live / searched / owned-card). A universal, guarded HTTP caller sits under all of them; small static datasets (periodic table, countries) answer offline. The payoff is the acquisition loop: one question resolves an entity and harvests its whole neighbourhood into cards — “capital of Australia?” mints capital + currency + region + language — so the library grows itself from use and adjacent questions then answer offline. This is resolve()’s SEEK → CACHE at the domain scale; the API is the SEEK, minting the CACHE. The Wikidata consume-harvester unbounds this to any entity (single-entity/targeted — the precise regime — with an ambiguity abstain), emitting is-a relations as the layer a reasoner walks. And describe is the interlock: harvested facts → rhetorical bricks → 1B voice, grounding-guarded, so the two engines meet on one seam.
  • Language composition (compose/convo_bricks.py, rhetoric.py, tongue.py). A reply is a small vocabulary of rhetorical moves (observe · name · reframe · contrast · generalize · exemplify · recommend · riff · advice · close, plus the contract-carrying reflect/validate/normalize/plan/verify/ boundary) chained into a program, the moves interlocking exactly like the compute bricks. The program is testable without the model; the 1B is wired as voice only (surface realization, grounding-guarded — it strings the grounded beats, never invents), while the lanes fill the content. Programs are now tunable per prompt type: therapy ends on a boundary, coding on a verify, life_riff never abstains, small_talk stays minimal — the shape itself carries the contract. program_for(intent) picks the shape; respond(context, intent, think=, voice=) is the one call a lane makes.
  • Talk bricks (compose/talk_bricks.py + talk_lexicon.py + talk_families/, Day 147 — on a branch, not yet in the live path). The other half of language composition: bricks that fill themselves from the user’s own words and cards, with no model at serve time — same line in, same reply out. A line is read into slots (act, hype, subject, kind, what you already said), each clause runs a pattern of bricks (Seq, and Each for recursion — a decision’s breakdown is one brick per factor), and a thread carries the subject across turns. 35 situation-space families (invites as states, travel, work/school, relationships, holidays, media…), ~5,250 bricks. The floor is shared: crisis, harm and serious-health lines never get a brick. A clause no brick can answer becomes a lane — a hole the right engine fills (code that ran, a cited card, a counted web answer, or a labelled guess), so one reply mixes bricks with lookups and the thread survives the detour.
  • Madlib bricks + conversation shapes (compose/madlib_bricks.py, plan_bricks.py, decision_bricks.py, convo_shapes.py, Day 147; merged to main Day 159, not yet deployed). The talk bricks above are pre-written strings and lost to production in front of the judge; these replace strings with shapes. A singular brick (observation, plan) reads a line into slots, evaluates the subject (WordNet → cards → web → an honest unknown), picks an affordance and fills ONE madlib frame — under ten frames, no word lists. That’s depth. Breadth is composites built from section bricks, four levels: arcs across turns (TEACH, SUPPORT, DECIDE) → long replies (IRSAF, COMPARE, EXPLAIN, IHDS, COMFORT) → short reactions (CELEBRATE, ICD, REPAIR, RECOMMEND) → the sections themselves, each with a contract (claims backed or dropped to a gap list; one follow-up; hype matched, never escalated; a pushback held only on two independent sources). One Conversation routes: reactions → shapes → singular bricks underneath. Each level has its own fuzzer; the section contracts are a deterministic ratchet (section_audit.py). By Day 159 the stack also holds event / state / feeling / outcome bricks with tone tiers (a loss, bad news and good news each get their own register — never “oh nice” on a grief line), master templates (TRIP, WRITE, EDIT, TROUBLESHOOT, PLAN, CODE_DEBUG, TAROT), the owned compute lanes wired into chat (units, arithmetic, dates, an everyday lane, saved recipes) and a safety floor (poison, carbon monoxide, never a dose guess) that runs before any tongue. The tongue (convo_tongue.py) only writes what the bricks plan; when a factual line has no facts, card_rewrite.py lets it act as librarian — rewrite the question as keywords, judge whether a hub card fits — and the reply quotes the card. Snippet and troubleshooting content is library data (snippet_library/*.json, procedure_library/), never code. Measured by the structure ratchet (see /flow HL.4).
COMPUTE     nums → filter → map → reduce → answer
KNOWLEDGE   api → facts → cards → relationships → reasoning
LANGUAGE    thought → semantic bricks → rhetorical bricks → voice → sentence

Three orthogonal dials on the language side — intent picks the shape, the lane fills the bricks, the tongue voices them. Same machinery on all three sides — compute, knowledge, language. The intelligence is the composition; the model is the tongue.

See also

  • The mind — werbos’s mind drawn as a radial: the capability axes, what each measures, and the ghost spokes it can’t measure yet.
  • The full original SPA — llm-map/index.html in the monorepo has the deeper sections (acronyms, gotchas, hardware fleet, repo map). Will be ported into per-page Hugo content as the site grows.
  • The advancements graph — visual dependency map of every milestone shipped.
  • The log for what’s actually happening day-to-day.