@north-light/crouter 0.3.174 → 0.3.175

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.
@@ -9,23 +9,24 @@ import { MEMORY_KINDS, MEMORY_SCOPES, VISIBILITY_RUNGS, resolveWriteTarget, memo
9
9
  export const writeLeaf = defineLeaf({
10
10
  name: 'write',
11
11
  description: 'create or update a memory document',
12
- whenToUse: 'you are recording a new knowledge document or preference — or revising one that already exists. Writes memory/<name>.md at the resolved scope from the frontmatter flags plus a body piped on stdin. Identity is path-derived: if <name> already exists at the scope it is updated in place, otherwise it is created.',
12
+ whenToUse: 'you are recording a new knowledge document or preference, or revising one that already exists — an existing <name> at the resolved scope is updated in place, so revision is also this leaf.',
13
13
  help: {
14
14
  name: 'memory write',
15
15
  summary: 'create or update memory/<name>.md at the resolved scope from frontmatter flags + a stdin body',
16
- guide: 'The body is the easy part; the craft is routing — every frontmatter flag decides who sees this doc, when, and at what context cost. Each rung up is paid by every future agent at every boot or read, forever, so default each rung down.\n\n' +
16
+ guide: 'Every frontmatter flag decides who sees this doc, when, and at what context cost. Each rung up is paid by every future agent at every boot or read, so default each rung down.\n\n' +
17
17
  'Pick the kind. knowledge is consulted for facts or procedures; preference directs behavior. The kind choice is about how the doc is used, not about how long it is.\n\n' +
18
- 'Store reusable current truth, not session notes. Useful memories are non-obvious procedures, gotchas, durable preferences, cross-repo conventions, and amendments to plans/specs that future agents must honor. Put plan/spec amendments under path names like `projects/<topic>/...`; add `projects/<topic>/INDEX.md` with `name` visibility so the topic is discoverable without loading the whole body. Do not store chat summaries, implementation history, or facts already recorded in the repo.\n\n' +
19
- 'Set both visibility rungs explicitly on create. There is no kind default. `none`, `name`, `preview`, and `content` move from least to most loaded: `none` keeps the doc out of auto-load and on-read surfaces, `name` is the bare doc tag only, `preview` is the name + envelope + routing line (`when-and-why-to-read`), and `content` inlines the whole body when the body is short enough to justify it. Each axis is independent; usually one carries a real rung and the other is `none`. When a doc is short enough to state in a single sentence — a one-line preference, or a knowledge fact that fits in a sentence — skip `preview` and use `name` or `content` directly: the routing line would run longer than the doc itself, so a `preview` rung just adds words. Sentence-length `content` docs are not just acceptable, they are correct. Never pad a memory to be more verbose than the rule or fact it carries.\n\n' +
20
- 'Choose the scope. `project` is for facts any agent in one repo needs. `user` is for person-wide facts and preferences that should follow the user everywhere. `profile` is for the profile’s bundle of dirs: cross-repo conventions, how the pieces relate, or the user’s stance toward that body of work. `node` is the narrowest — the this-node store (`nodes/<CRTR_NODE_ID>/context/memory/`), scratch memory only this running node sees; it rides straight into this node’s knowledge block and dies with the node. When unsure, choose the narrowest scope that will still reach the next agent who needs it.\n\n' +
21
- 'A project root INDEX is the workspace front door. Name the physical doc INDEX, target the exact project with --dir, and use kind knowledge, system-prompt-visibility none, file-read-visibility content, and applies-to ".". The `.` route surfaces the full operating guide in first-message context whenever cwd or a selected profile mounts that project store; its envelope name comes from the owning project directory unless the document already carries an explicit name. It is a front door, not a manual — keep only the project constraints, key commands, architecture orientation, and conventions that differ from defaults. `crtr memory lint` validates this exact contract for every project managed by the selected profile.\n\n' +
22
- 'Choose the hook — boot vs file context. System-prompt visibility is the boot catalog. Every non-none file-read rung also requires at least one explicit applies-to route: `.` means project workspace/profile mount and is evaluated during first-message assembly; every other value is a glob evaluated only after a matching file is actually read. There is no positional fallback from where the memory file lives. Put code-specific knowledge in the owning project store, give it the narrowest real file glob, and keep it out of boot when the file read is the useful trigger. Knowledge about a person or process usually has no file boundary, so set file-read-visibility none and route it through boot instead.\n\n' +
23
- 'Write the routing line (--when-and-why-to-read) first, before storing anything: "When <circumstance>, this <kind> should be read because <broader downstream payoff>." WHY is the READER’s payoff — the consequence they secure for the task in front of them by spending the read — never what the document says, its rule, or why it should be obeyed. The trap most authors fall into is the DISGUISED restatement: a because-clause that reads like a benefit but is just the doc’s own thesis reworded as an outcome. It still fails. The test: if you could derive the because-clause by paraphrasing the doc’s advice, it is a restatement, not a payoff — a real payoff names a consequence in the reader’s world that the document itself never asserts. Bad (naked restatement): "because only genuine first principles belong in taste memory." Bad (restatement in benefit’s clothing): "because keeping the test loop fast and free of speculative tests protects the development pace" — that is the doc’s rule in outcome costume, derivable straight from its advice. Good: "because identifying throughlines in user taste lets future decisions be made faster and with less re-litigation." The stranger test: someone mid-task who has NOT read the doc must be able to decide from this one line alone whether the read is worth it. If you cannot name the concrete situation that triggers it, you do not yet understand the memory — ask the user one sharp question instead of improvising.\n\n' +
18
+ 'Store reusable current truth, not session notes. Useful memories are non-obvious procedures, gotchas, durable preferences, and cross-repo conventions. Do not store chat summaries, implementation history, or facts already recorded in the repo.\n\n' +
19
+ 'The visibility rungs `none`, `name`, `preview`, and `content` move from least to most loaded: `none` keeps the doc out of auto-load and on-read surfaces, `name` is the bare doc tag only, `preview` is the name + envelope + routing line (`when-and-why-to-read`), and `content` inlines the whole body when the body is short enough to justify it. Each axis is independent; usually one carries a real rung and the other is `none`. When a doc fits in a single sentence — a one-line preference or a one-sentence knowledge fact — skip `preview` and use `name` or `content` directly: the routing line would run longer than the doc itself. Sentence-length `content` docs are correct; never pad a memory to be more verbose than the rule or fact it carries.\n\n' +
20
+ 'Choose the scope. `project` is for facts any agent in one repo needs. `user` is for person-wide facts and preferences that should follow the user everywhere. `profile` is for the profile’s bundle of dirs: cross-repo conventions, how the pieces relate, or the user’s stance toward that body of work. `node` is scratch memory only this running node sees; it rides into this node’s knowledge block and dies with the node. When unsure, choose the narrowest scope that will still reach the next agent who needs it.\n\n' +
21
+ 'A project root INDEX is the workspace front door. Name the physical doc INDEX, target the exact project with --dir, and use kind knowledge, system-prompt-visibility none, file-read-visibility content, and applies-to ".". Its envelope name comes from the owning project directory unless the document already carries an explicit name. Keep only the project constraints, key commands, architecture orientation, and conventions that differ from defaults. `crtr memory lint` validates this exact contract for every project managed by the selected profile.\n\n' +
22
+ 'Choose the hook — boot vs file context. System-prompt visibility is the boot catalog; file-read visibility fires on the applies-to routes. Put code-specific knowledge in the owning project store, give it the narrowest real file glob, and keep it out of boot when the file read is the useful trigger. Knowledge about a person or process usually has no file boundary, so set file-read-visibility none and route it through boot instead.\n\n' +
23
+ 'Write the routing line (--when-and-why-to-read) first, before storing anything. The test for its because-clause: if it can be derived by paraphrasing the doc’s advice, it is a restatement, not a payoff — a real payoff names a consequence in the reader’s world that the document itself never asserts. Bad: "because only genuine first principles belong in taste memory." Bad: "because keeping the test loop fast and free of speculative tests protects the development pace" — the doc’s rule as an outcome, derivable straight from its advice. Good: "because identifying throughlines in user taste lets future decisions be made faster and with less re-litigation." Someone mid-task who has not read the doc must be able to decide from this line alone whether the read is worth it. If you cannot name the concrete situation that triggers it, you do not yet understand the memory — ask the user one sharp question instead of improvising.\n\n' +
24
24
  'Gate and read-when share the same predicate language: a field map is AND-ed across fields; dotted fields resolve nested values; field matchers may be scalar, array, or object. Scalar matchers do exact equality, with arrays matching any element. Array matchers do membership or intersection. Object matchers accept `eq`, `ne`, `in`, `nin`, `exists`, `contains`, `containsAll`, `containsAny`, `matches`, `imatches`, `gt`, `gte`, `lt`, and `lte`. Combinators are `all`, `any`, and `not`; sibling field matchers next to them are AND-ed in. An empty condition is inert. An unknown op never matches.\n\n' +
25
25
  'Link related docs with `[[canonical/name]]`. A doc link in any body is a first-class cross-reference to another memory document by its exact canonical name — the same identifier `crtr memory read` takes (a directory INDEX is linked by its bare directory name). Links are pointers, never transclusion: the linked body is loaded only when a reader follows it, so a link costs nothing until needed. `crtr memory lint` fails on a link that resolves to no document, and `crtr memory read` lists a doc’s resolvable links alongside its body. There is no alias or label form.\n\n' +
26
- 'When a doc grows long or information-rich, nest it into a graph instead of letting it become a scroll. The main doc at the topic’s path keeps the high-level, most load-bearing information, most important first; depth splits into reference docs under the topic’s directory (`area/topic/...`), each pointed at with a `[[link]]`. Split by subject: a leaf earns its link by covering a different subject a task might need on its own; a leaf of offloaded “further evidence”, examples, or references is never followed, so supporting material either sits in the main doc next to the point it supports or gets cut. The main doc is the entry point a reader can act from alone; a reference leaf is loaded only when the task needs that depth. Save reference leaves at `none` visibility on both axes — the link from the main doc is how they are found, so any higher rung just double-charges every boot or read for depth the graph already routes. This is the same layering the visibility rungs apply to boot cost, applied to the body itself. Keep every doc as short as its job allows; `crtr memory lint` caps body length by rung and its findings carry the split guidance.\n\n' +
27
- 'Find before write. Prefer slightly expanding an existing document, nesting genuinely separate depth under its topic, and updating the existing `when-and-why-to-read` (plus its INDEX router when present) over creating another similar memory. A new document earns its own identity only when it has a distinct read trigger and a coherent body that would make the existing document harder to route or use. Group related docs with path names (area/topic). Do not store what is already recorded or what only matters to this conversation. Body is for current truth, not history. Provenance is automatic on create and preserved on update. Run `crtr memory lint` — the frontmatter validator — after authoring.\n\n' +
28
- '--rationale is the gap this doc exists to close — the observed agent failure that prompted it, captured from user signal (a correction, a mistake you watched happen) rather than inferred from the doc’s own content. The bar: if the rationale is guessable from reading the doc, it is not the real one — a guessable gap is one agents do not actually fall into, so a merely-plausible-sounding reason is not worth recording. It is maintainer-facing only and NEVER ships in a delivered surface (boot render, on-read injection, `memory read` content) — it lives in frontmatter, visible only via `memory read --frontmatter`. Omit it when you have no such gap to record; omitting the flag on an update always preserves whatever rationale already exists.',
26
+ 'When a doc grows long or information-rich, nest it into a graph instead of letting it become a scroll. The main doc at the topic’s path keeps the high-level, most load-bearing information, most important first; depth splits into reference docs under the topic’s directory (`area/topic/...`), each pointed at with a `[[link]]`. Split by subject: a leaf earns its link by covering a different subject a task might need on its own; a leaf of offloaded “further evidence”, examples, or references is never followed, so supporting material either sits in the main doc next to the point it supports or gets cut. The main doc is the entry point a reader can act from alone; a reference leaf is loaded only when the task needs that depth. Save reference leaves at `none` visibility on both axes — the link from the main doc is how they are found, so any higher rung just double-charges every boot or read for depth the graph already routes. Keep every doc as short as its job allows; `crtr memory lint` caps body length by rung and its findings carry the split guidance.\n\n' +
27
+ 'A directory INDEX earns existence only where the aggregate view beats the sum of per-file rungs. Two shapes pass: synthesis — an operating guide or the cluster’s mechanics, ordering, and relationships, content no single child can carry — and aggregated routing — one preview line covering a large cluster with one shared routing condition, children dropped to `name` or `none`. Otherwise skip the INDEX and let each doc’s own rung route it: frontmatter routing lines are self-maintaining, while an INDEX body describing its children is a hand-maintained copy that drifts. Never write an INDEX that restates child names, paraphrases their routing lines, fronts a small directory of sharply named docs, or summarizes children a reader should open.\n\n' +
28
+ 'Find before write. Prefer slightly expanding an existing document, nesting genuinely separate depth under its topic, and updating the existing `when-and-why-to-read` (plus its INDEX router when present) over creating another similar memory. A new document earns its own identity only when it has a distinct read trigger and a coherent body whose merge into the existing document would make it harder to route or use. Group related docs with path names (area/topic). Provenance is automatic on create and preserved on update. Run `crtr memory lint` after authoring.\n\n' +
29
+ '--rationale is the gap this doc exists to close — the observed agent failure that prompted it, captured from user signal (a correction, a mistake you watched happen) rather than inferred from the doc’s own content. If the rationale is guessable from reading the doc, it is not the real one — a guessable gap is one agents do not actually fall into. Omit the flag when you have no observed gap to record.',
29
30
  params: [
30
31
  { kind: 'positional', name: 'name', required: true, constraint: 'Path-derived identity: one segment, or several joined with `/` to nest the document under a directory and group it with related docs → memory/<name>.md at the resolved scope. Updated in place if it already exists, otherwise created.' },
31
32
  { kind: 'flag', name: 'kind', type: 'enum', choices: [...MEMORY_KINDS], required: true, constraint: 'Document kind.' },
@@ -34,7 +35,7 @@ export const writeLeaf = defineLeaf({
34
35
  { kind: 'flag', name: 'system-prompt-visibility', type: 'enum', choices: [...VISIBILITY_RUNGS], required: false, constraint: 'Rung controlling how much of this document auto-loads into the system prompt / CLI help. Required when creating — there is no kind default; pick a rung explicitly.' },
35
36
  { kind: 'flag', name: 'file-read-visibility', type: 'enum', choices: [...VISIBILITY_RUNGS], required: false, constraint: 'Rung controlling how much surfaces through file context. Required when creating — there is no kind default. Every value except none also requires at least one applies-to route in the resulting document.' },
36
37
  { kind: 'flag', name: 'gate', type: 'string', required: false, constraint: 'Frontmatter gate — YAML/JSON object predicate over node config using the same field/matcher vocabulary described in the guide.' },
37
- { kind: 'flag', name: 'applies-to', type: 'string', required: false, repeatable: true, constraint: 'One explicit file-context route per occurrence. In a project store, `.` fires when cwd/profile mounts that workspace during first-message assembly. Any other value is a glob matched after an actual file read against the absolute path, basename, and path relative to the owning project root. Required whenever file-read-visibility is not none.' },
38
+ { kind: 'flag', name: 'applies-to', type: 'string', required: false, repeatable: true, constraint: 'One explicit file-context route per occurrence. In a project store, `.` fires when cwd/profile mounts that workspace during first-message assembly. Any other value is a glob matched after an actual file read against the absolute path, basename, and path relative to the owning project root. There is no positional fallback from where the memory file lives. Required whenever file-read-visibility is not none.' },
38
39
  { kind: 'flag', name: 'read-when', type: 'string', required: false, constraint: 'Frontmatter read-when — YAML/JSON object predicate over a read file’s own frontmatter using the same field/matcher vocabulary described in the guide.' },
39
40
  { kind: 'flag', name: 'slash', type: 'bool', required: false, default: false, constraint: 'Presence flags this doc invocable as a pi slash command (`/<name>`, `/` in a nested name rendered as `:`) — the doc body becomes the command’s injected prompt. Default false: most docs are consulted, not invoked.' },
40
41
  { kind: 'flag', name: 'rationale', type: 'string', required: false, constraint: 'Frontmatter rationale — the observed agent failure that made this doc necessary. Maintainer-facing only: never ships in any delivered surface (boot render, on-read injection, `memory read` content), visible only via `memory read --frontmatter`. Omitting this flag on an update PRESERVES an existing rationale unchanged.' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.174",
3
+ "version": "0.3.175",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.174",
3
+ "version": "0.3.175",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.174",
9
+ "version": "0.3.175",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {