ctxr-cli 0.20.1 → 0.22.0

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 (100) hide show
  1. package/README.md +55 -8
  2. package/dist/adapters/builtin/index.d.ts.map +1 -1
  3. package/dist/adapters/builtin/index.js +8 -1
  4. package/dist/adapters/builtin/index.js.map +1 -1
  5. package/dist/adapters/harness/antigravity.d.ts +18 -0
  6. package/dist/adapters/harness/antigravity.d.ts.map +1 -0
  7. package/dist/adapters/harness/antigravity.js +24 -0
  8. package/dist/adapters/harness/antigravity.js.map +1 -0
  9. package/dist/adapters/harness/codex.d.ts +22 -0
  10. package/dist/adapters/harness/codex.d.ts.map +1 -0
  11. package/dist/adapters/harness/codex.js +28 -0
  12. package/dist/adapters/harness/codex.js.map +1 -0
  13. package/dist/adapters/types.d.ts +9 -0
  14. package/dist/adapters/types.d.ts.map +1 -1
  15. package/dist/commands/archive.d.ts +4 -3
  16. package/dist/commands/archive.d.ts.map +1 -1
  17. package/dist/commands/archive.js +28 -23
  18. package/dist/commands/archive.js.map +1 -1
  19. package/dist/commands/ingest.d.ts.map +1 -1
  20. package/dist/commands/ingest.js +22 -1
  21. package/dist/commands/ingest.js.map +1 -1
  22. package/dist/commands/init.d.ts +2 -0
  23. package/dist/commands/init.d.ts.map +1 -1
  24. package/dist/commands/init.js +20 -3
  25. package/dist/commands/init.js.map +1 -1
  26. package/dist/commands/publish-urls.d.ts +32 -0
  27. package/dist/commands/publish-urls.d.ts.map +1 -0
  28. package/dist/commands/publish-urls.js +125 -0
  29. package/dist/commands/publish-urls.js.map +1 -0
  30. package/dist/config/defaults.d.ts +26 -0
  31. package/dist/config/defaults.d.ts.map +1 -1
  32. package/dist/config/defaults.js +25 -1
  33. package/dist/config/defaults.js.map +1 -1
  34. package/dist/config/schema.d.ts +19 -0
  35. package/dist/config/schema.d.ts.map +1 -1
  36. package/dist/config/schema.js +31 -0
  37. package/dist/config/schema.js.map +1 -1
  38. package/dist/core/agents-doc.d.ts +26 -0
  39. package/dist/core/agents-doc.d.ts.map +1 -1
  40. package/dist/core/agents-doc.js +94 -40
  41. package/dist/core/agents-doc.js.map +1 -1
  42. package/dist/core/checks/harness-portability-checks.d.ts +32 -0
  43. package/dist/core/checks/harness-portability-checks.d.ts.map +1 -1
  44. package/dist/core/checks/harness-portability-checks.js +177 -2
  45. package/dist/core/checks/harness-portability-checks.js.map +1 -1
  46. package/dist/core/checks/integrity-checks.d.ts.map +1 -1
  47. package/dist/core/checks/integrity-checks.js +34 -14
  48. package/dist/core/checks/integrity-checks.js.map +1 -1
  49. package/dist/core/checks/organize-checks.d.ts +5 -0
  50. package/dist/core/checks/organize-checks.d.ts.map +1 -1
  51. package/dist/core/checks/organize-checks.js +57 -4
  52. package/dist/core/checks/organize-checks.js.map +1 -1
  53. package/dist/core/convention-doc.d.ts.map +1 -1
  54. package/dist/core/convention-doc.js +5 -2
  55. package/dist/core/convention-doc.js.map +1 -1
  56. package/dist/core/conventions.d.ts +7 -0
  57. package/dist/core/conventions.d.ts.map +1 -1
  58. package/dist/core/conventions.js +3 -0
  59. package/dist/core/conventions.js.map +1 -1
  60. package/dist/core/errors.d.ts +22 -0
  61. package/dist/core/errors.d.ts.map +1 -1
  62. package/dist/core/errors.js +52 -0
  63. package/dist/core/errors.js.map +1 -1
  64. package/dist/core/ingest/required-sections.d.ts +3 -3
  65. package/dist/core/ingest/required-sections.d.ts.map +1 -1
  66. package/dist/core/ingest/required-sections.js +79 -16
  67. package/dist/core/ingest/required-sections.js.map +1 -1
  68. package/dist/core/notes/list.d.ts.map +1 -1
  69. package/dist/core/notes/list.js +3 -0
  70. package/dist/core/notes/list.js.map +1 -1
  71. package/dist/core/reconcile.d.ts.map +1 -1
  72. package/dist/core/reconcile.js +2 -1
  73. package/dist/core/reconcile.js.map +1 -1
  74. package/dist/core/skills.d.ts.map +1 -1
  75. package/dist/core/skills.js +28 -4
  76. package/dist/core/skills.js.map +1 -1
  77. package/dist/run.d.ts.map +1 -1
  78. package/dist/run.js +15 -2
  79. package/dist/run.js.map +1 -1
  80. package/dist/version.d.ts +1 -1
  81. package/dist/version.js +1 -1
  82. package/package.json +3 -3
  83. package/templates/agents/canonical.md +3 -8
  84. package/templates/agents/capture-and-ingest.md +1 -36
  85. package/templates/agents/conventions.md +3 -1
  86. package/templates/agents/guidance-index.md +5 -0
  87. package/templates/agents/mission.md +2 -0
  88. package/templates/agents/retrieval-leg-routing.md +7 -42
  89. package/templates/conventions/baseline-conventions.md +20 -9
  90. package/templates/conventions/house-conventions-seed.md +10 -0
  91. package/templates/skills/ctxr-capture.md +35 -4
  92. package/templates/skills/ctxr-derived-artifacts.md +6 -0
  93. package/templates/skills/ctxr-ingest-orchestration.md +5 -1
  94. package/templates/skills/ctxr-mission.md +40 -31
  95. package/templates/skills/ctxr-organize-audit.md +30 -6
  96. package/templates/skills/ctxr-placement.md +5 -0
  97. package/templates/skills/ctxr-publish.md +2 -1
  98. package/templates/skills/ctxr-research.md +108 -0
  99. package/templates/skills/ctxr-second-opinion.md +5 -0
  100. package/templates/skills/ctxr-submit.md +28 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctxr-cli",
