Skip to content

refactor!: converge every package on the tutorial contract; numbered tutorial replaces the doc set - #1

Open
marcosluizfp wants to merge 36 commits into
mainfrom
simplification
Open

refactor!: converge every package on the tutorial contract; numbered tutorial replaces the doc set#1
marcosluizfp wants to merge 36 commits into
mainfrom
simplification

Conversation

@marcosluizfp

Copy link
Copy Markdown
Contributor

Summary

Breaking major that executes the approved simplification design (docs/superpowers/specs/2026-07-28-looprun-simplification-design.md): the public API of every package converges onto what the numbered tutorial teaches, everything else moves to @looprun-ai/core/internal, becomes module-local, or is deleted with evidence.

axis before after
core barrel 107 named + 2 wildcard exports 51 taught + 11 type riders (surface-locked)
backend seam mixed into the public barrel @looprun-ai/core/internal (46+2, locked)
mastra / models / eval / server 25 / 24 / 52 / 13 exports 7 / 8+2 / 19+9 / 4+3 (each surface-locked)
guards.ts 1,427-line monolith guards/ by category + GUARD_CATALOG data (30 entries, hook axis)
coherence queries 428 lines, zero external users erased; the trunk fold is module-local, byte-invariant (proof record)
docs 11 overlapping files docs/tutorial/01–06 — every TS block compiled in CI, chapter 04 generated from GUARD_CATALOG with a drift gate, terminal transcripts labelled real/illustrative

Evidence chain: symbol inventory (265 symbols, per-symbol verdicts) → tutorial outline as API contract → per-concept refactor with dual independent review per task → final whole-branch dual review. Ledgered in docs/superpowers/specs/.

Migration notes for external consumers (looprun-bench, agentspec skill, yntelli): docs/superpowers/specs/2026-07-28-migration-notes.md — includes two OPEN decisions that need a maintainer call (add looprun/eval/looprun/server facades? fate of the @looprun-ai/vercel stub?).

Type of change

  • Guard — catalog data (summaries de-taxonomized, backticked cross-refs; factory bodies byte-exact)
  • Runtime — barrels/visibility only; turn machine behavior preserved (2-line diff on turn.ts, both bare export removals)
  • Skill
  • Docs / tooling only — the tutorial, README, snippet harness, clean-build scripts

Governance checklist

  • Proof cases: N/A for new guards (none added); deleted coherence cases enumerated per-symbol in the records
  • pnpm test:proofs green (495/495, coverage 29/29 kinds)
  • Ratchet not lowered (29/29 before and after)
  • Proof records committed (7 on this branch, verdict: PASS)
  • governance/MATRIX.md regenerated and in sync (11 records)
  • GUARD_CATALOG current + pnpm docs:guards idempotent (drift gate in CI)
  • Drift lint clean (node tests/no-bench-drift.test.mjs)

Paste the generated matrix row

See governance/MATRIX.md — 7 new rows on this branch (2026-07-29-*), all PASS; representative:

| 2026-07-29 | trunk-fold-coherence-cut | core | refactor | PASS | 495/495 · 29/29 |

🤖 Generated with Claude Code

https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9

marcosluizfp and others added 30 commits July 29, 2026 17:22
Enumerates all 265 symbols exported from the index.ts of core, mastra,
models, eval, server and vercel, and classifies each as public /
internal / delete based on an import-aware scan of every consumer
(examples, skills, scripts, governance, looprun-bench, agentspec,
yntelli) plus the two shipped CLI bins and the agentspec guard catalog.

Result: 77 public, 35 internal, 153 with no consumer outside the
defining package. Re-verifies the 16 pre-seeded zero-usage claims (all
confirmed) and records six spot-checks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cope

Review round 1 fixes:

- core.validateSpec internal -> public. mastra's barrel ends with
  'export * from @looprun-ai/core', so yntelli reaches a CORE symbol
  through a MASTRA specifier and the import scan dropped it. Added a
  pass-C closure check resolving every consumer binding against the
  owner of the name: validateSpec is the only such case in the corpus.
- eval.agentForCase and eval.stripGovernance delete -> public, reached
  by agentspec's synth-fork.mjs through a computed importFromCwd().
- core.renderTurnPrompt internal -> public, same mechanism in
  synth-fork.mjs and extract-fork.mjs. Found in re-verification.
- models.localModel and its three companion types public -> internal:
  the earlier promotion rested on README evidence, and verdicts are
  usage-based. The docs/exports conflict is recorded for Task 12.

Corrections without verdict impact: fixed the false claim that foldRow,
isSingleClause and DEFAULT_POLARITY_LEXICON are unreferenced (all three
are used inside coherence.ts; only findUnassessableLines is genuinely
dead); defined what the same-package column measures and warned that a
dash never authorizes erasing an implementation; widened the doc sweep
to READMEs, GUARDS.md, governance/ and CHANGELOGs, attaching Task 12
notes instead of promoting on doc mentions; disclosed the 20 non-barrel
src exports and the 28 ./testing symbols as out of scope; flagged the
stale vendored guard-catalog snapshots and the three consumer files
that import symbols which do not exist.

Totals: 77 public / 37 internal / 151 delete (was 77 / 35 / 153).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
packages/looprun/bin/looprun.mjs is a published bin (package.json
"bin" + "files": ["dist","bin"]) and reaches resolveAlias
(lines 42, 66, 88, 102) and LlamaCppRuntime (lines 68, 94, 103) by
dynamic import — the same mechanism that promoted 11 eval symbols via
looprun-eval.mjs and localModelStatus via run-canary.mjs. Round 1
promoted the eval side and left the models side internal, which was
inconsistent.

Both flip internal -> public. §3 now states the rule explicitly rather
than leaving it implicit in the per-file table, so it cannot be applied
unevenly again: a symbol a published bin calls is user-facing
regardless of which package owns the bin.

models: 2/6/16 -> 4/4/16. Totals: 77/37/151 -> 79/35/151. Updated the
§1 chart and bar chart, the §7.3 heading, findings 1 and 4 in §6, and
the §9 revision log.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Places every inventory-public symbol in exactly one of the six tutorial
chapters. The union of the per-chapter lists is the target public API that
tasks 3-7 converge index.ts onto.

