“the rebuild is when transitive resolution stops lying.”

Set out to make 50 lifestyle skills. Ended with 80 across eight themed batches, two new categories, +4,531 lines of PROMPT_SKILLS entries. The deploy taught the lesson the source code wouldn’t.

The lifestyle skill bundle

PROMPT_SKILLS 45 → 125. Eight batches of 10, all auto-flowing into custom_skills reserved-name protection, the dispatch_skill tool router, and the Skills-tab catalog. Two new categories registered: finance, marketing. (1c8ec0a)

  • Food & Drink: /grocery · /cocktail · /leftovers · /dietary-swap · /wine-pair · /snack · /potluck · /lunchbox · /coffee-pick · /spice-sub
  • Health & Body: /hydrate · /sleep-tip · /workout · /stretch · /posture · /symptom · /eye-rest · /cold-shower · /step-goal · /body-scan
  • Money & Logistics: /tip-calc · /price-check · /subscription-audit · /coupon-ideas · /negotiate · /countdown · /timezone · /age-calc · /weekday · /recycle-check
  • Home, Errands & Travel: /errands · /fix-it · /plant-care · /laundry · /pest-id · /packing · /layover · /jetlag · /phrase · /small-talk
  • Mystical & Reflection: /runes · /iching · /astrology · /numerology · /oracle · /palm · /dream · /moon-phase · /intention · /mantra
  • Therapy & Inner Work: /cbt-reframe · /trigger-trace · /self-compassion · /anxiety-spiral · /anger-cool · /boundary-script · /people-please-check · /burnout-check · /therapist-prep · /inner-child
  • Personal Finance: /budget-build · /emergency-fund · /debt-payoff · /paycheck-allocate · /401k-check · /roth-vs-traditional · /invest-101 · /rent-vs-buy · /insurance-audit · /lifestyle-creep
  • Marketing & Copy: /headline · /tagline · /value-prop · /positioning · /landing-copy · /cold-email · /email-subject · /social-post · /seo-meta · /brand-voice

Safety patterns baked in

  • Every therapy skill carries a crisis-override block (988, 1-800-799-7233, ER) for suicidal ideation, abuse, trauma flashbacks, severe persistent symptoms. Modeled on symptom’s escalation pattern.
  • Every finance skill refuses to fabricate current tax brackets, contribution limits, or interest rates — those drift yearly. References “the current 402(g) limit” instead of a number, and routes individualized advice to a fee-only CFP or CPA.
  • Math-heavy skills (tip-calc, countdown, timezone, age-calc, weekday) show the work so the LLM’s arithmetic is auditable. For high-stakes uses, a short cross-check nudge.
  • Marketing skills mark placeholders explicitly (<TESTIMONIAL FROM REAL CUSTOMER>) rather than fabricating quotes / logos / stats. No dark-pattern recipes.

The deploy taught the lesson

The skills committed and pushed clean. The SR8 deploy did not.

  1. redeploy.sh failed on the nginx chat-builder Docker stage. npm run build couldn’t find tsc. Unrelated to the prompts.py change; pre-existing breakage in the chat-UI build chain. The full compose-up was gated on chat-builder, so the whole stack stayed on the old build.
  2. Backend-only fallback — docker compose up -d --build werbos to skip the broken chat-builder. The new werbos container built successfully, then crash-looped on startup: ModuleNotFoundError: No module named 'httpx'. Production was down.
  3. Root cause — werbos/tools/{ollama_chat, fetch_crypto, fetch_weather, fetch_stocks, fetch_definition, fetch_news} all import httpx, but pyproject.toml never declared it. The local dev env had httpx transitively via a sibling; the slim runtime image had it via the same sibling — until that sibling dropped it in a recent commit. The Dockerfile’s hand-listed runtime deps (websockets, starlette, uvicorn) didn’t fill the gap because the next step does pip install --no-deps on the wheel.
  4. Recovery — declared httpx>=0.27,<1 in pyproject.toml (c5922d6) AND in orchestration-deploy/Dockerfile.werbos (7efd6b5, orchestration-deploy repo). SSH pull both repos, rebuild. Container up healthy in 10 seconds.

The moral: transitive resolution is the kind of thing that lies to you in dev and tells the truth on rebuild.

What was already there that this proved

  • dispatch_skill auto-derives from PROMPT_SKILLS. All 80 new skills are visible to the chat LLM as natural-language dispatches with no extra wiring. “give me a tarot reading on my new job” → dispatch_skill(name='tarot', args='new job'). ~3–4K of system-prompt overhead at 125+ skills, acceptable on the local 8B.
  • Traces are flowing. A test /joke call produced two correlated trace events in /data/traces/2026-05-28.jsonl with the same trace_id joining the slash dispatch to the llm completion. UUIDv7, daily file, 0600 perms — as designed by the Day 23 tracing commit.
  • custom_skills reserved-names protection auto-picks up the new surface. No risk of a future user-uploaded custom skill shadowing /dietary-swap because _compute_reserved_names() reads PROMPT_SKILLS directly.

Numbers worth keeping

  • PROMPT_SKILLS: 45 → 125 (+80, +178%)
  • Categories: 10 → 12 (added finance, marketing)
  • Lines added to werbos/prompts.py: +4,531
  • Test suite after the change: 4,553 pass, 2 pre-existing failures unrelated to this work (dispatch_skill registry inheritance)
  • Deploy attempts: 3 (one full-stack fail, one backend-only crash, one recovered)
  • Minutes of prod downtime: ~10
  • Lines in the Dockerfile fix: +2

Aphorisms

“transitive resolution lies to you in dev and tells the truth on rebuild.”

“the catalog auto-grows; the per-skill cost approaches zero, but the system-prompt token cost does not.”

“OH these are for Werbos… not Claude…” — the mid-sketch realization that this was a Werbos product expansion, not a Claude Code skill set. ~30 minutes of detour avoided.

Carryover into Day 25

  • Fix the nginx chat-builder Docker stage. tsc not found blocks any full redeploy.sh run. Either a missing npm ci / devDependencies install step, or a stale Docker layer. Cheap to investigate.
  • Watch dispatch_skill token cost on the 8B local model. If chat responses lag noticeably, the catalog summary in the tool description is the lever to tighten.
  • Safety patterns deserve regression tests. symptom’s escalation block and the therapy crisis-overrides should be in the next security/safety sweep so a future skill edit can’t silently drop them.