3
- "version": "0.20.1",
3
+ "version": "0.22.0",
4
4
  "description": "Context store for AI coding agents — markdown and git, catalog and graph retrieval, no vector database.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -52,9 +52,9 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/markdown-it": "^14.2.0",
55
- "@types/node": "^22.20.1",
55
+ "@types/node": "^26.6.4",
56
56
  "typescript": "^7.0.2",
57
- "vitest": "^4.1.11"
57
+ "vitest": "^5.0.1"
58
58
  },
59
59
  "keywords": [
60
60
  "contexture",
@@ -2,9 +2,7 @@
2
2
 
3
3
  ### Root resolution
4
4
 
5
- Every contexture command resolves the store root in this order: an explicit `--root <path>` flag; the store found by walking up from the current directory when it is a linked git worktree of the store named by `CONTEXTURE_STORE_ROOT`; the `CONTEXTURE_STORE_ROOT` environment variable; walking up from the current directory looking for `__CONFIG_FILE_NAME__`. No other flag or environment variable selects the root.
6
-
7
- The worktree step is why a command run inside a session worktree operates on that worktree rather than on the canonical clone, even with `CONTEXTURE_STORE_ROOT` exported: the variable names which *store*, and a worktree raises which *checkout* of it. Standing in a different store still resolves the variable, unchanged. To target the canonical clone from inside a worktree, name it: `--root "$CONTEXTURE_STORE_ROOT"`.
5
+ Every contexture command resolves the store root in this order: an explicit `--root <path>` flag; the store found by walking up from the current directory when it is a linked git worktree of the store named by `CONTEXTURE_STORE_ROOT`; the `CONTEXTURE_STORE_ROOT` environment variable; walking up from the current directory looking for `__CONFIG_FILE_NAME__`. No other flag or environment variable selects the root. Inside a session worktree, commands therefore act on that worktree; to target the canonical clone from there, pass `--root "$CONTEXTURE_STORE_ROOT"`.
8
6
 
9
7
  ### Frontmatter schema
10
8
 
@@ -12,15 +10,12 @@ The worktree step is why a command run inside a session worktree operates on tha
12
10
 
13
11
  ### Note templates
14
12
 
15
- A new note starts from a template under `__TEMPLATES_PATH__`, not from a blank file and not by copying whatever sibling happens to be nearby. Substitute `{{title}}` and `{{date}}` as you write it — no command expands them, and a note that lands with one still in it is reported by `ctxr lint`. A template is never a note: nothing under that path is catalogued, graphed, or retrieved. Add your own kinds there alongside the shipped ones; contexture only ever rewrites the ones it delivered.
16
-
17
- Every shipped template except the base, `Note`, stamps the kind it is for into the note's `tags`. Keep it when you start a note: it is how you find every note of a kind, with your own search, since no `ctxr` command filters by it. A kind you cut from the base should stamp its own name the same way, and any further tags are this store's own.
13
+ Start a new note from a template under `__TEMPLATES_PATH__`, never a blank file or a copied sibling, and substitute `{{title}}` and `{{date}}` yourself — `ctxr lint` reports one left in. Keep the kind the template stamps into `tags`: it is how your own search finds every note of a kind, since no `ctxr` command filters by it.
18
14
 
19
15
  ### Write path
20
16
 
21
- Every write to this store happens inside a session worktree, never directly on the default branch: `ctxr session start` creates one, and the work stays there for as long as the session runs. When the operator asks to wrap up, `ctxr-submit` validates with `ctxr doctor`, commits, pushes, and opens (or reports how to open) a pull request — that request is what triggers it, not having finished a piece of work. Do not edit files in the store root directly.
17
+ Every write happens inside a session worktree (`ctxr session start`), never on the default branch, and lands through a reviewed pull request that `ctxr-submit` opens when the operator asks to wrap up. Do not edit files in the store root directly.
22
18
 
23
19
  ### Identity and recall
24
20
 
25
21
  Identity, persona, and the agent's conversational recall — what it remembers of the user and of itself from one session to the next — belong to its harness, not to this store. Subject-matter knowledge belongs here, including anything worth finding again in a later session: the store holds knowledge and skills, documented as portable markdown under `__SKILLS_PATH__`, and never a persona or recall file of its own.
26
- __MISSION_POINTER__
@@ -1,38 +1,3 @@
1
1
  ## Capturing and ingesting new material
2
2
 
3
- Captures live under `__CAPTURE_ROOT__`, which is excluded from retrieval: nothing in it is a note, and
4
- nothing in it is returned by a search, listed in the catalog, or drawn in the graph. It is tracked in git
5
- all the same — a capture is the provenance behind a note, not scratch space.
6
-
7
- To capture something new, write the material into `__INBOX_PATH__` — no CLI command wraps this, but
8
- `ctxr-capture` carries the procedure: what counts as the record rather than a summary of it, how to
9
- identify it, and where capture stops. The material may already carry these two fields, since whatever
10
- fetched it usually knows them:
11
-
12
- - `source_type`
13
- - `source_id`
14
-
15
- It MUST NOT carry either of these; contexture assigns them once, at ingest, and never before:
16
-
17
- - `source_hash`
18
- - `ingested`
19
-
20
- Before ingesting, run `ctxr source check <path> --source-id <id>` to get one of five verdicts: `new`,
21
- `already_ingested`, `drift` (same identity, the source's content moved), `alternate_source_match`, or
22
- `multiple_matches` — the last one means stop and resolve the ambiguity yourself rather than guessing which
23
- existing record it is.
24
-
25
- Then write, or extend, the note this material informed. Ingest does not create it: deciding what the store
26
- should know is the work, and "a new note" is only one of the answers.
27
-
28
- ```
29
- ctxr ingest <path> --into <note> --source-type <type> --source-id <id>
30
- ```
31
-
32
- That stamps the four fields onto the capture, moves it out of the inbox into `__CAPTURE_ROOT__` under the
33
- month it was ingested, and records its path in the note's `sources` list. The note itself carries no source
34
- identity — it is free to be rewritten, merged, or restructured without ever invalidating the frozen hash.
35
- A note may cite as many captures as it was built from.
36
-
37
- Material that is not markdown cannot carry frontmatter, so it travels with a markdown sidecar beside it
38
- naming the file in `capture_file`. The hash is taken over that file's bytes, and the two move together.
3
+ Capture new material as a file in `__INBOX_PATH__`. Everything under `__CAPTURE_ROOT__` is tracked in git as provenance but excluded from retrieval — nothing there is a note. A capture may carry `source_type` and `source_id`; it must never carry `source_hash` or `ingested`, which `ctxr ingest` assigns once. `ctxr-capture` carries the capture procedure and `ctxr-ingest-orchestration` the dedupe check and the ingest; the note a capture informs carries no source identity of its own.
@@ -1,5 +1,7 @@
1
1
  ## Store conventions
2
2
 
3
+ The rules that hold on every turn: contexture's baseline, then this store's own. Operator conventions are markdown files under `__GUIDANCE_PATH__`; each is inlined here unless its frontmatter declares `read_when`, in which case it is listed under "Read when" instead.
4
+
3
5
  __CONVENTION_BODY__
4
6
 
5
- A note that applies to only one agent harness (not every harness reading this store) belongs below that harness's own managed import in its own entry file, never here — every file in this directory is inlined into every harness's entry document equally.
7
+ A note for only one agent harness belongs in that harness's own entry file, below its managed import — never here.
@@ -0,0 +1,5 @@
1
+ ## Read when
2
+
3
+ This store's other guidance loads on demand. When a row's trigger matches what you are about to do, read that document first:
4
+
5
+ __GUIDANCE_ROWS__
@@ -1,5 +1,7 @@
1
1
  ## Mission
2
2
 
3
+ __MISSION_CONFIRMED__
4
+
3
5
  __MISSION_BODY__
4
6
 
5
7
  _Source: __MISSION_PATH___
@@ -1,46 +1,11 @@
1
- ## Retrieval: one pass, three steps
1
+ ## Retrieval
2
2
 
3
- Retrieval is a single pass — **enter**, **expand**, **widen** — not three tools to choose between.
4
- contexture builds and maintains the first two ahead of time; the third is yours.
3
+ Find before you write. contexture builds and maintains the catalog and the wikilink graph; consult them before your own search.
5
4
 
6
- **1. Enter.** Name where to start, positionally or relationally:
5
+ 1. **Enter and expand** with `ctxr context gather`. It takes entry selectors — `--section <id>`, `--under <prefix>`, `--seed <path>`, `--entity <name>` — walks the graph out from them (`--hops`, `--type <relation>`), and returns each note with its catalog gloss and hop distance, so you open only what the glosses justify. Start an open conceptual question from a catalog section (`ctxr catalog show --section <id>`).
6
+ 2. **Structure** — paths, hubs, orphans, clusters, bridges — comes from `ctxr graph query`; read the graph document at `__GRAPH_DOCUMENT_PATH__` for cluster context before writing.
7
+ 3. **Widen** with your own content matching (e.g. ripgrep) for a literal string or identifier, excluding __EXCLUSION_PATHS__, and feed a hit back in as `--seed`. Captures under `__CAPTURE_ROOT__` are excluded because they are provenance, not notes: to learn whether the store already holds some material, search `__CAPTURE_ROOT__` directly, by content and by the `capture_file` a capture names.
7
8
 
8
- - `--section <id>` — every note a catalog section lists (`ctxr catalog show --section <id>` reads one directly)
9
- - `--under <prefix>` — every retrievable note under a path prefix
10
- - `--seed <path>` — a note you already hold, including one your own search just found
11
- - `--entity <name>` — every note linking to a concept
9
+ When a search finds nothing, retry with the vocabulary the note itself would use, expand acronyms, and walk the graph from the nearest note you did find.
12
10
 
13
- **2. Expand.** `ctxr context gather` takes those selectors and walks the wikilink graph out from them,
14
- returning each reachable note with its catalog gloss, its hop distance, and labels saying why it is
15
- there — so you can triage the set without opening a single file, then read only what the glosses
16
- justify:
17
-
18
- ```
19
- ctxr context gather --section <id> --hops 1
20
- ctxr context gather --seed <path> --hops 2 --type <relation>
21
- ```
22
-
23
- Results are ordered: live material before demoted (archived) material, nearer hops before farther,
24
- then by how the note was reached, then by path. `no_gloss` on a result means the catalog has no
25
- description for that note yet — the pass found it structurally, not by what it says.
26
-
27
- For structure on its own — shortest path, hubs, orphans, clusters, bridges — query the graph directly
28
- with `ctxr graph query ...`, and read the graph document at `__GRAPH_DOCUMENT_PATH__` (rebuilt by
29
- `ctxr graph build`) for cluster context before writing.
30
-
31
- **3. Widen.** For a literal or entity question the first two steps do not answer — a specific string,
32
- an exact identifier, a phrase — use your own content-matching tool (e.g. grep/ripgrep) against the
33
- store, scoped to exclude:
34
-
35
- __EXCLUSION_PATHS__
36
-
37
- Feed anything it finds back in as `--seed` to pick the pass up again from there.
38
-
39
- Those exclusions are for finding knowledge. Captures under `__CAPTURE_ROOT__` are left out because they
40
- are provenance, not notes, so a search scoped this way never finds one. When the question is whether
41
- the store already holds some material — a document, a meeting, a thread — search `__CAPTURE_ROOT__`
42
- directly, by content and by the `capture_file` a capture names. Finding nothing in the notes is not
43
- evidence that it was never captured.
44
-
45
- There is no `ctxr search` command. Nothing here takes a free-text query, and no result carries a
46
- relevance score. Ranked or semantic search is deferred to a future version — do not look for one.
11
+ There is no `ctxr search` command: nothing takes a free-text query, and no result carries a relevance score.
@@ -2,26 +2,37 @@
2
2
  title: Baseline conventions
3
3
  description: Contexture's shipped conventions, rendered from this store's own configuration.
4
4
  ---
5
- These are the rules that hold regardless of which operation you're doing; a skill states the procedure for one operation.
5
+ ## Writing notes
6
+
7
+ - Write in outliner bullets, not prose paragraphs, unless asked otherwise. Link liberally with wikilinks, and when you create a note, search the store and suggest links to what already exists.
8
+ - Extend what a note says rather than overwrite it, unless a rewrite is asked for.
9
+ - Keep a note's `title:` equal to its filename stem, unique in the store: the catalog builds each entry's wikilink from `title:`, so a divergent title links to nothing.
10
+ - A task is a checkbox with a dated parenthetical: `- [ ] Task (added YYYY-MM-DD, due YYYY-MM-DD)`, `- [~] Task (added YYYY-MM-DD)` while in progress, `- [x] Task (done YYYY-MM-DD)`. Omit a date that does not apply.
11
+
12
+ ## What stays out of the store
13
+
14
+ - Credentials and full card or account numbers never enter it — the last four digits only.
15
+ - Scratch and intermediate files go in `__SCRATCH_PATH__`, never the store or `$HOME`. Deliverables are not scratch: a page goes under `__PUBLISH_PATH__`, a note into the store.
16
+ - Notes carry no access control — whoever reads the store reads all of it. Place sensitive material deliberately, and say in the note when it must not be quoted onward.
17
+
18
+ ## The store log
19
+
20
+ `__LOG_PATH__` is append-only: after an ingest, a lint pass, or a structural change, add `## [YYYY-MM-DD] <kind> | <title>` and a few bullets. At session start, if its last `lint` entry is more than seven days old or missing, suggest a lint pass.
6
21
 
7
22
  ## Links and the relation vocabulary
8
23
 
9
- Wikilinks (`[[Note Name]]`) are the edge substrate the graph is built from. A dangling link — pointing at a note that doesn't yet exist — is a candidate for a new note or a typo, not an error; nothing about it needs fixing before a commit.
24
+ Wikilinks (`[[Note Name]]`) are the edges the graph is built from. A dangling link is a candidate note or a typo, not an error.
10
25
 
11
26
  __RELATION_VOCABULARY__
12
27
 
13
28
  ## Archiving
14
29
 
15
- `ctxr archive <path>` retires a note via a single tracked rename into `__ARCHIVE_DESTINATION__`, preserving its git history and its frontmatter unchanged — never a status tag on a note that stays in place. It reports every other note that links to the archived one, so those links can be reviewed; a dangling link left behind is not itself an error (see Links, above).
30
+ Retire a note with `ctxr archive <path>` — one tracked rename into `__ARCHIVE_DESTINATION__`, the note unchanged — never a status tag on a note left in place.
16
31
 
17
32
  ## Git and sessions
18
33
 
19
- Nothing reaches `__DEFAULT_BRANCH__` un-gated — every write happens inside a session worktree under `__WORKTREES_PATH__`, landed only through a reviewed pull request (see the Write path rule above).
20
-
21
- Landing (`ctxr-land`) fast-forwards the store's canonical clone itself once a PR merges — `git fetch origin && git merge --ff-only origin/__DEFAULT_BRANCH__`, run from that clone — as long as it is on `__DEFAULT_BRANCH__` and can fast-forward cleanly from its remote; if it can't (diverged, no remote, or already elsewhere), the skill reports why instead of forcing it, and the clone is never checked out, reset, or discarded to make it fast-forward.
22
-
23
- The pre-push hook refuses a direct push to `__DEFAULT_BRANCH__`; `CONTEXTURE_ALLOW_DEFAULT_BRANCH_PUSH=1` is its emergency override — for genuine emergencies, not routine use.
34
+ Nothing reaches `__DEFAULT_BRANCH__` un-gated: work happens in a session worktree under `__WORKTREES_PATH__` and lands through a reviewed pull request (`ctxr-submit`, then `ctxr-land`). The pre-push hook refuses a direct push to `__DEFAULT_BRANCH__`; `CONTEXTURE_ALLOW_DEFAULT_BRANCH_PUSH=1` overrides it, for genuine emergencies only.
24
35
 
25
36
  ## Directory-scoped conventions
26
37
 
27
- Some folders may carry their own conventions that apply only when working within them — typically as a `README.md` at that folder's root. Read a folder's own `README.md`, if it has one, before making changes inside it; nothing else in this store scans for these automatically.
38
+ A folder may carry its own `README.md`; read it before changing anything inside that folder.
@@ -11,6 +11,16 @@ Each entry states the rule, why it exists, and how to apply it:
11
11
  Why: <what goes wrong without it — the observation that earned it>
12
12
  Apply: <what to actually do, concretely>
13
13
 
14
+ Every rule in this file is inlined into AGENTS.md and loads on every turn of every session. A rule that
15
+ matters only for one task belongs in its own file here, whose frontmatter declares when to read it:
16
+
17
+ ---
18
+ title: Content style
19
+ read_when: Before writing or restructuring a note's body
20
+ ---
21
+
22
+ A file with `read_when` is not inlined; AGENTS.md lists it under "Read when", by its trigger and its path.
23
+
14
24
  The Why is not decoration. Without the observation that earned a rule, no future reader can tell
15
25
  whether it still holds or whether a one-off calcified into a convention — so it never gets retired,
16
26
  and this file only ever grows. `ctxr-session-capture` proposes additions and removals at the end of a
@@ -9,6 +9,10 @@ on disk, a URL the user handed you. Do not assume any particular one is availabl
9
9
  one: look at what is there, and if nothing can reach the material, say so and ask rather than
10
10
  reconstructing it from memory or from what the user said about it.
11
11
 
12
+ Before a research pass on a topic, query the connected meeting and note sources for it first, and capture
13
+ what they hold. Desk research is the expensive move, and nothing else catches primary material that was
14
+ never captured, because every other check runs on what the store already holds.
15
+
12
16
  When a source system returns several items and the request named one, confirm which before writing.
13
17
  Capturing the wrong meeting is not recoverable by a later ingest — it is a record of something that did
14
18
  not happen.
@@ -22,8 +26,29 @@ that has been improved is no longer evidence of anything.
22
26
  Where the source supplies a summary of its own, keep it, clearly marked as the source's derivation, in
23
27
  its own section beside the record rather than instead of it. A summary is what a service concluded; the
24
28
  record is what happened. A store may require, per source type, the section its captures must carry — if
25
- it does, a capture missing that section is refused at ingest, so check the store's configuration before
26
- deciding a summary is enough.
29
+ it does, a capture missing that section is refused at ingest, and so is one whose heading has nothing under
30
+ it or appears only inside a code block, so check the store's configuration before deciding a summary is
31
+ enough.
32
+
33
+ Perishable material — a promotion, a price, an offer with an end date — is kept for its durable mechanic,
34
+ not its momentary state: capture how it works, and keep the state that will change in a section a later
35
+ capture overwrites.
36
+
37
+ A file a note links to or displays (a PDF it cites, an image it shows) lives under `__CAPTURE_ROOT__assets/`,
38
+ never in a folder of its own beside the notes.
39
+
40
+ Several items from one source system covering the same occasion (two recordings of one meeting, a
41
+ transcript and its summary) are one source. Check them against each other by content and named entities —
42
+ string matching misses the same speech transcribed twice — and when they share an event, say so in each
43
+ capture and name which governs. A fact appearing in both is never corroborated by the pair. Where one
44
+ rendering is demonstrably worse, keep it and record its specific errors rather than discarding it.
45
+
46
+ When a source does not separate speakers, say so in the capture as a caveat on the whole file. Any
47
+ attribution built from it is inference, and a service's own summary attributing positions to named people
48
+ is not the record.
49
+
50
+ A slide deck is read as images, not extracted text: render its pages and read those, since a deck's meaning
51
+ lives in its layout.
27
52
 
28
53
  One capture per item. Two meetings in one file cannot be cited separately, deduplicated separately, or
29
54
  retracted separately.
@@ -33,9 +58,15 @@ retracted separately.
33
58
  In the capture's frontmatter:
34
59
 
35
60
  - `source_type` — the source system's own name, lowercased. Use the same value the store already uses
36
- for that system; a second spelling silently defeats deduplication.
61
+ for that system; a second spelling silently defeats deduplication. Name the same value on
62
+ `ctxr ingest --source-type`: a capture that says one source type and is ingested as another is refused,
63
+ and a store's required section is looked up under the type the capture is recorded under.
37
64
  - `source_id` — that source type, then a slash, then the identifier the source system itself uses for
38
- this item. Prefer an opaque, stable id over a title or a date, which get edited.
65
+ this item. Prefer an opaque, stable id over a title or a date, which get edited. Material no system
66
+ identifies takes a hash instead: a file its SHA-1 (`pdf/<sha1 of the file>`), pasted text the SHA-1 of the
67
+ text (`manual/<sha1>`). An email is its `Message-ID`; a web page is its URL, which `ctxr source check`
68
+ compares with the store's tracking parameters (`ingest.tracking_params`) removed. Pass the same prefixed form
69
+ to `ctxr ingest --source-id`, which refuses one that does not begin with its source type.
39
70
 
40
71
  Do not write `source_hash` or `ingested`. Ingest assigns both, once, and a capture that arrives
41
72
  claiming them is treated as already ingested.
@@ -13,6 +13,12 @@ edit inside a fence that the next build erases).
13
13
  or hand-add only your entries, matching the committed structure, and say so in the commit message.
14
14
  3. Build, then read the result back: reported counts against the source (notes vs catalog entries, graph
15
15
  nodes vs notes); your new notes present with non-zero links; nothing else lost.
16
+ A gloss flagged stale (`ctxr catalog check --stale`, or `ctxr doctor`'s catalog finding) is confirmed by
17
+ reviewing it, then stripping its `<!-- hash:… -->` marker once, so the next `ctxr catalog build` stamps a fresh
18
+ one. The marker is frozen on purpose — editing the gloss and rebuilding does not clear the finding, and
19
+ stripping it without reviewing the gloss confirms nothing. The graph is a per-checkout cache under the cache
20
+ paths: every clone and worktree starts without one, so build it at the point of use when `ctxr doctor` reports
21
+ it stale; no schedule keeps it fresh.
16
22
  4. Fences: never hand-edit inside a `contexture:<region>` fence — the next build overwrites it. Hand
17
23
  edits OUTSIDE a fence (catalog glosses, prose around a generated section) are preserved by every
18
24
  build and are the right place for them. A note's own operator-defined fenced region (a ledger, a
@@ -36,7 +36,9 @@ to put the file — "create a new note" is one option among several, never the d
36
36
  hunt down the now-stale verdict language further down. A corrected body under an uncorrected
37
37
  headline is worse than either alone.
38
38
  - Source discipline: a field the source does not confirm is "not reported" — never inferred from
39
- silence in either direction.
39
+ silence in either direction. A quantity the store did not verify carries who claimed it, when, and
40
+ in what setting ("founder-claimed, 2026-09-16, recruiting pitch"): stripped of its setting, a pitch
41
+ number and a filed number look identical later. Say when a figure is checkable and unchecked.
40
42
  5. Write the note the decision calls for — create it, expand it, merge, restructure, or add a section —
41
43
  preserving prior content in every case but the deliberate rewrite. A NEW note starts from a template
42
44
  under `__TEMPLATES_PATH__`, with `{{title}}` and `{{date}}` substituted as you write (`ctxr-placement`
@@ -49,3 +51,5 @@ to put the file — "create a new note" is one option among several, never the d
49
51
  records its provenance exactly as a new one does, and a note built from several sources cites all of
50
52
  them. A deliberate ingest despite an `alternate_source_match` is the same command.
51
53
  7. Verify: `ctxr lint` (orphans, broken links, material still in the inbox) and `ctxr catalog check`.
54
+ 8. Log it: append `## [YYYY-MM-DD] ingest | <title>` to `__LOG_PATH__`, with a bullet naming the note it informed
55
+ and what changed there.
@@ -1,36 +1,45 @@
1
- Keep this store's mission document — the standing "what's active right now" map AGENTS.md names at
2
- `organize.mission_path` when configured — current: priorities, active builds, back burner, sunset
3
- candidates, and debt. Hand-written content outside the fenced region is never touched.
1
+ Keep this store's mission current: the short core every agent sees on every turn, inlined into AGENTS.md's
2
+ "Mission" section from the document named on its source line. The core is the operator's statement of what
3
+ matters now, so it is small, ranked, and dated. Everything else it once carried lives in a register note it
4
+ links to. Hand-written content outside the fenced region is never touched.
4
5
 
5
- Run `ctxr rollup stale` (or `--for <mission_path>`) first — a never-written mission document, or one whose
6
- recorded timestamp has aged past `organize.rollup_stale_days`, is reported stale on elapsed time alone (no
7
- backlinks compared, unlike an entity rollup); use it instead of guessing from memory whether the document
8
- is out of date.
6
+ Run `ctxr rollup stale` (or `--for <mission_path>`) first. A mission never confirmed, or one confirmed more than
7
+ `organize.rollup_stale_days` ago, is reported stale on elapsed time alone; `ctxr lint` also reports any due date
8
+ in it that has passed. Use those rather than guessing from memory whether it is out of date.
9
9
 
10
- 1. Resolve `<mission_path>` from AGENTS.md's canonical section. If no mission document is configured for
11
- this store, STOP — this skill has nothing to maintain; do not invent a path or create one unasked.
12
- 2. Gather from recent work: the current session's own changes, and every store location the taxonomy
13
- declares (read AGENTS.md's "Placing a new note" section for the configured layers) — not backlinks, and
14
- not a sample. A priority absent from every configured layer is not a store priority; treat it as the
15
- operator's own working memory instead and leave it out.
16
- 3. For each active priority, state its status, its purpose, and its next useful action — a priority with no
17
- next action is not actionable, and one with no purpose is not a priority; resolve or downgrade it rather
18
- than carry it silently.
19
- 4. For each back-burner item, state plainly why it is not active right now — a size cutoff, a blocking
20
- dependency, a deliberate deprioritization. An item with no stated reason for being dormant reads as
21
- simply forgotten; do not leave one that way.
22
- 5. Carry sunset candidates (work whose end state is in sight or whose relevance is fading) and operational
23
- debt (deferred cleanup, known gaps, workarounds owed a real fix) as their own sections, separate from
24
- active and back-burner priorities — never folded into either.
25
- 6. Synthesize into a file — bullets throughout, short clauses; skip any empty section silently (never
26
- "N/A", "none", or "TBD"). Nothing dated later than today; no editorializing beyond the status/purpose/
27
- next-action shape above.
28
- 7. Write: `ctxr rollup write <mission_path> --content-file <file>` — the same command `ctxr-rollup` uses for
29
- an entity, applied here to the store's own mission path; an idempotent fenced write (`changed: false` and
30
- a byte-identical file when the content matches; mismatched markers abort with nothing written).
10
+ 1. Resolve `<mission_path>` from the source line of AGENTS.md's "Mission" section. If no mission document is
11
+ configured for this store, STOP — this skill has nothing to maintain; do not invent a path or create one
12
+ unasked.
13
+ 2. Gather from recent work: the current session's own changes, the store log at `__LOG_PATH__`, and every store
14
+ location the taxonomy declares (read AGENTS.md's "Placing a new note" section for the configured layers) —
15
+ not backlinks, and not a sample. A priority absent from every configured layer is not a store priority; treat
16
+ it as the operator's own working memory instead and leave it out.
17
+ 3. Write the core, and only the core:
18
+ - **Primary mission** — one or two lines on what this store is for, right now.
19
+ - **Top priorities, in rank order** — three to five. Each names its status, its purpose, and its next useful
20
+ action; a priority with no next action is not actionable, and one with no purpose is not a priority —
21
+ resolve or downgrade it rather than carry it silently.
22
+ - **Not now** — what is deliberately set aside, one line each, so it is not mistaken for forgotten.
23
+
24
+ The core stays under `__MISSION_MAX_BYTES__` bytes; `ctxr doctor` fails above it. Per-item detail an agent
25
+ already finds elsewhere (a project's own next action, a status its note carries) is linked, not copied.
26
+ 4. Keep the register in a note the core links to, placed by `ctxr-placement` like any other: back-burner items,
27
+ each stating plainly why it is not active right now (a size cutoff, a blocking dependency, a deliberate
28
+ deprioritization); sunset candidates (work whose end state is in sight or whose relevance is fading); and
29
+ open operational debt (deferred cleanup, known gaps, workarounds owed a real fix). Debt that is closed is
30
+ history: record it in `__LOG_PATH__` and remove it.
31
+ 5. Propose, then write. The ranking and the mission are the operator's: show the proposed core and say what
32
+ moved and why, and write only once the operator confirms. A factual correction — a priority shipped,
33
+ blocked, or archived — is yours to make, and you say so in the report.
34
+ 6. Synthesize into a file — bullets throughout, short clauses; skip any empty section silently (never "N/A",
35
+ "none", or "TBD"). Nothing dated later than today; no editorializing beyond the shape above.
36
+ 7. Write: `ctxr rollup write <mission_path> --content-file <file>` — the same command `ctxr-rollup` uses for an
37
+ entity, applied here to the store's own mission path. It stamps the confirmation date AGENTS.md shows, and
38
+ is an idempotent fenced write (`changed: false` and a byte-identical file when the content matches;
39
+ mismatched markers abort with nothing written).
31
40
 
32
41
  ## Report
33
42
 
34
- Mission path, `changed` or unchanged, and what moved since the last write (a priority resolved, a new
35
- back-burner addition, a sunset candidate promoted or dropped). Anything outside the fence you want to fix
36
- is a separate, explicit edit.
43
+ Mission path, `changed` or unchanged, what moved since the last write (a priority resolved, re-ranked, or
44
+ added; an item moved to the register), and any factual correction made without confirmation. Anything outside
45
+ the fence you want to fix is a separate, explicit edit.
@@ -1,5 +1,7 @@
1
1
  1. Run `ctxr lint` for the full health report — orphan notes, broken links, uningested inbox material,
2
2
  catalog gaps. It always exits 0; its findings are observations for judgment, never a block.
3
+ After a lint pass, append `## [YYYY-MM-DD] lint | <one-line summary>` to `__LOG_PATH__`, with a bullet per
4
+ finding class you acted on — the log's last `lint` entry is how the next session knows one is due.
3
5
  2. Run `ctxr doctor` for the invariants that DO block: catalog coverage, hook health, and more. Address doctor's failures before `ctxr-submit`; it runs the same checks.
4
6
 
5
7
  ## Placement review
@@ -13,11 +15,19 @@ organized by actionability. Single-note calls go through `ctxr-placement`.
13
15
  ## Retiring: move, don't tag
14
16
 
15
17
  A status tag left in place defeats the layer — the active layers must show only active work.
16
- `ctxr archive <path>` moves the note into the configured archive location as a tracked rename; the
17
- note's frontmatter travels unchanged (never rewrite it on the move). Retiring is reversible cold storage,
18
- not deletion. Verify with `git status --short` showing `R` (a rename, history preserved), not a delete
18
+ `ctxr archive <path>` moves the note to the same path beneath `__ARCHIVE_DESTINATION__` as a tracked rename, so
19
+ the archive still shows where it lived and the reverse rename restores it. The note's frontmatter travels unchanged
20
+ (never rewrite it on the move). Retiring is reversible cold storage, not deletion. Verify with `git status --short` showing `R` (a rename, history preserved), not a delete
19
21
  plus an add, then `ctxr catalog check`.
20
22
 
23
+ A unit that lives as a folder of notes (a project with its supporting notes) is retired whole —
24
+ `ctxr archive <folder>` moves it to `__ARCHIVE_DESTINATION__<folder>` as one tracked rename. Archiving its notes
25
+ one by one leaves the unit half-retired until the last one moves.
26
+
27
+ Every retirement records, in the past tense, what happened and when it was retired — in the hub note for a
28
+ folder, as a blockquote at the top of a single note — so the item reads as a record, not as live work. When the
29
+ item was one of the mission's priorities, hand it to `ctxr-mission`, which proposes what takes the freed slot.
30
+
21
31
  ## Stale rollups
22
32
 
23
33
  `ctxr lint`'s rollup-stale finding (and `ctxr rollup stale` directly) names entity notes whose backlinks
@@ -36,6 +46,20 @@ have moved since their last synthesis, or which have never been rolled up — ha
36
46
 
37
47
  ## Moves at scale
38
48
 
39
- Two commits, never a broken intermediate: commit 1 = the moves PLUS the wikilink fixes they require;
40
- commit 2 = tooling and doc patches. Before the moves, grep for hardcoded references to the old paths.
41
- After they land, rebuild the derived artifacts (`ctxr-derived-artifacts`) and re-run `ctxr lint`.
49
+ A restructure that moves folders between layers is a migration. Run it in this order.
50
+
51
+ 1. **Snapshot, don't abort.** If the worktree holds unrelated uncommitted work, commit it first as
52
+ `WIP: pre-<slug> snapshot` and note that commit. It is the rollback anchor, and the baseline step 4 diffs
53
+ against.
54
+ 2. **Preflight.** Grep the whole store for the old path prefixes. That covers notes, skills, scripts and
55
+ generated config, but not `.git` or the session worktrees path. Every hit is a hardcoded reference the
56
+ move will break. A wikilink written with a path (`[[old/folder/Note]]`) breaks on the move, so rewrite it
57
+ to the bare name first. `ctxr doctor` reports links that resolve ambiguously; a collision the move would
58
+ create shows there afterwards.
59
+ 3. **Two commits, never a broken intermediate.** Commit 1 is the moves plus the wikilink fixes they
60
+ require, so the store is consistent after it alone. Commit 2 is tooling and doc patches.
61
+ 4. **Stage surgically.** Diff each staged file against the snapshot. A file whose diff is larger than the
62
+ migration's own edit is carrying unrelated drift: unstage it, restore it from the snapshot, re-apply only
63
+ the migration edit, and leave the drift for its own commit.
64
+ 5. **After they land,** rebuild the derived artifacts (`ctxr-derived-artifacts`), re-run `ctxr lint` and
65
+ `ctxr doctor`, and log the migration in the store log with the snapshot, move, and tooling commits.
@@ -31,6 +31,11 @@ clutter — worse than a slightly crowded existing one. Starting small and promo
31
31
  starting big and hollow is not. Make the promotion trigger a rule, not a vibe, and write it INTO the
32
32
  note: "Promote to its own top-level location the moment this holds 3+ distinct notes or topics."
33
33
 
34
+ A unit that will carry supporting notes (a project with its research, an exploration with its evidence)
35
+ gets a folder of its own. The graph clusters notes by their first __CLUSTER_DEPTH__ path segments, so
36
+ grouping such units under one common parent at that depth merges their clusters, and the graph then asserts
37
+ a relationship between them that does not exist.
38
+
34
39
  ## 4. What must never enter the store?
35
40
 
36
41
  Credentials, full account numbers, and secrets never enter the store — last-4 only. This is a placement
@@ -51,7 +51,8 @@ says something.
51
51
  When `gather` reports that an existing page belongs at the reported path too, it is because this
52
52
  subject is acquiring a second page, and a subject's pages collect under one folder naming it. Move
53
53
  that page there before you scaffold the new one, and tell the operator its URL changed — somebody
54
- may already be holding that link. `gather` moves nothing itself, and it names which signal counted
54
+ may already be holding that link. `ctxr publish urls` reports the old address beside the new one, and
55
+ `ctxr-submit` carries both into the pull request. `gather` moves nothing itself, and it names which signal counted
55
56
  the page as this subject's; read that before you move anything, because the signal is a reading of
56
57
  the page's README and can be wrong. Lead a page's source notes with the note it is a representation
57
58
  of — that lead link is what says whose page this is, and everything after it is a citation.