Resolves the localModel conflict the inventory flagged (finding 4): chapter
06 teaches localModel, so it and its three companion types flip back to
public — on tutorial-contract grounds, not on a doc mention. Inventory
totals 79/35/151 -> 83/31/151, recorded as revision round 3.

No symbol was orphaned, so no "no tutorial home" downgrades.
Round 3 passed a mechanical 83-vs-83 completeness diff while three chapters
were unwritable from the surface they claimed. Fixes, each verified against
the named source line:

- drop "bring your own loop" (06.4): closing that loop needs recordToolResult,
  resultOk and isTerminal, all internal, so a taught version would leave the
  ledger empty and every history-keyed guard silently never firing. Its ten
  symbols demote to @looprun-ai/core/internal, reason "no tutorial home"
- promote the types the reader must author but could not name: Dim, Hook,
  ToolTarget, AgentScope, TerminalPolicy (core spec/guards), TurnInput,
  RunResult, TurnRecord, RuntimeDeps (runSpecConversation), StateView, and
  the eval subject-directory types (Subject, SubjectCase, CaseTurn,
  CaseInvariants, ReqCall, RubricItem)
- state that the scheduler artifacts are authored in docs/tutorial/snippets/
  by tasks 8-9; examples/calendar is a seed with no code
- correct worldFromTools (native-tools mode, exec throws); 03 teaches
  hand-writing AgentWorld as the certified path
- rescope 06 to server + local models; decoding trio moves to 05
- add per-chapter import specifiers; vercel excluded as a non-functional stub
- GUARD_CATALOG ships on /internal, not the public barrel (plan amendment)

Two rules now decide types (annotation rule, taught-field rule) so the
promotion set is bounded and reproducible.

Inventory totals 83/31/151 -> 89/38/138, recorded as revision round 4.
Three places still read as certifying symbols that round 4 demoted:
§3's published-bin box and the §5 spot-check rows for redriveMessage and
renderTurnPrompt. Each now carries a "→ internal in round 4, seam preserved
on /internal" note. The evidence itself was correct and is unchanged; only
its standing is annotated. No verdict and no count changed.

Also: Layer's union is 'minimal' | 'base' | 'full' | 'agent' (was
enumerated with three members in two places); the outline's exclusion row
now separates addGuard opts from AgentSpecConfig fields and lists
MutatorBinding; and decision 4 records that GUARD_CATALOG has no inventory
row, so it is the only place Task 4's reviewer can check exports against.
…ooprun-ai/core/internal

`packages/core/src/index.ts` now exports exactly the 51 core symbols the tutorial
contract claims (docs/tutorial/00-outline.md §4, chapters 03/04/05) — 97 runtime
values + their types down to 51 total.

Everything with an `internal` verdict in the symbol inventory (§7.1, 37 symbols)
moves to the new `@looprun-ai/core/internal` subpath: the guard-catalog tables,
spec binding resolution, the trunk renderer, model settings, and the whole
governed-turn seam (ledger + terminal protocol + prompt renderer + turn machine).
That subpath carries no compatibility promise.

`delete`-verdict symbols only leave the barrel — no implementation is erased; the
inventory's §2 rule holds (every one of them still has an internal or test caller).

In-repo consumers (mastra, eval) and the core/mastra tests now import internals
from the subpath or from the owning module file; no test was weakened or dropped.

Verified: `pnpm -r build` (7/7) · `pnpm test` (773 tests, 0 failures) ·
`pnpm typecheck` (8/8, incl. examples/hermes-sim).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…xecutionError, surface lock

Four review findings on the Task 3 cut.

1. TYPE-CLOSURE RIDER. Cutting the barrel to the taught 51 made public signatures
   uncompilable downstream: a consumer building with `declaration: true` hits
   TS4023/TS2742 the moment it writes `export const w = validateSpec(spec)` or
   subclasses AgentSpecBase, because SpecWarning / AgentControls / ChainSpec /
   StateDirective / GuardBinding / MutatorBinding / Layer / SpatialEdge /
   ReplyMutator / SamplingSettings / TokenUsage are named by no entry point.
   Both barrels now export the transitive type closure of their own signatures as
   type-only riders (11 on `.`, 8 on `/internal`), derived with the TS compiler
   API rather than hand-picked. Riders are not taught and are not counted in the
   89 — recorded as outline §7 and inventory §9 round 5.

   New proof `test/proofs/declaration-emit.test.ts` compiles two real consumer
   modules from a temp dir whose node_modules/@looprun-ai/core symlinks to this
   package, so resolution goes through the real `exports` map — which also makes
   it the first test covering the `./internal` condition. It carries a self-test
   that TS4023/TS2742 are in fact reported.

2. The src/index.ts header claimed everything cut was "still available from
   /internal". False: ~58 former exports (renderTrunkBlocks, chainOrder,
   resolveBindings, TERMINAL_TOOLS, the coherence set, …) are on neither barrel.
   Reworded to name all three destinations, module-local included, and to say
   Tasks 5/6 own their fate.

3. GuardExecutionError is thrown across the package boundary at guard authors but
   was reachable from no entry point, so `e instanceof GuardExecutionError` was
   unwritable downstream. Exported from /internal; whether chapter 04 teaches it
   (promoting it public) is deferred to Task 10 as outline §6 decision 8.

4. SURFACE LOCK. Tasks 4-7 all edit this barrel and nothing failed if it drifted.
   `test/proofs/surface-lock.test.ts` asserts the exact export-name sets of both
   entry points against three hardcoded arrays (51 taught by chapter, 11 riders,
   46 internal), via the TS compiler API over src so types count and no build is
   needed. A deliberate surface change must edit the arrays.

Verified: pnpm -r build 7/7 · pnpm typecheck 8/8 · pnpm test 781 passed, 0 failed
(was 773; +8 from the two new proofs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…OG data

The 1427-line guards.ts becomes packages/core/src/guards/, one file per
tutorial category — flow, args, world, confirmation, honesty, reply, custom —
plus shared.ts (module-local helpers), catalog.ts (the vocabulary as data) and
index.ts (the single import site). Every factory body moves verbatim: the only
edits inside the moved code are the `export` prefix on the shared helpers.

catalog.ts adds GUARD_CATALOG: one GuardCatalogEntry per exported factory
(summary / whenToUse / example), the data Task 10's chapter-04 generator reads.
It ships from @looprun-ai/core/internal, not the public barrel (outline §6,
decision 4) — documentation infrastructure, not authoring vocabulary. The three
kind-classification registries (DENY_ONLY_PROSE_KINDS, CONFIRM_CLASS_KINDS,
ARMED_SEAMS) move there with it and keep their /internal export.

guard-catalog-parity now scans the directory and gains a second lane: every
exported factory has exactly one catalog entry and vice versa, every example
calls its own factory, every entry sits in the file that exports it. The
surface lock's INTERNAL array grows by the two new seam symbols; TAUGHT and
RIDERS are untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…arden the gates

Review follow-up on 08fecd0.

- GuardCatalogEntry gains `hook` ('preTool' | 'postTool' | 'onReply' |
  'onReplyMutate'), set per entry from the factory's real installation phase via
  spec.ts#DIM_HOOKS. `category` stays file-derived; the two axes disagree exactly
  where it matters (noInstructionFromData lives in reply.ts but gates a call).
  Task 10's chapter groups by phase, as the agentspec reference does.
- guard-catalog-parity gains two lanes: the hook must be one of the four, and the
  tricky rows are spot-asserted (noInstructionFromData=preTool,
  jargonScrub=onReplyMutate, resultInvariant=postTool,
  pendingConfirmMustAsk=onReply).
- Gate hardening: both source-scanning tests drop the `f !== 'shared.ts'`
  filename skip. They already discriminate by return type, and the skip would let
  a Guard-returning factory dropped into shared.ts escape the ratchet.
- whenToUse rewritten for confirmFirst, noFalseFailureClaim and degenerationGuard
  — the discriminating situation first, configuration second. confirmFirst's
  example is now the shipping string overload confirmFirst('confirmed'), and its
  summary records the construction-time throw on confirmFirst('prior-ask').
- Outline amended: chapter 04 is 30 catalog rows + canonArgs taught in prose (it
  returns a string, not a Guard — §3 and §6 decision 2); §6 decision 4 records
  the hook field. The §4 row and every symbol count are unchanged.
- Stale path comments: test/proofs/catalog.ts, ratchet.test.ts; ledger.ts now
  imports canonArgs via ./guards/index.js like spec.ts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ule-local

`coherence.ts` (428 lines, 33 exports) shipped two things: the trunk's attributed
table + fold, which `renderScopedSpecTrunk` needs, and the coherence QUERIES
(contradiction / duplication / single-owner / lint censuses), which nothing needs.
Task 3 removed every one of them from the barrel; this removes the implementations
whose only remaining callers were each other and the proof cases written for them.

- new `src/trunk-fold.ts` (184 lines, module-local — reachable from no entry point):
  the table types, `GUARD_KIND_SUBJECT`, `derivePolarity`, `deriveSubject`,
  `foldTrunk`. `foldRow` is now private to it.
- erased: findContradictions, findDuplications, findMultiOwnerSubjects,
  findSubjectlessLines, findUnassessableLines, isSingleClause, mutatorLines,
  trunkLines, withPolarityLexicon, DEFAULT_POLARITY_LEXICON, groupBySubject and the
  NormativeLine / MutatorBindingLike / PolarityLexicon / *Finding types. The
  polarity lexicon was injectable for the census alone, so `derivePolarity(text)`
  loses its second parameter; the `jargonScrub` subject entry went with
  `mutatorLines` (a mutator has no prose and never reaches `deriveSubject`).
- `trunk-provenance.test.ts`: the cases whose subjects were erased are deleted with
  them (15 census cases); everything about the render → table → fold mechanism is
  kept, including the byte-identity invariant. `trunkLines` survives as a
  three-line test-local helper.

Public and `/internal` export sets are unchanged (surface-lock green). Guard
behavior is untouched: proofs 495/495, coverage still 29/29 kinds. Proof record:
governance/proofs/2026-07-29-trunk-fold-coherence-cut.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
… edit, close the record gap

Review follow-up on 55b8ac5. Its message says "15 census cases" and the first cut
of the record said 14; both double-counted. MEASURED (vitest, and grep -c on the
file at 4b59968): trunk-provenance.test.ts goes 36 cases -> 24, i.e.

  12 deleted outright   query (a) 4 · query (b) 2 · query (c) 2 · B4 2 of 3 · I7 2 of 3
   2 rewritten          the mutator adds no bytes · the polarity markers are English-only
   1 assertion dropped  findSubjectlessLines, inside a surviving case

The by-describe axis (4/2/2/2/2) and the by-symbol axis (findMultiOwnerSubjects 3,
mutatorLines 2, …) count the same 12 cases; they differ only because the
mutator-as-owner case calls both symbols. Report and record now print both.
(55b8ac5's own message could not be amended — history rewriting is blocked in this
environment — so this commit is the correction of record.)

Also in the Task-5 record:
- Disclose that GUARD_KIND_SUBJECT lost its `jargonScrub: 'term-substitution'`
  entry, with the inertness argument: the table is read only by deriveSubject <-
  trunk.ts#line() <- rendering a guard's prose(); a ReplyMutator has no prose(), so
  no TrunkLine can carry that kind.
- Fix the malformed table (header/separator inverted).
- Fix the arbiter claim: foldTrunk(renderTrunkBlocks(…)) === renderScopedSpecTrunk(…)
  is INTRA-COMMIT self-consistency; the repo pins no cross-commit trunk snapshot.
  Cross-commit identity is cited as REVIEW evidence — sha256 f695126…, 6999 bytes,
  identical at 4b59968 and 55b8ac5 over a three-trunk fixture incl. installed
  jargonScrub — not as an in-repo pin.

Governance gap: `check-record-required --base main` was passing VACUOUSLY, the
Task-5 record silently covering the 24 governed paths of Tasks 3 and 4 while its
body says no guard was touched (true of Task 5, false for the branch). Two
retroactive records fill it, both generated by `pnpm proofs:record` with fresh
tallies and both disclosing that they attest branch state, not an at-the-time run:

- 2026-07-29-core-internal-subpath.md — Task 3 (5b5e30f, e6860ec)
- 2026-07-29-guards-split-catalog.md — Task 4 (08fecd0, 4b59968)

MATRIX regenerated (6 records). core/src/index.ts drops the planning-internal
"Task 5" reference for timeless prose.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
Task 6 is a verification pass: Task 3 already moved the governed-turn
machine to @looprun-ai/core/internal, so the public barrel already carries
only the contract's result/record types and the backends already import the
machinery from /internal. The one residual was half-open visibility.

Seven symbols in runtime/*.ts carried `export` while no barrel, no sibling
package and no test imported them — TERMINAL_TOOLS, TERMINAL_PROTOCOL,
TERMINAL_PROTOCOL_REPLY_ONLY (terminal.ts), uploadDisplayLabels, isReplyOnly
(prompt.ts), applyMutators, checkReply (turn.ts). Each has an in-file caller,
so only the keyword goes; the implementations are byte-identical.

RuntimeTurnInput (types.ts) is erased: a `= TurnInput` alias with zero
references anywhere. RuntimeTurnRecord stays — /internal names it.

recordVeto, VETO_STORM_LIMIT and shouldFireChain KEEP their exports: core's
own tests import them by module path, so they are not dead.

Proof record: governance/proofs/2026-07-29-runtime-dead-export-cut.md
(PASS, 495/495, ratchet 29/29 kinds — unchanged, no guard touched).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
BREAKING CHANGE: `@looprun-ai/mastra` now exports only the 7 taught symbols of the
tutorial contract (docs/tutorial/00-outline.md §4) plus the `@looprun-ai/core`
re-export: LoopRunAgent, LoopRunAgentConfig, LoopRunOptions, worldFromTools,
StateView, runSpecConversation, RuntimeDeps.

Off the barrel (inventory §7.2 internal/delete verdicts, implementations kept and
module-local — mastra has no /internal subpath): SessionStore, LoopRunSession,
WorldFactory, compileSpec, CompiledSpec, buildWorldTools, buildTerminalTools,
makeGuardHooks, makeInputProcessors, repeatedToolCallStop, GuardHooks,
jsonSchemaToZodObject, jsonTypeToZod, surfaceFingerprint, DEFAULT_MAX_STEPS,
DEFAULT_REDRIVES, LoopRunResultMeta. `createLoopRunAgent` is deleted (zero callers).

- split agent.ts 551 → 448: construction (validation, world/surface resolution,
  tool build, drift gate, static instructions, Agent pass-through) moves verbatim
  to src/agent-construction.ts; agent.ts keeps the governed turn only.
- add packages/mastra/test/surface-lock.test.ts — the barrel is data, not an
  emergent property (compiler-API mechanism copied from core's lock).
- @looprun-ai/server declares the governed-turn meta shape it reads, since
  LoopRunResultMeta is internal to mastra and unreachable across the boundary.
- governance record: governance/proofs/2026-07-29-mastra-facade-trim.md (PASS,
  495/495 proofs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
…cord

Review follow-up on 199c012.

- packages/server/test/meta-mirror.test.ts: restores the compile-time tripwire
  the duplicated meta shape removed. Type-only deep import of mastra's
  declaration + MUTUAL assignability, enforced by `tsc --noEmit` (the build
  config excludes test/, so it never ships). Verified: renaming a field in
  mastra fails the server typecheck in 3 places.
- reciprocal MIRROR comments above both declarations, each naming the other file
  and the pin.
- src/index.ts docstring: the lock is packages/mastra/test/surface-lock.test.ts,
  not test/proofs/ (it is deliberately outside the guard-proof lane).
- governance record: both construction reorders now disclosed with the inertness
  argument — makeGuardHooks (pure closure factory) and new SessionStore (typeof
  test + field assignments). Body-only edit; `pnpm proofs:matrix` regenerates
  MATRIX.md byte-identical, so no frontmatter/matrix change was needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
…act + surface locks

The last three package barrels that still exported more than the Task-2 contract now
export exactly the outline §4 rows for their package, plus the type-closure riders
that make those signatures nameable downstream:

  models  24 → 8 taught (+2 riders)   eval 52 → 19 taught (+9)   server 13 → 4 (+3)

Every `delete`-verdict symbol (inventory §7.3/§7.4/§7.5) stops being exported and stays
module-local — none of these packages has an `/internal` subpath — so in-package code and
the packages' own tests import the module files directly. No implementation with a live
caller was erased; the one exception, `models.localModelClient`, had zero references in
this repo and in looprun-bench / agentspec / yntelli, and lived inside the barrel file.

The published bins keep their contract: `looprun-eval` reaches 11 eval symbols and
`bin/looprun.mjs` reaches 3 models symbols through a dynamic PACKAGE import, so those are
public by that fact — each lock asserts them separately (eval's reads the bin's actual
`api.<name>` accesses rather than a maintained list).

`TurnEvent.meta` decision (left open by the Task 7 review): the server's `LoopRunResultMeta`
mirror is exported as a rider rather than inlined structurally, so the mirror keeps exactly
one name and `meta-mirror.test.ts` keeps pinning the type `TurnEvent` really uses. Recorded
in the outline §7 and inventory §9 round 6.

Three new surface locks (copying mastra's compiler-API mechanism) hold all of it; each was
sabotage-verified to fail on drift. Rider sufficiency was checked by compiling a synthetic
consumer with `declaration: true` against the built packages.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
docs/tutorial/snippets is a private workspace package that depends on the
published `looprun` facade (workspace:*), so every tutorial code block is
compiled against exactly what an npm reader installs — never @looprun-ai/*.

Ships the running example's shared modules (outline §2): the scheduler spec
(AgentSpecBase subclass, scope, terminal, contract, a custom no-double-book
gate, destructiveTools ⇒ auto confirmFirst on cancelEvent), its hand-written
AgentWorld, its ToolDef surface, plus the seeded 02-hello-world snippet.

Gates: `pnpm -r --if-present typecheck` picks up the package, and a two-test
vitest smoke run keeps the world honest at runtime, not only at type level.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
… model id

Dual-review fixes for the Task 8 snippet package.

CRITICAL: the chapter-02 cut passed toolDefs:[listEvents] over the three-tool
scheduler spec, so the rendered trunk advertised addEvent/cancelEvent rules and
activeTools named unregistered tools. Adds scheduler/hello-spec.ts — one tool,
plain config, no addGuard — and 02-hello-world.ts uses it.

Also: terminal policy no longer contradicts a behavior bullet (the bullet is now
about disambiguation, which is what askUser is for here); argFormat on
addEvent.start/end plus world-side DATETIME_RE + past-date checks, so the
lexicographic clash compare can no longer be fed 'next Tuesday'; model id is the
repo's pinned google/gemini-3.1-flash-lite with its env-var noted; cancelEvent's
description says the confirm lands in a LATER turn; 02 shows LoopRunOptions;
ingestAttachment returns the url; REFERENCE_NOW + the datetime pattern live once
in scheduler/contract.ts; outline's `agent.run` → `agent.generate`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
A world instance plus loopRun.sessionId is rejected by the mastra SessionStore
("pass a world FACTORY"), so 02-hello-world.ts threw before it ever reached the
model — introduced by the LoopRunOptions example in the previous commit.

Also: spec.ts's header described two guards while the constructor installs three
(and confirm-first is auto-installed, not written there); addEvent's start/end
schema now carries the same DATETIME_PATTERN the argFormat guards enforce, so
the model sees the constraint; the smoke test covers the world's backwards-window
and past-date rejections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
01-concepts (code-free): the ungoverned-loop problem, the action/language
split, the three nouns (spec = map, guards = safety kit, agent = GPS), and a
full annotated turn showing a preTool veto returning as the tool result.

02-hello-world: teaches LoopRunAgent / LoopRunAgentConfig / LoopRunOptions
only, on snippets/02-hello-world.ts verbatim. States the
GOOGLE_GENERATIVE_AI_API_KEY requirement (the provider reads it, not
looprun), why the model id is pinned, and why `world` is a FACTORY (an
instance + a sessionId throws in the session store). Closes with the
borrow list from outline §3, unexpanded.

03-agent-anatomy: all 13 taught symbols against the shared scheduler
modules, plus a new snippets/03-agent-anatomy.ts for validateSpec, the two
world-read casts and the native-tools StateView. Teaches the forced
[k: string]: any index signature and its cost (a typo typechecks — proved
in the CI-typechecked snippet), the nominal vs structural cast trade-off,
and worldFromTools as the native-tools adapter whose exec() throws. States
explicitly that the smoke test covers the world's half of the two-step
cancel, not the confirmFirst guard.

Every fenced TS block is verbatim from docs/tutorial/snippets/ or marked as
a library signature / illustrative.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
…iew 03 -> 06

Accuracy (all verified against source before editing):
- 03: the confirmed-flag cross-check does NOT throw at construction.
  assertDestructiveConfirmable has exactly one caller, run-conversation.ts:101
  (the chapter-05 runner); LoopRunAgent's resolveConstruction never calls it.
  Reworded to say the eval runner throws at run start and LoopRunAgent does
  not check it today. No code changed.
- 03: system-prompt order redrawn from trunk.ts:293-337 — voice, scope, core
  rules, flow, tool rules, governance, persona+behavior, languageClause LAST.
  The old diagram put scope below core rules and languageClause in the head.
- 03: mcp.getTools() -> listTools(), plus the namespacing (serverName_toolName)
  and deny-by-default surface intersection (agent-construction.ts:80-97).
  Applied in the parked chapter-06 text, since the section moved.
- 01 + 03: the veto is the tagged governance envelope (turn.ts:33-73), not a
  bare { success:false, error }. 01 now teaches the world-refusal vs
  guard-correction distinction, which is the point of the discriminator.
- 02: hello world was not runnable as printed — added the copy-the-scheduler
  step, type=module and npx tsx notes, and scoped "twenty lines" to the agent
  file.
- 02: model equivalence downgraded to same family (the harness pins the
  thinking-off variant); "wording constrained by machine checks" replaced —
  the language layer is never gated, it is measured.
- 03: auto-install box scoped (lexicon.falseFailureClaimRe adds a sixth guard;
  confirmMechanism selects arg vs prior-ask), and `mode` documented as a
  required, near-vestigial field.

Contract amendment (controller ruling): worldFromTools + StateView move from
chapter 03 to chapter 06 — 03 13->11, 06 11->13, total still 89, no verdict
changed. Recorded in 00-outline.md §7 and symbol-inventory §9 round 7;
mcp-tools.md now absorbed by 06. Chapter 03 keeps a 3-line forward reference,
and the section text is parked (with the listTools/namespacing/refresh-is-
fire-and-forget fixes applied) for Task 11.

Also: 03 §7's index-signature essay condensed to a callout, class diagram
corrected, addGuard's elided `layer` field marked, scope's all-or-nothing
rendering stated, and the chapter's "every block is quoted" umbrella replaced
with the honest excerpt-vs-signature split.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
cp -r copies five files, not four, and the claim that chapter 03 writes all
of them was wrong twice: hello-spec.ts is chapter 02's own, and spec.ts is
03's full three-tool spec that comes along unused. Replaced the sentence
with a per-file table naming what each one is and whether this chapter uses
it. Also tightened 03 §10's forward reference.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
The catalog half of docs/tutorial/04-guards.md is rendered by
scripts/gen-guards-chapter.mjs from GUARD_CATALOG on the BUILT
@looprun-ai/core/internal, grouped by `hook` (the enforcement phase) with
`custom` in its own escape-hatch group. summary/whenToUse/example are emitted
verbatim — a wording fix belongs in src/guards/catalog.ts.

The hand-written half teaches the four vocabulary types (Guard, GuardCtx,
ObservedCall, Dim), canonArgs as a helper in prose, cross-references addGuard to
chapter 03, and closes with writing a custom guard.

GuardExecutionError stays on /internal (outline §6 decision 8): §6 MENTIONS it
as the diagnostic a throwing check produces, but does not teach its API — the
intended reaction is to fix the guard, not catch the error.

Drift gate: `node scripts/gen-guards-chapter.mjs --check` exits 1 on drift, and
runs both at the end of the root `pnpm test` chain and as its own CI step.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
…, routing table

CRITICAL: maxCalls does NOT use canonArgs (flow.ts counts by tool name, args
ignored). Four sites taught the opposite; §4 now contrasts the two — a rephrased
retry escapes noDuplicateCall and still burns maxCalls budget.

The "the catalog examples typecheck" claim is now a fact: the generator also
emits docs/tutorial/snippets/04-guards-examples.generated.ts (all 30 examples,
committed + drift-checked), which the snippets package typechecks in CI.

Catalog prose (governed path, proof record
2026-07-29-guard-catalog-summaries-detaxonomized, 495/495 unchanged):
risk-family prefixes stripped from six summaries; forbidThisTurn's scope
corrected to the binding's lifetime; custom's hook caveat de-dangled.

Chapter: symptom→guard routing table and the honesty cluster added to §4,
section index in the intro, §3's five+conditional-sixth count fixed, addGuard
convention-vs-rule and addReplyCheck payoff, onInput noted in §5's intro.
Outline: Task 10 amendment recording the three departures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
Chapter 05 (running & eval) teaches its 27 outline symbols: runSpecConversation
with TurnInput/RuntimeDeps/RunResult/TurnRecord, the decoding trio, the subject
directory contract with its five authored case types, and the twelve
looprun-eval entry points taught CLI-first. It absorbs docs/guides/eval-config.md
and docs/guides/measured-loop.md (both die in Task 12).

Chapter 06 (advanced) teaches its 13: the OpenAI-compatible server (4), the
local-model seven, and worldFromTools/StateView moved here by the outline §7
amendment. It absorbs docs/guides/local-models.md, packages/server/README.md
and docs/guides/mcp-tools.md. @looprun-ai/vercel gets one honest line: a
reserved stub whose factory throws.

New snippets: 05-running-and-eval.ts, 06-advanced.ts, and a real eval subject
(scheduler-subject/) over the shared scheduler — norms/gen/evals/ask plus the
judge prompt. Its smoke test runs a scripted governed conversation (the clash
gate really vetoes) and asserts the five preflight lints are clean.

The scheduler modules' relative imports now carry the .ts extension: the subject
is imported by node through loadSubject, where a .js specifier does not resolve
to a .ts file. worldFromTools/StateView moved out of the 03 snippet with their
chapter; the mastra surface lock's comment labels follow.

Terminal transcripts are labelled: help, lint (clean and failing) and the three
seal commands are real runs on this repo; run/fold/cert need a live model and
are marked as illustrative shapes.
CRITICAL: cloudValidationDeps assigned geminiFlashLiteThinkOff()'s modelParams
straight onto the deps, replacing pinnedDecoding() and leaving temperature on
the provider default — inside the section about pinning. It now spreads over
pinnedDecoding(), the way provider.ts does, and §3 says the helper carries the
thinking-off options only.

The seal-void transcript's "on disk" hash was produced by a different tamper
than the one the chapter prints. Re-ran the exact four-command sequence twice:
both hashes now reproduce byte-identical (restore → VALID a2c96e1f…, re-append
→ VOID 6ab73afa…), and the caption discloses the node-bin invocation.

Accuracy: the trunk-static gate is conditional on ≥2 declared presets (plus the
<200-byte shared-head rule for multi-agent subjects); forbiddenToolCalls is
evaluated over calls that REACHED the world, so a vetoed call is not a
violation; rubric `critical` is an unenforced hint for the judge prompt;
cases.jsonl is not gitignored by anything, so that is now a recommendation;
lintSubject exempts the minimal: layer from GUARD-NEVER-TARGETED; the ungoverned
strip also empties controls.exhaustionReply and keeps flow; the systemPrompt
escape hatch and the seal --target model:rate:reps triple are stated.

Chapter 06: the wire envelope carries five fields, NOT the observed ledger —
only onTurn sees it; §1 gains a real curl transcript against a server started
with a scripted model (no live model), and a test pins that envelope's field set
on an ephemeral port; turn 0 renders on a never-refreshed StateView; the GPU
line no longer implies CPU-only is impossible; two captions now admit elided doc
comments and worldFromTools' signature shows its real default parameter.

mcp.listTools() stands: Mastra v1 deprecated getTools() and renamed it.
§5.6 still carried the pre-fix vocabulary ("fails on the ATTEMPT"), contradicting
§4: forbiddenToolCalls fails on the call REACHING the world, and the arms differ
by how far the write travels before something stops it.

The pinnedDecoding row implied looprun drops a flat temperature. It does not —
runSpecConversation and LoopRunAgent both normalize flat call settings into
modelSettings before calling Mastra; the drop is Mastra's own generate(). Row
rescoped, and the snippet comment no longer cites provider.ts as the reason.

The /v1/models body is a list envelope, not the model object.
The six tutorial chapters now carry the whole story, so the nine documents
they absorbed are removed: overview, getting-started, illustrated-guide,
examples, references, and all four guides/.

Before deleting, the six sections a prior review flagged as having no chapter
home were adjudicated individually:

  illustrated-guide 3.5  zero business strings      DROP - library-internal CI
                                                    invariant; the practical
                                                    consequence is in ch03 §2
  illustrated-guide 3.6  the debate gate            DROP - duplicated in README
  illustrated-guide 4    skill install + pipeline   DROP - agentspec-skill
                                                    methodology, owned by that
                                                    repo; install is in README
  illustrated-guide 4.4  the fail taxonomy          CARRIED - 7 of 8 rows are
                                                    already ch05 §5.7; row 8
                                                    (near-tie action coin) was
                                                    genuinely absent and is now
                                                    added there
  illustrated-guide 6    contributing               DROP - CONTRIBUTING.md and
                                                    governance/ are authoritative
  getting-started 2      agentspec pipeline         DROP - strict subset of the
                                                    README section

00-outline.md is NOT deleted. It is the standing record of the public-API
contract and is cited by path from all six src/index.ts barrels and their
surface-lock tests, so it moves to docs/superpowers/specs/ alongside the
inventory and the design. Every live citation is rewritten; the dated plan
and the governance proofs keep the old path, as records of what was true
when they were written.

Link integrity: docs/benchmarks.md repointed at the chapters; zero dead
relative links across README, docs/** and packages/*/README.md.
README is now what it should have been: what looprun is, install, a runnable
hello world, the six-chapter table, certify, local models, packages,
benchmarks. The agentspec pipeline shrinks to a bullet (private-beta skill,
own repo) and the hand-written path points at chapter 03.

Stale symbols corrected against the post-refactor barrels:

  compileSpec           README packages table    -> runSpecConversation,
                                                    worldFromTools (compileSpec
                                                    is internal to mastra)
  createOpenAiHandler   server README "API"      -> reachable as
                                                    createModelServer(...).handler
                                                    (verified on ModelServer)
  CaseDump              eval README, ch05        -> "one case dump per line";
                                                    the type is module-local
  getTools()            agent.ts JSDoc,          -> listTools(); getTools is
                        hermes-sim README           deprecated in Mastra v1
                                                    (codemod v1/mcp-get-tools).
                                                    Chapter 06 already taught
                                                    listTools; these were the
                                                    last stale copies
  core/internal seam    vercel README            -> names the subpath the backend
                                                    primitives actually live on,
                                                    and its lack of a promise

localModel stays headlined: the outline resolved it to public on
tutorial-contract grounds, so the docs and the barrel now agree.

Also corrects two comments that overstated what they pin: the
LoopRunResultMeta mirror does not catch an OPTIONAL field added to one side,
and canonArgs is keyed on by noDuplicateCall and pendingConfirmMustAsk
specifically, not by an unnamed set of "repetition kinds".

Governed-path edits here are comment-only; see the Task 12 proof record.
marcosluizfp and others added 6 commits July 29, 2026 23:48
The changeset bumps all seven packages major (the config links them), with
the before/after barrel counts derived from the actual barrels on main
rather than from memory: core 107 named + 2 wildcards -> 51 + 11 riders,
mastra 25 + 1 -> 7, models 24 -> 8, eval 52 -> 19, server 13 -> 4.

The migration notes give external consumers the old-symbol -> new-location
table, per repo:

  agentspec     renderTurnPrompt -> core/internal; the eval symbols
                synth-fork computes are untouched. Three reference-catalog
                corrections are owed there: forbidThisTurn is a
                binding-lifetime ban and not a repeat detector;
                lint-guard-catalog.mjs still scans the deleted
                packages/core/src/guards.ts and SKIPs silently rather than
                failing; a stale vendored dist/guards.d.ts will mask it
  looprun-bench runSpecConversation intact; nine runtime primitives move to
                core/internal; the shim's TrunkTheme/EvalCase/EvalConfig
                imports are phantom and never typechecked
  yntelli       no action - LoopRunAgent, validateSpec and worldFromTools
                are all on the taught surface

TWO OPEN USER DECISIONS are carried verbatim out of the outline's §6 so
they survive its move, and are NOT decided here:

  5  add looprun/eval + looprun/server facade subpaths, or keep the direct
     package names the tutorial uses today?
  6  @looprun-ai/vercel - ship the stub, implement it, or drop it?

Task 12 left both untouched. vercel still ships as a reserved stub.

The proof record covers the comment-only edits on packages/core/src and
packages/mastra/src. The claim is mechanical, not asserted: filtering the
governed diff for lines that do not start with a comment marker returns
nothing, so a behavior change is not expressible by it. Suite green anyway
at 495/495.
The bench and agentspec sections were written from the ledger's prose rather
than from the repos. Both are on disk; every claim below is now verified
against them.

MIGRATION NOTES, looprun-bench. The seam list was wrong in both directions.
The real seam file is
benchmarks/tau2-telecom/harness/shim/src/step-handler.ts, whose single
import block is the whole story:

  removed (0 occurrences anywhere in the bench):
    renderTurnPrompt, recordToolResult, isTerminal, terminalProtocol,
    forcedTerminalPrompt
  added (imported, and now /internal-only):
    enforcePostTool, redriveMessage, renderScopedSpecTrunk, resolveGuards,
    ReplyViolation
  marked unchanged-public:
    Guard, GuardCtx (taught by ch04), ObservedCall (shim/src/transcript.ts)

TrunkTheme/EvalConfig/EvalCase were misattributed to the shim, which is
clean. The "never existed" verdict holds - neither barrel has ever exported
them - but the real sites matter much more: TrunkTheme is 94 occurrences
across 40 files, essentially the entire Atlas v0.6.0 spec set, which is the
code behind the README's governed-96.5 headline. That spec set does not
typecheck against any published looprun and did not before this release
either; each theme.ts needs the type defined locally. Stated plainly in the
notes rather than buried, since a maintainer mid-migration is the right
person to learn it.

MIGRATION NOTES, agentspec. renderTurnPrompt has TWO call sites in two
scripts - synth-fork.mjs (:105 import, :178/:190 calls) and
extract-fork.mjs (:184 import, :210/:222 calls). The table pointed at one,
so a maintainer following it would fix half the problem. Both resolve the
package from the user's cwd at runtime, so neither fails at build time.

The lint-guard-catalog.mjs correction described a mechanism that does not
exist. It never scans repo sources: it resolves @looprun-ai/core from
node_modules and reads guards.d.ts next to the BUILT barrel. Post-split the
build emits dist/guards/index.d.ts, so the read throws and the catch prints
"engine not installed" - a false diagnosis that silently disables parity
checking. Rewritten around the actual mechanism, folding in the stale-dist
point, and prescribing the catch-message fix as part of it.

Also: the §7.1-not-discharged statement (recordVeto, VETO_STORM_LIMIT,
shouldFireChain remain test-only module exports by design, reachable from
no barrier) so an auditor does not read them as missed work.

SWEEP GAP. pnpm-workspace.yaml:4 - a live config file - still cited the
deleted docs/tutorial/00-outline.md. My first sweep missed it because the
grep filtered on --include=*.md,*.ts,*.mjs,*.json and never looked at YAML.
Re-run with no filter at all: only the two dated governance receipts remain,
which stay by design.

Also corrected: "all six src/index.ts barrels" cite the outline - it is five
(vercel has no taught surface); ch04's "four confusable clusters" heading
and "the four groups" body, which then present a fifth (honesty).

MINORS. Changeset now explains the looprun and vercel majors (the umbrella
re-exports core so the break reaches consumers through the facade; vercel
has no API change and rides the linked version group). README: seal added to
the eval verb list (verified as a real CLI verb), looprun/vercel subpath
named, core row scoped so the trunk renderer and turn machine are not
presented as public. The models-pull size string 3-21 GB -> 2.5-17 GB in all
five places, not one: ch06:202 is a verbatim --help transcript and had to
move with the CLI or stop matching it. Two RuntimeTurnInput test
doc-comments -> TurnInput. Outline's present-tense "Absorbs docs/guides/..."
-> past tense, since those files are now deleted.

Gate: build, 848 tests, typecheck, proofs 495/495, matrix in sync,
record-required OK, docs:guards idempotent, links 18/18 clean twice. No
governed path touched this round, so no new proof record is owed.
`tsc` only ever adds to `dist/` — it never removes an output whose source is
gone. After the guards.ts split and the coherence cut, a workspace built across
both layouts kept a pre-split `dist/guards.js` (80.8 kB) and `coherence.*` maps,
and `npm pack --dry-run` in packages/core listed all of them: 111 files shipped
where 106 exist.

Every publishable package gets a `clean` script, the root gets a recursive one,
and the release ritual's gate now cleans before it builds — the tarball is built
from whatever sits in `dist/`, so the clean belongs in the gate, not in a
maintainer's habits.

Verified: clean + build → `npm pack --dry-run` lists no `guards.js` and no
`coherence.*` at the dist root, and `dist/guards/` (the split) still ships.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
…cabulary of record

GUARDS.md called itself "the guard reference (source of truth)" and carried a
hand-maintained kind table headed "The 29 guard kinds" — while src/guards/ ships
30 — plus a "SIX RISK-FAMILY kinds" section built on the taxonomy this branch
already removed from the catalog summaries. CONTRIBUTING step 3 pointed every
new-guard PR at that table, so the drift was structural, not accidental.

Ruling applied: demote it. The sections that exist nowhere else stay verbatim —
the GuardCtx firewall and purity law, hook semantics, the prose-rendering and
prose≠reason laws with the parity proof, what AgentSpecBase auto-installs, the
reader-of-record traps, controls, P8a, the pair doctrine, behavior[]. The kind
list is replaced by a pointer to docs/tutorial/04-guards.md §5 (generated from
GUARD_CATALOG, examples compiled in CI) and to catalog.ts itself. The
risk-family section is gone.

Consequences: the parity test drops its markdown lane — it gated names in a file
that no longer lists any, and the GUARD_CATALOG lane is strictly stronger (an
entry must carry a summary, a when-to-use, an example that calls its own factory,
and the right category file). CONTRIBUTING step 3, the PR template and the
governance skill now say "add the GUARD_CATALOG entry, then pnpm docs:guards";
they also stop pointing at skills/agentspec/references/guard-catalog.md, a path
this repo does not have.

Also: catalog.ts backticks its identifier cross-references in summary/whenToUse,
so chapter 04's generated region stops reading as a second author beside its own
backticked prose; and chapter 04 §1 states the factory → Guard → kind mapping
once, since the audit trail shows kinds and the catalog is indexed by factory.

Proof record: governance/proofs/2026-07-29-guards-md-demoted-to-internals.md
(text-only on two governed paths; proofs 495/495 unchanged).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
Chapter 02 sets the reader up OUTSIDE the repo — they clone looprun, copy
./scheduler and ./hello.ts out of it, and work there. Every command in chapter 05
was then repo-relative (docs/tutorial/snippets/scheduler-subject), so nothing in
the chapter ran where the reader stood.

§4 now copies the subject out the same way 02 copies the modules, and says why
the two directories must sit side by side (norms/index.ts imports ../../scheduler
rather than re-declaring the spec). Every command switches to ./scheduler-subject
and ./scheduler.

The three transcripts marked **real** were re-run from that layout, not merely
re-pathed: lint (clean, exit 0), the CASE-WITHOUT-TARGET finding (exit 1), and
the four-command seal sequence. Both seal hashes come back byte-identical —
mintSeal hashes subject-RELATIVE paths, so the layout cannot move them — and the
caption now says so. The one **illustrative shape** stays labelled as such.

Also: 05 §1 tells the reader the §2 smoke test needs `npm i -D @looprun-ai/mastra`,
since scriptedModel lives on @looprun-ai/mastra/testing and on no looprun/*
subpath; 02 §1 mentions `npx looprun init` as the optional environment check the
root README already advertises; both chapters drop the "outline decision 5"
citations, which pointed the reader at an internal planning artifact, and state
the fact plainly instead; 06 surfaces examples/hermes-sim and ends with a short
"where next".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
Four packages published with no README at all — looprun, @looprun-ai/core,
@looprun-ai/mastra, @looprun-ai/models — so their npm pages showed only the
manifest description. Each gets a short one: what it is, the install line, what
is on the barrel, and a link to the tutorial. The link is an absolute GitHub URL
because npm pages cannot resolve repo-relative paths; the three existing READMEs
(server, eval, vercel) get the same line. `files` needed no change — npm always
ships README, verified with npm pack --dry-run.

Corrections:

- the changeset claimed "each barrel is now pinned by a surface-lock test, so it
  cannot drift back". Not literally true: the published ./testing subpaths of
  core and mastra re-export by wildcard (~27 symbols) and carry no lock. The
  claim now names that gap as a follow-up.
- packages/mastra/test/surface-lock.test.ts said its core lane resolved through
  the package specifier and therefore proved the built barrel — it reads
  core/src/index.ts by path and says nothing about dist.
- migration-notes said TrunkTheme occurs in 40 files; it is 39.
- the root README lost "a birth certificate, not vibes" and "first-class", which
  are marketing where a statement of what the artifact contains does the job, and
  gained a three-line note for returning readers whose old doc set was retired.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRBVNBAvFrTNLq2yfMU3u9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant