@north-light/crouter 0.3.208 → 0.3.210

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/dist/api/client.d.ts +3 -1
  2. package/dist/api/client.js +4 -0
  3. package/dist/api/dto/broker-ops.d.ts +2 -12
  4. package/dist/api/dto/nodes.d.ts +16 -0
  5. package/dist/api/routes.d.ts +1 -0
  6. package/dist/api/routes.js +1 -0
  7. package/dist/builtin-memory/00-runtime-base.md +3 -2
  8. package/dist/builtin-memory/01-spine/00-has-manager.md +3 -2
  9. package/dist/builtin-memory/01-spine/01-no-manager.md +3 -2
  10. package/dist/builtin-memory/02-lifecycle/00-terminal.md +3 -2
  11. package/dist/builtin-memory/02-lifecycle/01-resident.md +3 -2
  12. package/dist/builtin-memory/04-base-worker.md +3 -2
  13. package/dist/builtin-memory/04-orchestration-kernel.md +3 -2
  14. package/dist/builtin-memory/05-kinds/advisor/00-base.md +3 -2
  15. package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +3 -2
  16. package/dist/builtin-memory/05-kinds/design/00-base.md +3 -2
  17. package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +3 -2
  18. package/dist/builtin-memory/05-kinds/developer/00-base.md +3 -2
  19. package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +3 -2
  20. package/dist/builtin-memory/05-kinds/explore/00-base.md +3 -2
  21. package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +3 -2
  22. package/dist/builtin-memory/05-kinds/general/00-base.md +3 -2
  23. package/dist/builtin-memory/05-kinds/general/01-orchestrator.md +3 -2
  24. package/dist/builtin-memory/05-kinds/plan/00-base.md +3 -2
  25. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +3 -2
  26. package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +3 -2
  27. package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +3 -2
  28. package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +3 -2
  29. package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +3 -2
  30. package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +3 -2
  31. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +3 -2
  32. package/dist/builtin-memory/05-kinds/review/00-base.md +3 -2
  33. package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +3 -2
  34. package/dist/builtin-memory/05-kinds/review/companion/00-base.md +3 -2
  35. package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -2
  36. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +3 -2
  37. package/dist/builtin-memory/05-kinds/spec/requirements.md +3 -2
  38. package/dist/builtin-memory/advisor/council.md +0 -2
  39. package/dist/builtin-memory/design.md +3 -2
  40. package/dist/builtin-memory/development.md +3 -2
  41. package/dist/builtin-memory/insights/capture.md +1 -3
  42. package/dist/builtin-memory/insights/init.md +1 -3
  43. package/dist/builtin-memory/insights/listen.md +3 -2
  44. package/dist/builtin-memory/internal/INDEX.md +5 -4
  45. package/dist/builtin-memory/internal/agent-shaping.md +5 -4
  46. package/dist/builtin-memory/internal/examples/INDEX.md +3 -2
  47. package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -2
  48. package/dist/builtin-memory/internal/marketplaces.md +3 -2
  49. package/dist/builtin-memory/internal/memory-loading.md +31 -20
  50. package/dist/builtin-memory/internal/nodes-and-canvas.md +3 -2
  51. package/dist/builtin-memory/internal/plugins.md +7 -6
  52. package/dist/builtin-memory/internal/storage-tiers.md +3 -2
  53. package/dist/builtin-memory/plan/roadmap.md +3 -2
  54. package/dist/builtin-memory/spec/guide.md +0 -2
  55. package/dist/builtin-memory/spec/requirements.md +0 -2
  56. package/dist/builtin-memory/spec/roadmap.md +3 -2
  57. package/dist/builtin-memory/testing.md +1 -3
  58. package/dist/builtin-memory/wedged-child-on-runaway-bash.md +3 -2
  59. package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +1 -1
  60. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +3 -3
  61. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +1 -4
  62. package/dist/clients/attach/viewer.js +366 -366
  63. package/dist/commands/memory/delete.js +3 -18
  64. package/dist/commands/memory/edit.js +23 -30
  65. package/dist/commands/memory/history.js +1 -1
  66. package/dist/commands/memory/lint.d.ts +7 -8
  67. package/dist/commands/memory/lint.js +178 -132
  68. package/dist/commands/memory/list.d.ts +0 -1
  69. package/dist/commands/memory/list.js +2 -12
  70. package/dist/commands/memory/move.d.ts +1 -0
  71. package/dist/commands/memory/move.js +195 -0
  72. package/dist/commands/memory/read.js +135 -141
  73. package/dist/commands/memory/shared.d.ts +18 -17
  74. package/dist/commands/memory/shared.js +93 -39
  75. package/dist/commands/memory/write.js +23 -33
  76. package/dist/commands/memory.js +5 -4
  77. package/dist/commands/pkg/browse/catalog.js +2 -4
  78. package/dist/commands/pkg/browse/doc-view.js +17 -11
  79. package/dist/commands/pkg/browse/model.d.ts +7 -9
  80. package/dist/commands/sys/migrate.d.ts +1 -0
  81. package/dist/commands/sys/migrate.js +106 -0
  82. package/dist/commands/sys/sync-deps.js +5 -10
  83. package/dist/commands/sys/sync-project-guidance.js +36 -16
  84. package/dist/commands/sys/sync-skills.js +8 -4
  85. package/dist/commands/sys.js +3 -2
  86. package/dist/core/__tests__/inline-memory-refs.test.js +8 -5
  87. package/dist/core/__tests__/memory-resolver-precedence.test.js +5 -4
  88. package/dist/core/__tests__/nested-store-discovery.test.js +1 -3
  89. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +3 -3
  90. package/dist/core/__tests__/on-read-dedup-resume.test.js +12 -12
  91. package/dist/core/__tests__/on-read-nested-store.test.js +23 -20
  92. package/dist/core/canvas/db.d.ts +3 -1
  93. package/dist/core/canvas/db.js +12 -2
  94. package/dist/core/memory/history.d.ts +4 -1
  95. package/dist/core/memory/history.js +1 -0
  96. package/dist/core/memory/inline-ref-inventory.d.ts +5 -4
  97. package/dist/core/memory/inline-ref-inventory.js +23 -19
  98. package/dist/core/memory-resolver.d.ts +4 -4
  99. package/dist/core/memory-resolver.js +16 -43
  100. package/dist/core/runtime/bearings.d.ts +4 -3
  101. package/dist/core/runtime/bearings.js +4 -4
  102. package/dist/core/runtime/broker-extension-render.d.ts +3 -2
  103. package/dist/core/runtime/broker-extension-render.js +3 -3
  104. package/dist/core/runtime/memory.js +2 -3
  105. package/dist/core/substrate/index.d.ts +7 -4
  106. package/dist/core/substrate/index.js +6 -4
  107. package/dist/core/substrate/injected-store.d.ts +24 -12
  108. package/dist/core/substrate/injected-store.js +80 -33
  109. package/dist/core/substrate/listings.d.ts +21 -0
  110. package/dist/core/substrate/listings.js +88 -0
  111. package/dist/core/substrate/on-read-node.d.ts +5 -5
  112. package/dist/core/substrate/on-read-node.js +4 -5
  113. package/dist/core/substrate/on-read.d.ts +25 -4
  114. package/dist/core/substrate/on-read.js +81 -102
  115. package/dist/core/substrate/render-node.d.ts +5 -2
  116. package/dist/core/substrate/render-node.js +5 -3
  117. package/dist/core/substrate/render.d.ts +9 -8
  118. package/dist/core/substrate/render.js +104 -96
  119. package/dist/core/substrate/schema.d.ts +34 -18
  120. package/dist/core/substrate/schema.js +75 -32
  121. package/dist/core/substrate/surface-match.d.ts +32 -0
  122. package/dist/core/substrate/surface-match.js +179 -0
  123. package/dist/daemon/api/handlers/nodes.js +9 -0
  124. package/dist/migrations/001-surfaces-frontmatter.d.ts +2 -0
  125. package/dist/migrations/001-surfaces-frontmatter.js +276 -0
  126. package/dist/migrations/convergent.d.ts +31 -0
  127. package/dist/migrations/convergent.js +71 -0
  128. package/dist/migrations/registry.d.ts +2 -0
  129. package/dist/migrations/registry.js +19 -0
  130. package/dist/migrations/types.d.ts +40 -0
  131. package/dist/migrations/types.js +11 -0
  132. package/dist/pi-extensions/canvas-context-intro.d.ts +2 -1
  133. package/dist/pi-extensions/canvas-doc-substrate.d.ts +2 -1
  134. package/dist/pi-extensions/canvas-doc-substrate.js +57 -34
  135. package/package.json +1 -1
  136. package/runtime.lock.json +2 -2
  137. package/dist/core/substrate/ceiling.d.ts +0 -17
  138. package/dist/core/substrate/ceiling.js +0 -67
@@ -2,8 +2,6 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When directly received user material supports a proposed reusable principle, this knowledge should be read because review by the user keeps durable guidance grounded in their actual judgment.
4
4
  short-form: Extract the why behind one user-derived principle, review its truth and destination, then write only what the user approves.
5
- system-prompt-visibility: none
6
- file-read-visibility: none
7
5
  rationale: Agents have missed deeper user insight hidden in ordinary feedback, saved their own unreviewed interpretation as fundamental truth, and — when the user corrected a behavior — proposed the corrected behavior itself as the insight when the durable truth was the reason the user made the correction. The earlier proposal template compounded this by framing capture as correction (a "Current truth" section) and burying destination and source in prose sections.
8
6
  ---
9
7
 
@@ -45,6 +43,6 @@ The review is asynchronous. Continue unrelated work or wait dormant, but do not
45
43
 
46
44
  Apply direct line edits and explicit comments. If feedback requires a materially new formulation, update the open review artifact or submit a replacement review; review the revised formulation before writing it. If no candidate survives, save nothing.
47
45
 
48
- Run `crtr memory write -h` for the authoring contract, then reach only the approved destination — `crtr memory write` to create it, `crtr memory edit` to revise one that exists. A new principle is normally knowledge, and a preference only when its use is behavioral; use `none` visibility on both axes unless review approves a flat boot-rung exception. Keep its body to the approved truth, any material boundary, and the concise why. Update the selected active listener or organizing router with the canonical link without duplicating the principle.
46
+ Run `crtr memory write -h` for the authoring contract, then reach only the approved destination — `crtr memory write` to create it, `crtr memory edit` to revise one that exists. A new principle is normally knowledge, and a preference only when its use is behavioral; give it no `surfaces` routing unless review approves a boot entry. Keep its body to the approved truth, any material boundary, and the concise why. Update the selected active listener or organizing router with the canonical link without duplicating the principle.
49
47
 
50
48
  Source context and agent reasoning stay only in the review artifact. Do not copy them into semantic memory or provenance frontmatter. Run `crtr memory lint` after every create or rewrite and fix every finding.
@@ -2,8 +2,6 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When the user invokes /insights:init to begin gathering user-derived insight about a domain, this knowledge should be read because a correctly scoped listener preserves uniquely valuable knowledge without creating a parallel store or background system.
4
4
  short-form: Initialize passive insight gathering for a domain at the narrowest durable scope; create one routed topic index that reviews user-derived principles before saving them.
5
- system-prompt-visibility: none
6
- file-read-visibility: none
7
5
  slash: true
8
6
  rationale: Ordinary conversations, corrections, answers to `crtr human send`, and review comments carry unique user knowledge that agents inconsistently recognize or save; when agents do infer a deeper principle, they have written it without first letting the user correct the extrapolation.
9
7
  ---
@@ -34,7 +32,7 @@ Search the chosen scope before creating. If `insights/<topic>` already represent
34
32
 
35
33
  ## Create the listener
36
34
 
37
- Run `crtr memory write -h`, then create `insights/<topic>/INDEX.md` at the chosen scope as a preference with system-prompt visibility `preview` and file-read visibility `none`.
35
+ Run `crtr memory write -h`, then create `insights/<topic>/INDEX.md` at the chosen scope as a preference surfaced `{on: boot, at: preview}`.
38
36
 
39
37
  Its routing line must name the actual domain trigger: when user-supplied information, a correction, or a user response relates to this domain, read the preference because recognizing the underlying principle preserves knowledge future decisions can use.
40
38
 
@@ -1,9 +1,10 @@
1
1
  ---
2
2
  kind: preference
3
3
  when-and-why-to-read: When directly received user material may contain a reusable principle, this preference should be read because knowledge unavailable from model weights should guide future decisions instead of disappearing with the episode.
4
- system-prompt-visibility: content
5
- file-read-visibility: none
6
4
  rationale: Agents currently miss reusable alpha and sometimes save their own extrapolation without review.
5
+ surfaces:
6
+ - on: boot
7
+ at: content
7
8
  ---
8
9
 
9
10
  When directly received user-supplied or user-validated material may contain a coherent reusable principle, follow [[insights/capture]]. Use an active domain listener's boundary when one matches; otherwise use the higher bar: the episode must justify a permanent reusable principle future agents should be routed to, and a new domain needs that principle as its first approved truth. Do not treat approval of an insight review as a fresh candidate, because user knowledge unavailable from model weights should not disappear with the episode.
@@ -2,8 +2,9 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When you hit a question about how the crtr runtime itself works or how to extend it — how nodes and the canvas behave, where state lives on disk, how to add plugins/commands/marketplaces to crtr, or how the primitives compose into real systems — this index should be read so runtime-sensitive work follows the canonical model instead of fragile inferences from scattered command help.
4
4
  short-form: internal/ is the runtime's self- and developer-documentation — operational guides to nodes/canvas and the storage tiers, plugin command and marketplace authoring, plus worked example compositions. Open it to understand how crtr works or to extend it.
5
- system-prompt-visibility: preview
6
- file-read-visibility: none
5
+ surfaces:
6
+ - on: boot
7
+ at: preview
7
8
  ---
8
9
 
9
10
  # internal/ — how the crtr runtime works, and how to extend it
@@ -14,13 +15,13 @@ Open this dir whenever a task turns on understanding the runtime itself or chang
14
15
 
15
16
  - **nodes-and-canvas** — the agent-runtime model: nodes on the canvas graph, spawn/delegate, the push/feed spine, lifecycle (mode + lifecycle axes), and revive (manual + daemon auto-revive).
16
17
  - **storage-tiers** — where every kind of state lives: the two tiers (scope root and canvas home) and their durability/ownership contracts.
17
- - **memory-loading** — the memory load model: the two hooks (boot catalog, file-read), the four-rung ladder, gates, applies-to/read-when routing, boot-render ordering, and store mounting/precedence — read when diagnosing why a doc did or didn't load.
18
+ - **memory-loading** — the memory load model: the five surface events, the rung ladder, gates, listings, boot-render ordering, and store mounting/precedence — read when diagnosing why a doc did or didn't load.
18
19
  - **agent-shaping** — the when-to-use-which layer over the four dials that shape a node: kinds (the builtin roster, sub-kinds, and custom personas), modes (base vs orchestrator), profiles, and the memory tiers (node/profile/project/user/builtin).
19
20
  - **plugins** — authoring a crtr plugin: the plugin.json manifest, directory layout, scopes, install mechanics, versioning, command-capable plugins (contributing top-level CLI commands through commands.json plus an exec or HTTP transport), and bare binaries a plugin or scope puts on every node's PATH.
20
21
  - **marketplaces** — authoring a crtr marketplace: the marketplace.json index, local-link and remote-Git plugin sources, auto-bump CI, dual-publishing.
21
22
  - **examples/** — worked compositions of the primitives into complete systems (the analogue of pi's `examples/` dir), e.g. the iMessage assistant node.
22
23
 
23
- Adjacent, outside this dir: authoring memory documents (kind, rungs, gates, routing line, the asked-to-remember workflow) is owned by `crtr memory write -h` — the authoring guide lives on that `-h` surface so it surfaces exactly when you write.
24
+ Adjacent, outside this dir: authoring memory documents (kind, surfaces routing, gates, routing line, the asked-to-remember workflow) is owned by `crtr memory write -h` — the authoring guide lives on that `-h` surface so it surfaces exactly when you write.
24
25
 
25
26
  Briefly: **plugins** package docs and commands, with command execution selected by `plugin.json.transport` (`exec` for a trusted local executable or `http` for a fetched remote REST manifest); **marketplaces** index and distribute plugins. Plugin commands enter the **external-command** fallthrough, leaving the core fast-path untouched.
26
27
 
@@ -2,14 +2,15 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When you are choosing how to shape a node — which kind to spawn, base vs orchestrator, which profile, or which memory scope a doc belongs in — this reference should be read so each task gets the right role, orchestration depth, identity, and guidance reach instead of paying for a mismatched agent shape.
4
4
  short-form: The four orthogonal dials that shape a node — kind (role + model tier), mode (base vs orchestrator), profile (identity + purview), and memory tier (who sees a doc) — plus when to reach for each over its alternatives.
5
- system-prompt-visibility: name
6
- file-read-visibility: none
7
5
  rationale: Agents pick shaping dials by reflex from the one-line `-h` blurbs and get the discriminators wrong — delegating debugging to explore instead of advisor, grinding an orchestrator-shaped job in base, minting a duplicate memory doc at the wrong scope. The per-kind base docs carry the rationale but only the running node of that kind ever sees them; nothing gave a chooser the cross-cutting "which one, and why it's built this way" view before committing.
6
+ surfaces:
7
+ - on: boot
8
+ at: name
8
9
  ---
9
10
 
10
11
  # Agent shaping — kinds, modes, profiles, and memory tiers
11
12
 
12
- Four orthogonal dials shape every node. This is the **when-to-use-which** layer over them — the philosophy of each and how to choose between alternatives. It does not cover mechanics: the node/canvas/lifecycle model is `internal/nodes-and-canvas`, the physical disk layout of every store is `internal/storage-tiers`, and the authoring/routing/visibility contract for memory docs is `crtr memory write -h`. Point at those; this doc decides which dial to turn.
13
+ Four orthogonal dials shape every node. This is the **when-to-use-which** layer over them — the philosophy of each and how to choose between alternatives. It does not cover mechanics: the node/canvas/lifecycle model is `internal/nodes-and-canvas`, the physical disk layout of every store is `internal/storage-tiers`, and the authoring/routing contract for memory docs is `crtr memory write -h`. Point at those; this doc decides which dial to turn.
13
14
 
14
15
  The dials are independent — you set each without constraining the others:
15
16
 
@@ -66,7 +67,7 @@ Reach for a **new** profile when a distinct body of work has its own set of dire
66
67
 
67
68
  ## Memory tiers — where a doc lives decides who sees it
68
69
 
69
- A memory doc's **scope** is a reach dial: the wider the scope, the more agents pay to carry it, forever. Choose the **narrowest scope that still reaches the next agent who needs it**. Physical paths and durability contracts are in `internal/storage-tiers`; the frontmatter/routing/visibility contract is `crtr memory write -h`. The scopes, narrowest reach to widest:
70
+ A memory doc's **scope** is a reach dial: the wider the scope, the more agents pay to carry it, forever. Choose the **narrowest scope that still reaches the next agent who needs it**. Physical paths and durability contracts are in `internal/storage-tiers`; the frontmatter/routing contract is `crtr memory write -h`. The scopes, narrowest reach to widest:
70
71
 
71
72
  - **node** (`nodes/<id>/context/memory/`) — only *this* running node sees it; rides its boot context and dies with the node. Scratch memory for one goal's cross-refresh state.
72
73
  - **profile** (the profile's own store) — every node running under that profile, across all the dirs in its purview. Cross-repo conventions and the user's stance toward that bundle of work.
@@ -2,8 +2,9 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When you want a worked end-to-end composition of crouter primitives — not what one command does but how several combine into a real standing system — open this dir so you can reuse a proven shape instead of re-deriving how the primitives fit or relying on unverified OS assumptions.
4
4
  short-form: Worked examples composing crouter primitives into complete systems (like pi's examples/ dir). Currently — the iMessage assistant node.
5
- system-prompt-visibility: name
6
- file-read-visibility: none
5
+ surfaces:
6
+ - on: boot
7
+ at: name
7
8
  ---
8
9
 
9
10
  # internal/examples/ — worked compositions of crouter primitives
@@ -2,8 +2,9 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When you are building a standing assistant node bridged to an external channel — iMessage, email, a chat service — this example should be read so you can reuse a proven event-driven shape and avoid rediscovering macOS messaging traps.
4
4
  short-form: Worked example — an always-on iMessage assistant built from crouter primitives. Resident root node + launchd watcher → node message send wakes + chat.db reads + osascript sends + substrate memory.
5
- system-prompt-visibility: name
6
- file-read-visibility: none
5
+ surfaces:
6
+ - on: boot
7
+ at: name
7
8
  ---
8
9
 
9
10
  # Example: an iMessage assistant node (OpenClaw-style)
@@ -2,8 +2,9 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When creating a crtr marketplace or contributing plugins to one, this knowledge should be read so indexed plugins install and update coherently without release automation desynchronizing their versions.
4
4
  short-form: How to author a crtr marketplace — marketplace.json index, plugin entries, symlink-based install, auto-bump CI, dual-publishing. Use when creating a marketplace or contributing plugins to one.
5
- system-prompt-visibility: name
6
- file-read-visibility: none
5
+ surfaces:
6
+ - on: boot
7
+ at: name
7
8
  ---
8
9
 
9
10
  # Authoring crtr marketplaces
@@ -1,47 +1,58 @@
1
1
  ---
2
2
  kind: knowledge
3
- when-and-why-to-read: When you need to know why a memory doc did or didn't load — or are deciding how a new doc should surface — this reference should be read because it names the hook, rung, gate, and ordering that produced the behavior, so you fix loading by turning the right dial instead of guessing at frontmatter.
4
- short-form: The complete load model — two hooks (boot catalog, file-read), the four-rung ladder, gates, applies-to/read-when routing, boot-render ordering, and store mounting/precedence.
5
- system-prompt-visibility: name
6
- file-read-visibility: none
3
+ when-and-why-to-read: When you need to know why a memory doc did or didn't load — or are deciding how a new doc should surface — this reference should be read because it names the event, rung, gate, and ordering that produced the behavior, so you fix loading by turning the right dial instead of guessing at frontmatter.
4
+ short-form: The complete load model — the five surface events, the rung ladder, gates, listings, transcript dedup, boot-render ordering, and store mounting/precedence.
5
+ surfaces:
6
+ - on: boot
7
+ at: name
7
8
  ---
8
9
 
9
10
  # How memory loads
10
11
 
11
- Every memory doc declares its own loading policy in frontmatter; the runtime never guesses. Loading is two hooks, one four-rung dial per hook, an optional gate, and structural ordering. The authoring contract (flags, routing-line craft) is `crtr memory write -h`; which scope to write to is `internal/agent-shaping`; physical paths are `internal/storage-tiers`. This doc is the mechanics between those: what actually fires, when, and in what order.
12
+ Every memory doc declares its own delivery in frontmatter `surfaces` entries; the runtime never guesses. Delivery is five events, one rung per entry, an optional gate, and structural ordering. The authoring contract (flags, routing-line craft) is `crtr memory write -h`; which scope to write to is `internal/agent-shaping`; physical paths are `internal/storage-tiers`. This doc is the mechanics between those: what actually fires, when, and in what order.
12
13
 
13
- ## The two hooks
14
+ ## Surfaces entries
14
15
 
15
- - **System prompt** (`system-prompt-visibility`) — the boot catalog assembled into every node's system prompt at revive.
16
- - **File read** (`file-read-visibility`) — context attached to the workspace or to files. Two events: **workspace mount** during first-message assembly (docs routed `applies-to: "."`), and a later **matching file read** — docs routed by glob, and `.`-routed docs whose store's owning dir contains the read file. Nothing positional fires from where the doc happens to sit on disk — only from its declared route.
16
+ A doc with no `surfaces` does exactly one thing: appears in its directory's listing. Everything beyond that is an explicit entry — `{on: <event>, match?, match-frontmatter?, at: <rung>}`. Entries OR across; multiple entries per event are legal. The events:
17
17
 
18
- Each doc sets both rungs explicitly; there is no kind-based default. Usually one axis carries a real rung and the other is `none`.
18
+ - **boot** — the catalog assembled into every node's system prompt at revive. No match; the entry's presence is the match.
19
+ - **workspace-open** — first-message context when cwd/profile mounts the doc's project store. Project stores only.
20
+ - **read** — a `read` tool call returned a matching file: path globs vs the file's absolute path and basename, `./`-anchored globs vs its path relative to the store's owning repo dir, `match-frontmatter` predicates over the read file's own YAML frontmatter.
21
+ - **memory-read** — a `crtr memory read` resolved a matching doc: name globs vs its canonical name, `./` anchored to this doc's own name directory.
22
+ - **command** — a matching shell command ran: globs vs the whole command string, `*` crossing `/`. Delivery is post-execution — right for "you are now in this territory," never for "don't run this at all."
23
+
24
+ Nothing positional fires from where a doc happens to sit on disk — only from its declared entries and its listing.
19
25
 
20
26
  ## The rung ladder
21
27
 
22
- `none` → `name` → `preview` → `content`, per hook:
28
+ `at` sets how much delivers when an entry fires:
23
29
 
24
- - `none` — invisible on that hook; findable only by search/read. For archival docs and for the unused axis.
25
- - `name` — the bare title. The practical floor: an agent can't reach for a doc it has never seen named.
30
+ - `name` — the bare title. The practical boot floor: an agent can't reach for a doc it has never seen named.
26
31
  - `preview` — name + the `when-and-why-to-read` routing line, rendered verbatim. The heart of progressive disclosure: one sentence that lets an agent decide whether to spend the read.
27
- - `content` — the full body inlined. Reserved for always-relevant docs that are either a bullet's worth of text or a wholly-important operating guide (the root INDEX shape below).
32
+ - `content` — the full body inlined. Reserved for always-relevant docs that are either a bullet's worth of text or a wholly-important operating guide (the workspace front door below).
33
+
34
+ Silence is the absence of an entry; there is no `none` rung. `short-form` is **not** a rung and never enters agent context — it exists for the user browsing `crtr memory list`. Disclosure is name → routing line → whole thing; there is deliberately no "just the summary" level, because agents satisfice on abbreviations and never read the rest.
35
+
36
+ ## Gates
37
+
38
+ An optional `gate` predicates every entry on the node's own config — kind, mode, orchestration depth, scope, cwd — using the standard matcher vocabulary (`crtr memory write -h`). No gate means always eligible. Persona prose is just gated boot-content docs (`gate: {kind: developer, mode: base}`); guidance that should scale with effort is one predicate (`orchestration.depth: {gte: 2}`), not a mechanism.
28
39
 
29
- `short-form` is **not** a rung and never enters agent context — it exists for the user browsing `crtr memory list`. Disclosure is name → routing line → whole thing; there is deliberately no "just the summary" level, because agents satisfice on abbreviations and never read the rest.
40
+ ## Listings and dedup
30
41
 
31
- ## Gates and read-when
42
+ Reading a doc discloses where it sits: `crtr memory read <doc>` also renders, once per transcript, the listing of the doc's directory and each ancestor — one routing line per member doc, one bare name per subdirectory. `crtr memory read <dir>` (or a bare-dir `[[ref]]`) returns the listing itself; no doc answers for a directory. `unlisted: true` suppresses a doc from every listing. Store roots are never auto-listed — `crtr memory list` is the deliberate root browse.
32
43
 
33
- An optional `gate` predicates visibility on the node's own config — kind, mode, orchestration depth, scope, cwd — using the standard matcher vocabulary (`crtr memory write -h`). No gate means always eligible. Persona prose is just gated content-rung docs (`gate: {kind: developer, mode: base}`); guidance that should scale with effort is one predicate (`orchestration.depth: {gte: 2}`), not a mechanism. `read-when` additionally matches the *read file's* frontmatter on the file-read hook; it refines a route but never replaces the required `applies-to` boundary.
44
+ Every delivery dedups per transcript keyed on (doc, rung), higher rungs piercing lower: a listing line is a preview-rank render, boot renders seed the set at their boot rung, and a content delivery silences everything after it.
34
45
 
35
46
  ## Store mounting and precedence
36
47
 
37
48
  At boot/first-message assembly the runtime mounts: builtin docs, the user store (`~/.crouter/memory/`), the selected profile's store, and every project store — ancestor `.crouter/memory/` dirs walking up from cwd plus each project in the profile's purview. Physical duplicates are deduplicated; name collisions resolve nearest-first (project over profile over user over builtin), which is what lets a project doc shadow a builtin one.
38
49
 
39
- A root `INDEX.md` is a workspace's front door: `system-prompt-visibility: none`, `file-read-visibility: content`, `applies-to: "."` — the operating guide loads when that workspace mounts, not in every boot catalog. Multiple mounted roots render broad-to-specific, each under its own envelope name.
50
+ A workspace's front door is an ordinary doc carrying the entry pair `{on: workspace-open, at: content}` + `{on: read, match: "./**", at: content}` — the operating guide loads when that workspace mounts or its files are read, not in every boot catalog. `crtr memory lint` requires exactly one workspace-open content doc per profile-managed project store. Multiple mounted roots render broad-to-specific.
40
51
 
41
- A `.crouter/memory/` store nested BELOW a mounted root (a package or subsystem dir) is delivered by the read path, not by boot: reading any file beneath its owning dir surfaces its `.`-routed docs, deduplicated against everything already in the transcript. Addressability is separate — the `crtr memory` leaves (list/read/find/lint/delete/origin) discover nested stores through a bounded walk (git-aware, depth- and time-capped), while the boot catalog stays ancestor+profile only, which is why a nested doc's `system-prompt-visibility` rung is inert (lint warns; set `none`).
52
+ A `.crouter/memory/` store nested BELOW a mounted root (a package or subsystem dir) is delivered by the read path, not by boot: reading any file beneath its owning dir surfaces its read-routed docs, deduplicated against everything already in the transcript. Addressability is separate — the `crtr memory` leaves (list/read/find/lint/delete/origin) discover nested stores through a bounded walk (git-aware, depth- and time-capped), while the boot catalog stays ancestor+profile only, which is why a nested doc's boot entries are inert (lint warns; drop them).
42
53
 
43
54
  ## Ordering
44
55
 
45
- The boot render is structural, never a per-doc knob: docs group by rung (content bodies as prose, then previews, then names), and within a group order general-to-specific — scope first (builtin → user → profile → outermost project root → nearest), then tree position (higher directories before deeper), then filename. A numeric `NN-` filename prefix (stripped from the doc's name) is the sparing escape hatch when an exact sequence must be pinned.
56
+ The boot render is structural, never a per-doc knob: docs group by boot rung (content bodies as prose, then previews, then names), and within a group order general-to-specific — scope first (builtin → user → profile → outermost project root → nearest), then tree position (higher directories before deeper), then filename. A numeric `NN-` filename prefix (stripped from the doc's name) is the sparing escape hatch when an exact sequence must be pinned.
46
57
 
47
- `crtr memory lint` is the validator for all of the above: frontmatter schema, both rungs present, routes on every non-`none` file-read rung, rung-scaled body length, dangling `[[links]]`, and each profile-managed project's front door.
58
+ `crtr memory lint` is the validator for all of the above: frontmatter schema, strict `surfaces` entries, rung-scaled body length, dangling `[[links]]`, and each profile-managed project's front door.
@@ -2,8 +2,9 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When you are operating the canvas — spawning or steering nodes, deciding how work reports up, recovering a dormant or crashed node, or reasoning about the daemon — this reference should be read so lifecycle and reporting operations preserve one live engine, deliver results reliably, and recover nodes without corrupting state.
4
4
  short-form: Operational model of the agent runtime — nodes on the canvas graph, spawn/delegate, the push/feed spine, lifecycle states, and revive (manual + daemon auto-revive).
5
- system-prompt-visibility: name
6
- file-read-visibility: none
5
+ surfaces:
6
+ - on: boot
7
+ at: name
7
8
  ---
8
9
 
9
10
  # How nodes and the canvas work (operational)
@@ -2,8 +2,9 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When creating a crtr plugin, packaging memory docs for distribution, adding top-level CLI commands via a command manifest, or debugging install/resolution, this knowledge should be read so installs resolve predictably across scopes and command surfaces do not fail from manifest drift or protocol mistakes.
4
4
  short-form: How to author a crtr plugin — plugin.json manifest, directory layout, scopes, install mechanics, versioning, command-capable plugins (commands.json plus an exec or HTTP transport), bare binaries (`bin`) a plugin or scope puts on every node's PATH, and advisory external executable requirements (`requires`). Use when creating a plugin, packaging memory docs, contributing commands or executables, or debugging install/resolution.
5
- system-prompt-visibility: name
6
- file-read-visibility: none
5
+ surfaces:
6
+ - on: boot
7
+ at: name
7
8
  ---
8
9
 
9
10
  # Authoring crtr plugins
@@ -32,7 +33,7 @@ If it's a one-off note for yourself, scope-owned memory docs are simpler. Promot
32
33
  └── memory/
33
34
  ├── <name>.md # a kind:knowledge or kind:preference doc
34
35
  └── <area>/
35
- ├── INDEX.md # optional — a dir surfaces as one entry at its INDEX rung
36
+ ├── INDEX.md # optional — an ordinary doc; a bare-dir read answers with the listing
36
37
  └── <name>.md
37
38
  ```
38
39
 
@@ -71,7 +72,7 @@ The `<plugin-name>` directory IS the plugin. The manifest's `name` field must ma
71
72
 
72
73
  ## Plugin kinds
73
74
 
74
- A plugin can ship a complete persona kind: declare the registry entry in the manifest's `kinds` block, and author the persona prose as ordinary plugin memory docs gated `{kind: <name>, mode: base}` (and `{kind: <name>, mode: orchestrator}`) with `system-prompt-visibility: content` — the same shape a builtin kind uses at `kinds/<kind>/00-base.md`. Nothing else is needed: gates evaluate uniformly over plugin docs, so the persona splices into any node launched with that kind.
75
+ A plugin can ship a complete persona kind: declare the registry entry in the manifest's `kinds` block, and author the persona prose as ordinary plugin memory docs gated `{kind: <name>, mode: base}` (and `{kind: <name>, mode: orchestrator}`) surfaced `{on: boot, at: content}` — the same shape a builtin kind uses at `kinds/<kind>/00-base.md`. Nothing else is needed: gates evaluate uniformly over plugin docs, so the persona splices into any node launched with that kind.
75
76
 
76
77
  `readMergedLaunchConfig` layers an enabled plugin's `kinds` entries directly above the builtin registry and below its host scope's own `config.json` — full precedence: builtin → user-scope plugins → user config → profile → per project root (that root's plugins → that root's config). So a plugin kind appears in `crtr node new -h` and is launchable like any other, and a user or project `config.json` can still patch or shadow it. Plugins within one scope layer name-sorted; the scope's own config always wins.
77
78
 
@@ -157,7 +158,7 @@ Standard semver:
157
158
 
158
159
  `crtr pkg plugin disable <name>` flips the per-scope config without removing files. Disabled plugins are hidden from `crtr memory list` and don't resolve via `crtr memory read <name>`. Re-enable with `crtr pkg plugin enable <name>`.
159
160
 
160
- Individual memory docs inside an enabled plugin are hidden by setting their frontmatter visibility rungs to `none` (or a gate that fails), not by a command — see `crtr memory write -h`.
161
+ Individual memory docs inside an enabled plugin are hidden by giving them no `surfaces` entries plus `unlisted: true` (or a gate that fails), not by a command — see `crtr memory write -h`.
161
162
 
162
163
  ## What goes in a plugin
163
164
 
@@ -319,7 +320,7 @@ Two contributors at the same precedence claiming one name is a collision, not a
319
320
  - When the plugin (or a scope `config.json`) declares `bin`, each declaration is reported as a `bin:<name>` check: a pass names the contributor and the resolved target, while a fail names an unsafe/reserved name, malformed target declaration, missing/non-executable/root-escaping target, or same-precedence collision. Contributed binaries are never executed during validation. Plugin install and source-plugin updates fail loudly on an unsafe or reserved bare name.
320
321
  - When an enabled plugin declares `requires`, each `requires:<name>` check names the plugin and resolved executable path on pass, or carries its install hint as remediation on fail. The executable is never run; a malformed declaration fails source-plugin install and update, while an absent executable remains advisory.
321
322
 
322
- `crtr memory lint` checks the docs under `memory/`: frontmatter parses, valid `kind`, both visibility rungs set. Run `crtr memory write -h` for the authoring + routing guide. Other sibling artifact dirs (`rules/`, `agents/`, `hooks/`) are validated by their respective specs as those land.
323
+ `crtr memory lint` checks the docs under `memory/`: frontmatter parses, valid `kind`, valid `surfaces` entries. Run `crtr memory write -h` for the authoring + routing guide. Other sibling artifact dirs (`rules/`, `agents/`, `hooks/`) are validated by their respective specs as those land.
323
324
 
324
325
  ## Cross-publishing with Claude Code
325
326
 
@@ -3,9 +3,10 @@ name: internal/storage-tiers
3
3
  kind: knowledge
4
4
  description: Where crouter state belongs
5
5
  when-and-why-to-read: When locating crtr state or deciding where a new file belongs, this reference should be read so files are found or placed in the storage tier with the right ownership and durability.
6
- system-prompt-visibility: name
7
- file-read-visibility: none
8
6
  short-form: The two crtr storage tiers — scope root for durable user/repo content and canvas home for node-graph runtime state, node artifacts, and human tickets.
7
+ surfaces:
8
+ - on: boot
9
+ at: name
9
10
  ---
10
11
 
11
12
  # Where everything lives (the two storage tiers)
@@ -2,11 +2,12 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When shaping a planning roadmap, deciding plan structure, or preparing a consequential plan for implementation, this knowledge should be read so implementation receives a right-sized, parallel-safe execution map whose gaps are caught while they are still cheap to fix.
4
4
  short-form: Use when shaping a planning roadmap, deciding plan structure, or preparing a consequential plan for implementation.
5
- system-prompt-visibility: preview
6
- file-read-visibility: none
7
5
  gate: {kind: plan}
8
6
  rationale: >-
9
7
  The original playbook required five parallel plan reviewers before every consequential implementation and made “passes all five lenses” the ready bar. Combined with the plan persona's re-review loop, this turned lenses into agents and resolution into reviewer polling rather than plan-owner judgment.
8
+ surfaces:
9
+ - on: boot
10
+ at: preview
10
11
  ---
11
12
 
12
13
  # Planning Playbook
@@ -2,8 +2,6 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When eliciting or writing a specification, this knowledge should be read because downstream design and planning need settled intent without making the user answer avoidable questions or forcing every request through the same ceremony.
4
4
  short-form: Elicit only consequential uncertainty, then write a right-sized behavioral contract a downstream reader can use without guessing.
5
- system-prompt-visibility: none
6
- file-read-visibility: none
7
5
  rationale: Specification quality and elicitation guidance lived inside an always-loaded spec persona while the lightweight /spec command had almost none, leaving agents to choose between a vague one-shot and a fixed discovery workflow.
8
6
  ---
9
7
 
@@ -2,8 +2,6 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When writing or evaluating requirements, this knowledge should be read because implementation and validation need one complete behavioral contract rather than behavior scattered across design prose or silently filled in by the planner.
4
4
  short-form: Write complete, atomic, observable, testable requirements; use formal templates only when they make a conditional behavior clearer.
5
- system-prompt-visibility: none
6
- file-read-visibility: none
7
5
  rationale: The requirements persona made EARS mandatory and omitted behavior already stated by the design, which could produce a gap list instead of the complete behavioral contract downstream work needs.
8
6
  ---
9
7
 
@@ -2,10 +2,11 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When a specification effort contains independent discovery, design, or requirements surfaces large enough for worthwhile parallel work, this knowledge should be read because the handoffs must preserve one settled contract without turning sequential reasoning into coordination ceremony.
4
4
  short-form: Orchestrate a specification only for worthwhile parallel work, using canonical artifacts rather than conversation context for handoffs.
5
- system-prompt-visibility: preview
6
- file-read-visibility: none
7
5
  gate: {kind: spec}
8
6
  rationale: The prior roadmap required every large specification to follow exact stages, fresh-window yields, fixed delegation, and user approval gates; the resulting process treated ceremony as the quality bar instead of the clarity of the finished contract.
7
+ surfaces:
8
+ - on: boot
9
+ at: preview
9
10
  ---
10
11
 
11
12
  # Orchestrating a specification
@@ -2,8 +2,6 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When a repo has no recorded testing stance and you must decide whether a change carries a test, this knowledge should be read because eliciting the standard once and storing it settles every later change in that repo instead of each agent guessing differently and leaving the owner to strip out unwanted coverage.
4
4
  short-form: How to produce a repo's testing-stance memory — read what the repo already shows, draft a stance from that evidence, get the owner to confirm it, and store it.
5
- system-prompt-visibility: none
6
- file-read-visibility: none
7
5
  rationale: >-
8
6
  Agents defaulted to a coverage-first instinct in repos that had deliberately chosen otherwise, and to the opposite absolute in repos that wanted coverage — each inventing a stance rather than taking the repo's. The missing move was procedural, not a rule: read the standard the repo already shows, and when it shows none, ask once and store the answer where the next agent inherits it.
9
7
  ---
@@ -38,4 +36,4 @@ Put the draft to the owner through `crtr human send`, as one question answerable
38
36
 
39
37
  Save the confirmed stance as a `testing-stance` preference in that repo's own project store (`crtr memory write -h`), so every agent working there inherits it and no one repeats this workflow. Keep it to what earns a test, what proves a change instead, and the local-versus-CI split with any per-test bound — the decision, never the conversation that produced it.
40
38
 
41
- A one-or-two-sentence stance belongs at the `content` rung on the boot axis, because the decision it governs — should this change carry a test — happens before any test file is opened. Route it through file context instead only for conventions that matter while editing a test, matched to the repo's own test globs.
39
+ A one-or-two-sentence stance belongs in a `{on: boot, at: content}` entry, because the decision it governs — should this change carry a test — happens before any test file is opened. Route it through a read entry instead only for conventions that matter while editing a test, matched to the repo's own test globs.
@@ -2,8 +2,9 @@
2
2
  kind: knowledge
3
3
  when-and-why-to-read: When a node is marked wedged or remains active without progress while its inbox accumulates, this reference should be read so recovery restores progress without losing context or killing the wrong process.
4
4
  short-form: A node stuck mid-turn is detected from a stale busy heartbeat plus near-zero process-tree CPU. Kill a runaway subprocess when one exists; when the broker itself is stuck, the daemon SIGTERMs it and applies bounded, conditional recovery.
5
- system-prompt-visibility: preview
6
- file-read-visibility: none
5
+ surfaces:
6
+ - on: boot
7
+ at: preview
7
8
  ---
8
9
 
9
10
  A base node can wedge mid-turn on a runaway bash command (for example, an unbounded recursive scan from `/`). Its pi turn cannot push or finish while the tool call is blocked.
@@ -36,7 +36,7 @@ directory's `node_modules/`.
36
36
  | `provider-rotation.ts` | Subscription credential rotation across Anthropic / OpenAI-Codex: does its own OAuth login/refresh, rotates on rate-limits, falls back across the model ladder. Registers `/provider-sub <provider> <list\|add\|select\|rm>`. |
37
37
  | `crtr-commands/` | Auto-generates a slash command per `crtr` CLI node. The tree is derived in-process from crtr's own `buildRoot()` (no subprocesses, no cache on disk); `filters.json` controls which nodes are exposed. |
38
38
  | `sysprompt-window.ts` | Registers `/sysprompt`, which runs `crtr sys sysprompt --window` without injecting the prompt into context. |
39
- | `frontmatter-rules/` | Injects `.pi/rules/*.md` whose `when:` frontmatter matches a read markdown file. `.claude/rules` are migrated into substrate docs with `applies-to` via `crtr sys sync project-guidance`. Needs the `yaml` dep. See the `pi-frontmatter-rules` skill. |
39
+ | `frontmatter-rules/` | Injects `.pi/rules/*.md` whose `when:` frontmatter matches a read markdown file. `.claude/rules` are migrated into substrate docs with read-glob `surfaces` entries via `crtr sys sync project-guidance`. Needs the `yaml` dep. See the `pi-frontmatter-rules` skill. |
40
40
  | `statusline.ts` | Custom status line. |
41
41
  | `strip-skills-docs.ts` | Trims skill docs from context. |
42
42
 
@@ -5,9 +5,9 @@
5
5
  * whose YAML frontmatter satisfies a rule's `when:` condition. This is the
6
6
  * inverse of a PATH-glob rule (matched on the document's location, not its
7
7
  * content): here the *content* of the read document (its frontmatter) decides
8
- * which rules apply, not the document's path. Path-glob rules now live as
9
- * substrate docs with `applies-to` (see `crtr sys sync project-guidance`'s
10
- * `.claude/rules` migration), not as a sibling pi-extension.
8
+ * which rules apply, not the document's path. Path-glob rules live as
9
+ * substrate docs with read-glob `surfaces` entries (see `crtr sys sync
10
+ * project-guidance`'s `.claude/rules` migration), not as a sibling pi-extension.
11
11
  *
12
12
  * Rule files live in `.pi/rules/*.md` (walked up the read file's ancestor
13
13
  * chain, so a project-root rules dir governs everything beneath it) plus a
@@ -29,7 +29,6 @@ interface MemoryListItem {
29
29
  name: string;
30
30
  path: string;
31
31
  short_form: string;
32
- is_dir: boolean;
33
32
  slash: boolean;
34
33
  }
35
34
 
@@ -55,7 +54,6 @@ async function defaultListMemoryDocs(): Promise<MemoryListItem[]> {
55
54
  name: doc.name,
56
55
  path: doc.path,
57
56
  short_form: doc.shortForm,
58
- is_dir: doc.isDir,
59
57
  slash: doc.slash,
60
58
  }));
61
59
 
@@ -64,7 +62,7 @@ async function defaultListMemoryDocs(): Promise<MemoryListItem[]> {
64
62
  // precedence). Resolve all eligible names against one source snapshot.
65
63
  const seen = new Set<string>();
66
64
  const names = items.flatMap((item) => {
67
- if (item.is_dir || seen.has(item.name)) return [];
65
+ if (seen.has(item.name)) return [];
68
66
  seen.add(item.name);
69
67
  return item.slash === true ? [item.name] : [];
70
68
  });
@@ -98,7 +96,6 @@ export async function discoverSlashDocs(): Promise<SlashDoc[]> {
98
96
  const seen = new Set<string>();
99
97
  const out: SlashDoc[] = [];
100
98
  for (const item of items) {
101
- if (item.is_dir) continue;
102
99
  if (seen.has(item.name)) continue;
103
100
  seen.add(item.name);
104
101
  if (item.slash) {