@cairnkeep/cli 2.3.1 → 2.5.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.
- package/CHANGELOG.md +85 -0
- package/README.md +232 -6
- package/bin/cairn +43 -2
- package/claude/capability-contract/hooks/capability-command-finish.sh +81 -0
- package/claude/capability-contract/hooks/capability-command-start.sh +76 -0
- package/claude/hooks/compaction-capture.sh +34 -0
- package/claude/hooks/memory-capture.sh +47 -5
- package/claude/hooks/memory-wakeup.sh +55 -2
- package/docs/building-an-overlay.md +4 -3
- package/docs/design/meta-agent.md +439 -0
- package/docs/harness-compatibility.md +117 -0
- package/docs/learning/CURRICULUM-MAP.md +91 -0
- package/docs/learning/FEATURE-GUIDE.md +86 -0
- package/docs/learning/PRODUCTION-PLAN.md +45 -14
- package/docs/learning/README.md +20 -1
- package/docs/learning/instructor-guide.md +6 -0
- package/docs/learning/lessons/L00-why-cairnkeep.md +20 -8
- package/docs/learning/lessons/L01-safe-trial.md +3 -3
- package/docs/learning/lessons/L02-installation.md +23 -5
- package/docs/learning/lessons/L03-first-project.md +7 -2
- package/docs/learning/lessons/L04-memory-fundamentals.md +4 -0
- package/docs/learning/lessons/L05-daily-workflow.md +4 -0
- package/docs/learning/lessons/L07-privacy-and-storage.md +3 -0
- package/docs/learning/lessons/L10-context-exploration.md +4 -2
- package/docs/learning/lessons/L12-managed-overlays.md +2 -0
- package/docs/learning/lessons/L13-session-evidence.md +71 -0
- package/docs/learning/lessons/L14-typed-memory.md +51 -0
- package/docs/learning/lessons/L15-capability-governance.md +56 -0
- package/docs/learning/lessons/L16-evaluation.md +67 -0
- package/docs/learning/lessons/L17-agent-boundary.md +55 -0
- package/docs/learning/templates/lesson-template.md +4 -1
- package/docs/learning/tracks/evidence-and-evaluation.md +20 -0
- package/docs/learning/tracks/operator.md +8 -2
- package/docs/learning/tracks/practitioner.md +6 -1
- package/docs/learning/tracks/quickstart.md +3 -0
- package/docs/learning/video-scripts/L00-why-cairnkeep.md +21 -17
- package/docs/learning/video-scripts/L02-installation.md +9 -2
- package/docs/learning/video-scripts/L03-first-project.md +3 -0
- package/docs/operating.md +567 -7
- package/docs/privacy-and-data-flow.md +417 -0
- package/docs/storage.md +252 -0
- package/examples/eval/README.md +42 -0
- package/examples/eval/adapter.json +12 -0
- package/examples/eval/bundled-fake.json +1 -0
- package/examples/eval/task-set.json +1 -0
- package/mcp-memory-server/dist/artifact-cli.js +184 -0
- package/mcp-memory-server/dist/artifact-schema.js +218 -0
- package/mcp-memory-server/dist/artifact-store.js +812 -0
- package/mcp-memory-server/dist/capability-adapter.js +286 -0
- package/mcp-memory-server/dist/capability-cli.js +361 -0
- package/mcp-memory-server/dist/capability-config.js +310 -0
- package/mcp-memory-server/dist/capability-harness.js +496 -0
- package/mcp-memory-server/dist/capability-registry.js +123 -0
- package/mcp-memory-server/dist/capability-schema.js +65 -0
- package/mcp-memory-server/dist/capability-store.js +431 -0
- package/mcp-memory-server/dist/compaction-normalize.js +267 -0
- package/mcp-memory-server/dist/eval-cli.js +523 -0
- package/mcp-memory-server/dist/eval-plan.js +346 -0
- package/mcp-memory-server/dist/eval-process.js +273 -0
- package/mcp-memory-server/dist/eval-report.js +609 -0
- package/mcp-memory-server/dist/eval-runner.js +827 -0
- package/mcp-memory-server/dist/eval-schema.js +368 -0
- package/mcp-memory-server/dist/eval-statistics.js +161 -0
- package/mcp-memory-server/dist/eval-workspace.js +313 -0
- package/mcp-memory-server/dist/failure-signature.js +141 -0
- package/mcp-memory-server/dist/index.js +600 -55
- package/mcp-memory-server/dist/node-cli.js +84 -0
- package/mcp-memory-server/dist/node-schema.js +170 -0
- package/mcp-memory-server/dist/node-store.js +455 -0
- package/mcp-memory-server/dist/note-cli.js +235 -0
- package/mcp-memory-server/dist/note-distiller.js +177 -0
- package/mcp-memory-server/dist/note-enrichment.js +93 -0
- package/mcp-memory-server/dist/note-schema.js +4 -0
- package/mcp-memory-server/dist/note-store.js +985 -0
- package/mcp-memory-server/dist/trajectory-cli.js +141 -0
- package/mcp-memory-server/dist/trajectory-normalize.js +448 -0
- package/mcp-memory-server/dist/trajectory-redaction.js +155 -0
- package/mcp-memory-server/dist/trajectory-schema.js +73 -0
- package/mcp-memory-server/dist/trajectory-store.js +339 -0
- package/mcp-memory-server/package.json +24 -2
- package/mcp-memory-server/scripts/fixtures/compaction-claude-code-2.1.219.json +9 -0
- package/mcp-memory-server/scripts/fixtures/compaction-claude-code-2.1.220.json +9 -0
- package/mcp-memory-server/scripts/fixtures/compaction-opencode-1.17.20-event.json +6 -0
- package/mcp-memory-server/scripts/fixtures/compaction-opencode-1.17.20-messages.json +119 -0
- package/mcp-memory-server/scripts/fixtures/compaction-unknown-version.json +17 -0
- package/opencode/capability-contract/plugins/capability-command.ts +319 -0
- package/opencode/command/graphify.md +25 -14
- package/opencode/plugins/memory-capture.ts +76 -10
- package/opencode/plugins/memory-wakeup.ts +58 -6
- package/package.json +8 -4
- package/pi/extensions/cairnkeep-trajectory.ts +55 -0
- package/schemas/artifact.schema.json +133 -0
- package/schemas/capability-callback.schema.json +68 -0
- package/schemas/capability-contract.schema.json +126 -0
- package/schemas/eval-adapter.schema.json +43 -0
- package/schemas/eval-protocol.schema.json +114 -0
- package/schemas/eval-report.schema.json +423 -0
- package/schemas/eval-task-set.schema.json +114 -0
- package/schemas/memory-node.schema.json +90 -0
- package/schemas/note.schema.json +112 -0
- package/schemas/trajectory-redaction.schema.json +25 -0
- package/schemas/trajectory.schema.json +82 -0
- package/scripts/bootstrap.sh +6 -0
- package/scripts/completion.sh +119 -5
- package/scripts/doctor.sh +284 -0
- package/scripts/fake-eval-adapter.mjs +120 -0
- package/scripts/fixtures/capability-harness-contracts.json +408 -0
- package/scripts/install-audit-timer.sh +3 -1
- package/scripts/lib/capability-opencode-plugin-harness.mjs +291 -0
- package/scripts/lib/trajectory-opencode-plugin-harness.mjs +25 -0
- package/scripts/lib/trajectory-pi-extension-harness.mjs +42 -0
- package/scripts/memory-wiki-audit.sh +49 -0
- package/scripts/smoke-bash32.sh +9 -0
- package/scripts/sync-claude-assets.sh +99 -6
- package/scripts/sync-opencode-graphify-assets.sh +24 -3
- package/scripts/sync-opencode-plugin-assets.sh +31 -5
- package/scripts/sync-opencode-security-assets.sh +24 -3
- package/scripts/sync-opencode-wiki-assets.sh +24 -3
- package/scripts/sync-pi-assets.sh +72 -0
- package/scripts/test-audit-timer.sh +98 -0
- package/scripts/test-bootstrap-untracked.sh +49 -0
- package/scripts/test-cli-dispatch.sh +41 -2
- package/scripts/test-compaction-hooks.sh +495 -0
- package/scripts/test-completion.sh +77 -0
- package/scripts/test-doctor.sh +348 -1
- package/scripts/test-eval-cli.sh +175 -0
- package/scripts/test-launcher-hooks.sh +630 -3
- package/scripts/test-learning-docs.sh +20 -4
- package/scripts/test-notes-cli.sh +114 -0
- package/scripts/test-package-install.sh +254 -0
- package/scripts/test-phase16-node-lifecycle.sh +50 -0
- package/scripts/test-phase17-artifact-lifecycle.sh +370 -0
- package/scripts/test-phase18-capability-lifecycle.sh +504 -0
- package/scripts/test-phase18-harness-boundary.sh +1060 -0
- package/scripts/test-phase19-eval-lifecycle.sh +1015 -0
- package/scripts/test-trajectory-cli.sh +87 -0
- package/scripts/test-trajectory-hooks.sh +142 -0
- package/scripts/test-uninstall.sh +231 -5
- package/scripts/uninstall.sh +38 -5
- package/scripts/verify-dependency-security.mjs +121 -0
- package/scripts/verify-docs-parity.sh +527 -1
- package/scripts/verify-phase18-runtime-evidence.mjs +895 -0
- package/scripts/verify-phase19-runtime-evidence.mjs +947 -0
- package/templates/capabilities.json.template +7 -0
- package/templates/env.example.template +51 -0
- package/templates/memory-wiki-audit.service.template +1 -1
- package/templates/start-claude.sh.template +36 -0
- package/templates/start-kimi.sh.template +39 -0
- package/templates/start-opencode.sh.template +47 -5
- package/templates/start-pi.sh.template +30 -0
- package/templates/trajectory-redaction.json.template +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,88 @@
|
|
|
3
3
|
All notable user-facing changes are documented here. This project follows
|
|
4
4
|
[Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [2.5.0] - 2026-07-29
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add Kimi Code as a supported memory client with a generated project launcher,
|
|
13
|
+
local stdio guidance, and tested authenticated remote HTTP configuration.
|
|
14
|
+
- Add an explicit harness compatibility matrix and a documented validation
|
|
15
|
+
process for future MCP clients.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Document that Kimi requires a literal MCP URL and a token reference through
|
|
20
|
+
`bearerTokenEnvVar`, preventing invalid `${VAR}` URL configurations without
|
|
21
|
+
writing bearer-token values to project files.
|
|
22
|
+
|
|
23
|
+
## [2.4.0] - 2026-07-29
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Add opt-in, local-only, structured Claude Code and OpenCode session
|
|
28
|
+
trajectories with pre-write redaction, reasoning omission, bounded retention
|
|
29
|
+
and no model or network dependency.
|
|
30
|
+
- Add `cairn trajectory list|show|prune`, shell completion, and explicit
|
|
31
|
+
`cairn doctor --repair` support for trajectory metadata and indexes.
|
|
32
|
+
- Add native Pi trajectory capture through its `session_shutdown` extension,
|
|
33
|
+
`cairn sync-pi`, a generic Pi launcher, uninstall coverage, and the same
|
|
34
|
+
opt-in local redaction, size, and retention boundary as other harnesses.
|
|
35
|
+
- Add default-off deterministic hindsight-note distillation, exact repeated
|
|
36
|
+
error lookup, typed local Markdown hierarchy, lifecycle history, explicit
|
|
37
|
+
corroborated shared promotion, and `cairn notes` CLI/completion support.
|
|
38
|
+
- Add separately opted-in provider-neutral note prose enrichment and integrate
|
|
39
|
+
all-project incremental distillation into the existing audit timer without
|
|
40
|
+
adding online-agent latency.
|
|
41
|
+
- Add default-off typed memory metadata/tags, hard-filtered discovery,
|
|
42
|
+
history-aware structured `memory_import`, and logical project/shared note
|
|
43
|
+
address spaces with journaled crash recovery and doctor integration.
|
|
44
|
+
- Add independent default-off compaction continuity for supported Claude Code
|
|
45
|
+
and OpenCode seams, capturing only harness-produced summaries into local,
|
|
46
|
+
redacted, bounded immutable revisions with structured fresh-session recovery.
|
|
47
|
+
- Add a separate local artifact store for compaction summaries, diffs, test
|
|
48
|
+
output, and generated-file metadata/snapshots; four gated MCP tools;
|
|
49
|
+
`cairn artifact list|show|delete|prune`; doctor, completion, package, and
|
|
50
|
+
backup-first uninstall coverage; and separately consented HTTP access.
|
|
51
|
+
- Add a default-off managed contract for eight existing capabilities, including
|
|
52
|
+
project CLI overrides, compatibility-aware status/digests, exact MCP tool
|
|
53
|
+
omission, guarded installed workflows, and separately consented payload-free
|
|
54
|
+
local callback records.
|
|
55
|
+
- Add a default-off, adapter-driven two-pass evaluation harness with immutable
|
|
56
|
+
task sets, paired seeds, confidence intervals, per-capability ablations,
|
|
57
|
+
deterministic offline fixtures, bounded reports, and exact-source runtime
|
|
58
|
+
evidence without claiming an unmeasured quality improvement.
|
|
59
|
+
- Add a design-only meta-agent contract describing how future configuration
|
|
60
|
+
proposals could be evaluated through the existing harness without giving
|
|
61
|
+
Cairnkeep ownership of an agent or inference loop.
|
|
62
|
+
|
|
63
|
+
### Fixed
|
|
64
|
+
|
|
65
|
+
- Load the native OpenCode capability plugin through its supported single-export
|
|
66
|
+
shape, run its coordinator with Node under OpenCode's Bun host, accept the
|
|
67
|
+
pinned runtime event envelope, and settle terminal callbacks before the host
|
|
68
|
+
can exit.
|
|
69
|
+
- Layer `CAIRN_EXTRA_SETTINGS` through OpenCode's supported
|
|
70
|
+
`OPENCODE_CONFIG` environment seam and keep headless graph commands in the
|
|
71
|
+
tool-calling path until their real owner operation completes.
|
|
72
|
+
- Pin the Claude Code 2.1.220 `PostCompact` `prompt_id` payload shape alongside
|
|
73
|
+
the retained 2.1.219 adapter while continuing to refuse unknown versions.
|
|
74
|
+
- Preserve redacted Pi provider failures as trajectory system events and treat
|
|
75
|
+
a closed trajectory CLI output pipe as a normal consumer exit.
|
|
76
|
+
- Make the audit script executable so its rendered systemd service target can
|
|
77
|
+
run directly.
|
|
78
|
+
- Bind evaluation note distillation to the admitted task workspace so nested
|
|
79
|
+
task trajectories cannot be missed or replaced by a source-root fallback.
|
|
80
|
+
- Upgrade the MCP SDK to 1.30.0 so both package graphs use the upstream-owned,
|
|
81
|
+
patched Hono transport and report zero production vulnerabilities.
|
|
82
|
+
|
|
83
|
+
Trajectory/compaction capture, artifact access, and note distillation/enrichment remain disabled by default. Existing
|
|
84
|
+
MCP tools, memory database paths, and remote HTTP behavior are unchanged. No
|
|
85
|
+
memory-quality or efficiency improvement is claimed before the evaluation
|
|
86
|
+
harness measures it.
|
|
87
|
+
|
|
6
88
|
## [2.3.1] - 2026-07-25
|
|
7
89
|
|
|
8
90
|
### Fixed
|
|
@@ -129,6 +211,9 @@ stored memories.
|
|
|
129
211
|
- Preserve executable permissions and Bash 3.2 portability on macOS.
|
|
130
212
|
- Add backup-first uninstall and SQLite-safe memory export/import guidance.
|
|
131
213
|
|
|
214
|
+
[Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.5.0...HEAD
|
|
215
|
+
[2.5.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.4.0...v2.5.0
|
|
216
|
+
[2.4.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.3.1...v2.4.0
|
|
132
217
|
[2.3.1]: https://github.com/cairnkeep/cairnkeep/compare/v2.3.0...v2.3.1
|
|
133
218
|
[2.3.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.2.1...v2.3.0
|
|
134
219
|
[2.2.1]: https://github.com/cairnkeep/cairnkeep/compare/v2.2.0...v2.2.1
|
package/README.md
CHANGED
|
@@ -9,15 +9,17 @@
|
|
|
9
9
|
A *cairn* is a stack of stones left as a trail marker for whoever follows; a
|
|
10
10
|
*keep* is where you store what matters. **Cairnkeep** is where coding agents
|
|
11
11
|
stack durable memory — decisions, pitfalls, patterns — and follow the trail
|
|
12
|
-
across sessions, projects, and harnesses (Claude Code, OpenCode,
|
|
12
|
+
across sessions, projects, and harnesses (Claude Code, OpenCode, Kimi Code,
|
|
13
|
+
Pi, and other MCP clients).
|
|
13
14
|
|
|
14
15
|
## Status
|
|
15
16
|
|
|
16
|
-
Shipped: the memory server, the `cairn` CLI (`bootstrap`, `memory-server`, `sync`,
|
|
17
|
-
`doctor`, `memory`, `audit-timer`, `completion`, `uninstall`) installable via
|
|
17
|
+
Shipped: the memory server, the `cairn` CLI (`bootstrap`, `memory-server`, `sync`, `sync-pi`,
|
|
18
|
+
`doctor`, `trajectory`, `artifact`, `notes`, `memory`, `eval`, `audit-timer`, `completion`, `uninstall`) installable via
|
|
18
19
|
`npm i -g @cairnkeep/cli`, and the
|
|
19
20
|
operating layer (commands,
|
|
20
|
-
agents, hooks) installed on
|
|
21
|
+
agents, hooks) installed on Claude Code and OpenCode, plus a native Pi
|
|
22
|
+
trajectory extension. The generic launchers
|
|
21
23
|
expose wrapper seams (`.ai/pre-launch.sh`, `CAIRN_EXTRA_SETTINGS`,
|
|
22
24
|
`.ai/post-exit.sh`) so an enterprise wrapper can add provider/credential setup
|
|
23
25
|
without forking them. Also shipped: context exploration (`/context-explore`) and
|
|
@@ -35,6 +37,8 @@ and 20 are end-of-life upstream.
|
|
|
35
37
|
|---|---|
|
|
36
38
|
| Claude Code on Linux/macOS | Memory server plus commands, agents, hooks, and launchers |
|
|
37
39
|
| OpenCode on Linux/macOS | Memory server plus commands, plugins, hooks, and launchers |
|
|
40
|
+
| Kimi Code on Linux/macOS | Memory MCP server plus project launcher; no Cairnkeep operating-layer assets yet |
|
|
41
|
+
| Pi on Linux/macOS | Native opt-in trajectory extension and launcher; no bundled MCP bridge |
|
|
38
42
|
| Codex CLI | Memory MCP server; no Cairnkeep operating-layer assets |
|
|
39
43
|
| Other MCP clients | Memory and optional domain-knowledge MCP tools |
|
|
40
44
|
| Native Windows | Not supported by the Bash-based installer; use WSL (not yet CI-verified) |
|
|
@@ -42,6 +46,9 @@ and 20 are end-of-life upstream.
|
|
|
42
46
|
Linux, macOS, Bash 3.2 portability, and clean Node 22/24/26 runtime checks
|
|
43
47
|
are exercised in CI.
|
|
44
48
|
|
|
49
|
+
See [Harness compatibility](docs/harness-compatibility.md) for exact support
|
|
50
|
+
levels, Kimi configuration, and candidates that are not yet runtime-tested.
|
|
51
|
+
|
|
45
52
|
## Try with Podman
|
|
46
53
|
|
|
47
54
|
The minimal OCI image runs the memory server as an unprivileged user and keeps
|
|
@@ -67,10 +74,17 @@ storage paths, secrets, and private derived images, see
|
|
|
67
74
|
embedding-ranked search against any OpenAI-compatible endpoint.
|
|
68
75
|
- **`bin/cairn`** — the CLI. `cairn bootstrap [path]` scaffolds a project's
|
|
69
76
|
`.ai/` launchers + env; `cairn doctor` health-checks the configured pieces;
|
|
77
|
+
`cairn trajectory list|show|prune` manages opt-in local session trajectories;
|
|
78
|
+
`cairn artifact list|show|delete|prune` manages opt-in local artifacts;
|
|
79
|
+
`cairn eval validate|run|ablate|report|prune|delete` coordinates explicit
|
|
80
|
+
local two-pass and one-capability-at-a-time measurements;
|
|
81
|
+
`cairn notes distill|search-error|promote|doctor` compiles and searches
|
|
82
|
+
default-off local hindsight notes outside the online agent path;
|
|
70
83
|
`cairn memory export|import` relocates the durable store between machines
|
|
71
84
|
(`export` requires the optional `sqlite3` CLI);
|
|
72
85
|
`cairn audit-timer` installs the scheduled memory+wiki audit;
|
|
73
86
|
`cairn completion bash|zsh|fish` generates shell completion definitions; and
|
|
87
|
+
`cairn sync-pi` installs the native Pi trajectory extension;
|
|
74
88
|
`cairn uninstall` reverses the install (backup-first, revertible).
|
|
75
89
|
- **`templates/`** — project scaffolding (generic launchers, env) plus the
|
|
76
90
|
derived-knowledge layer (wiki, alignment, graph, security, planning).
|
|
@@ -139,6 +153,41 @@ patterns/transactional-migrations: Use transactional migrations for schema chang
|
|
|
139
153
|
The exact command rendering depends on the client. Any MCP client can call
|
|
140
154
|
`memory_write` and `memory_search` directly.
|
|
141
155
|
|
|
156
|
+
For Kimi Code, bootstrap supplies a launcher and Kimi reads the repository's
|
|
157
|
+
MCP configuration. A local stdio entry uses `cairn memory-server`. Remote Kimi
|
|
158
|
+
configuration requires a literal URL and supports a token reference through
|
|
159
|
+
`bearerTokenEnvVar`; it does not expand `${VAR}` in the URL. See
|
|
160
|
+
[Harness compatibility](docs/harness-compatibility.md#kimi-code).
|
|
161
|
+
|
|
162
|
+
For Pi, install the local trajectory adapter and use the scaffolded launcher:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
cairn sync-pi --apply
|
|
166
|
+
cairn bootstrap /path/to/project
|
|
167
|
+
cd /path/to/project && ./.ai/start-pi.sh
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
This installs trajectory capture only. Cairnkeep does not bundle or select a Pi
|
|
171
|
+
MCP bridge; configure a user-chosen bridge separately if you also want the MCP
|
|
172
|
+
memory tools inside Pi.
|
|
173
|
+
|
|
174
|
+
Closed trajectories can be compiled into local hindsight notes without a model
|
|
175
|
+
or embedding service. Capture and distillation are separate opt-ins:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
export CAIRN_TRAJECTORY_CAPTURE=1 # affects future closed sessions
|
|
179
|
+
export CAIRN_NOTE_DISTILLATION=1
|
|
180
|
+
cairn notes distill --project /path/to/project --json
|
|
181
|
+
printf '%s\n' 'TypeError: example' | cairn notes search-error --project /path/to/project --json
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Notes keep deterministic failure, resolution, abandonment, and recurrence
|
|
185
|
+
history under `~/.cairnkeep/notes/`. Shared promotion is never automatic: it
|
|
186
|
+
requires compatible evidence from two distinct projects and an explicit
|
|
187
|
+
`cairn notes promote NOTE-ID --with NOTE-ID --confirm`. See the
|
|
188
|
+
[operating guide](docs/operating.md#hindsight-notes-opt-in) before enabling
|
|
189
|
+
optional model enrichment.
|
|
190
|
+
|
|
142
191
|
Prefer working from a clone? Build the server with `cd mcp-memory-server && npm
|
|
143
192
|
install && npm run build`, then use `scripts/sync-claude-assets.sh` and
|
|
144
193
|
`bin/cairn` in place of the installed `cairn`.
|
|
@@ -159,8 +208,9 @@ unless a wrapper opts in:
|
|
|
159
208
|
export env (e.g. a provider base URL) or abort the launch by returning
|
|
160
209
|
non-zero. This is where credential refresh / connectivity setup lives.
|
|
161
210
|
- **`CAIRN_EXTRA_SETTINGS`** — path to a settings file layered onto the harness
|
|
162
|
-
(`--settings` for Claude Code,
|
|
163
|
-
|
|
211
|
+
(`--settings` for Claude Code, `OPENCODE_CONFIG` for OpenCode). Pi has no equivalent
|
|
212
|
+
generic settings-file flag, so its launcher leaves this variable unused.
|
|
213
|
+
Process env still wins, so an inline value beats the profile.
|
|
164
214
|
- **`.ai/post-exit.sh`** — sourced after the harness exits, with
|
|
165
215
|
`CAIRN_EXIT_STATUS` set to its exit code.
|
|
166
216
|
|
|
@@ -188,6 +238,37 @@ search):
|
|
|
188
238
|
| `CAIRN_MEMORY_EMBEDDING_MODEL` | Embedding model name (required for semantic search) |
|
|
189
239
|
| `CAIRN_MEMORY_EMBEDDING_TIMEOUT_MS` | Embedding request timeout before substring fallback (default `15000`) |
|
|
190
240
|
| `CAIRN_AGENTFS_BASE_DIR` | Base dir for global memory scopes (default `~/.cairnkeep`) |
|
|
241
|
+
| `CAIRN_TRAJECTORY_CAPTURE` | Opt in to local structured session capture (`1`, `true`, `yes`, or `on`; default off) |
|
|
242
|
+
| `CAIRN_TRAJECTORY_SESSION_MAX_BYTES` | Maximum serialized bytes per captured session (default `5242880`, 5 MiB) |
|
|
243
|
+
| `CAIRN_TRAJECTORY_STORE_MAX_BYTES` | Maximum logical bytes across local trajectories (default `268435456`, 256 MiB) |
|
|
244
|
+
| `CAIRN_TRAJECTORY_RETENTION_DAYS` | Retain captured sessions for this many days (default `30`) |
|
|
245
|
+
| `CAIRN_TRAJECTORY_REDACTION_FILE` | Optional project-contained redaction config (default `.ai/trajectory-redaction.json` when present) |
|
|
246
|
+
| `CAIRN_REDACTION_FILE` | Optional project-contained redaction config shared by trajectories and artifacts (falls back to `CAIRN_TRAJECTORY_REDACTION_FILE`) |
|
|
247
|
+
| `CAIRN_COMPACTION_CAPTURE` | Opt in to local harness-produced compaction capture and fresh-session recovery (off by default) |
|
|
248
|
+
| `CAIRN_ARTIFACT_STORE` | Expose four local stdio artifact tools (off by default; independent of compaction capture) |
|
|
249
|
+
| `CAIRN_ARTIFACT_HTTP` | Separately consent to artifact tools over authenticated HTTP (off by default; also requires `CAIRN_ARTIFACT_STORE`) |
|
|
250
|
+
| `CAIRN_ARTIFACT_MAX_BYTES` | Maximum stored bytes per artifact (default `1048576`, 1 MiB) |
|
|
251
|
+
| `CAIRN_ARTIFACT_SESSION_MAX_BYTES` | Maximum logical bytes per artifact session (default `16777216`, 16 MiB) |
|
|
252
|
+
| `CAIRN_ARTIFACT_STORE_MAX_BYTES` | Maximum logical bytes in one artifact store (default `268435456`, 256 MiB) |
|
|
253
|
+
| `CAIRN_ARTIFACT_RETENTION_DAYS` | Artifact age retention (default `30`) |
|
|
254
|
+
| `CAIRN_COMPACTION_MAX_REVISIONS` | Retained compaction revisions per session (default `8`) |
|
|
255
|
+
| `CAIRN_ARTIFACT_GENERATED_FILE_SNAPSHOT_MAX_BYTES` | Generated-file inline snapshot cap (default `262144`, 256 KiB; lower if the artifact cap is lower) |
|
|
256
|
+
| `CAIRN_NOTE_DISTILLATION` | Opt in to one-shot/scheduled local note distillation and lookup (default off) |
|
|
257
|
+
| `CAIRN_NOTE_ENRICHMENT` | Separately opt in to remote/local prose enrichment; never implied by credentials (default off) |
|
|
258
|
+
| `CAIRN_NOTE_ENRICHMENT_MODEL` | Explicit chat model for optional note enrichment (no default) |
|
|
259
|
+
| `CAIRN_NOTE_ENRICHMENT_TIMEOUT_MS` | Optional enrichment timeout (default `15000`) |
|
|
260
|
+
| `CAIRN_TYPED_MEMORY_NODES` | Opt in to typed metadata, filters, logical note address spaces, and `memory_import` (default off; restart the server after changing) |
|
|
261
|
+
| `CAIRN_CAPABILITY_CONTRACT` | Opt in to the managed eight-capability contract (default off) |
|
|
262
|
+
| `CAIRN_CAPABILITY_LOGGING` | Override payload-free local callback logging (`1`/`0`; default off) |
|
|
263
|
+
| `CAIRN_CAPABILITY_MEMORY_WRITE` | Override `memory.write` for this process |
|
|
264
|
+
| `CAIRN_CAPABILITY_MEMORY_SEARCH` | Override `memory.search` for this process |
|
|
265
|
+
| `CAIRN_CAPABILITY_NOTES_DISTILL` | Override `notes.distill` for this process |
|
|
266
|
+
| `CAIRN_CAPABILITY_WIKI` | Override `wiki` for this process |
|
|
267
|
+
| `CAIRN_CAPABILITY_GRAPH` | Override `graph` for this process |
|
|
268
|
+
| `CAIRN_CAPABILITY_SECURITY_AUDIT` | Override `security.audit` for this process |
|
|
269
|
+
| `CAIRN_CAPABILITY_ROUTE_CHECK` | Override `route.check` for this process |
|
|
270
|
+
| `CAIRN_CAPABILITY_CONTEXT_EXPLORE` | Override `context.explore` for this process |
|
|
271
|
+
| `CAIRN_EVAL` | Opt in to the local evaluation coordinator (default off; does not select a harness, model, endpoint, credential, or network) |
|
|
191
272
|
| `CAIRN_GIT_PROVIDER` | Git host for collaboration commands: `github`\|`gitlab`\|`codeberg`\|`forgejo`\|`none` ([docs/git-providers.md](docs/git-providers.md)) |
|
|
192
273
|
| `CAIRN_ROUTE_ENDPOINT` | Base URL of an already-running token-miser routing/tiering proxy (unset → `route_check` is inert) |
|
|
193
274
|
| `CAIRN_EXPLORE_BINARY` | Absolute path to the `token_miser` binary used by `context_explore` (unset → the tool throws) |
|
|
@@ -203,6 +284,151 @@ remote memory, and delegated exploration can send content to endpoints you
|
|
|
203
284
|
configure. Review [Privacy and data flow](docs/privacy-and-data-flow.md) before
|
|
204
285
|
enabling them.
|
|
205
286
|
|
|
287
|
+
### Managed capability contract (opt-in)
|
|
288
|
+
|
|
289
|
+
`CAIRN_CAPABILITY_CONTRACT=1` enables one versioned, typed boundary around the
|
|
290
|
+
existing capability owners. The master flag and callback logging are both off
|
|
291
|
+
by default. With the master flag unset, MCP registration, installed
|
|
292
|
+
Markdown/workflow bytes, commands, processes, configuration reads, logging,
|
|
293
|
+
output, and performance remain on the legacy path.
|
|
294
|
+
|
|
295
|
+
| Capability ID | Kind | Existing owner | Compatibility default | Process override |
|
|
296
|
+
|---|---|---|---:|---|
|
|
297
|
+
| `memory.write` | MCP tool | `memory_write` | on | `CAIRN_CAPABILITY_MEMORY_WRITE` |
|
|
298
|
+
| `memory.search` | MCP tool | `memory_search` | on | `CAIRN_CAPABILITY_MEMORY_SEARCH` |
|
|
299
|
+
| `notes.distill` | offline job | note distillation CLI/timer | off | `CAIRN_CAPABILITY_NOTES_DISTILL` |
|
|
300
|
+
| `wiki` | operating workflow | installed wiki commands/workflows | on | `CAIRN_CAPABILITY_WIKI` |
|
|
301
|
+
| `graph` | operating workflow | installed graph commands | inherited from `graphify.enabled`, otherwise off | `CAIRN_CAPABILITY_GRAPH` |
|
|
302
|
+
| `security.audit` | operating workflow | installed security commands/workflows | on | `CAIRN_CAPABILITY_SECURITY_AUDIT` |
|
|
303
|
+
| `route.check` | MCP tool | existing token-miser routing delegate | on | `CAIRN_CAPABILITY_ROUTE_CHECK` |
|
|
304
|
+
| `context.explore` | MCP tool | existing token-miser exploration delegate | on | `CAIRN_CAPABILITY_CONTEXT_EXPLORE` |
|
|
305
|
+
|
|
306
|
+
Manage project overrides in `.ai/capabilities.json` through the CLI rather than
|
|
307
|
+
editing JSON:
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities list
|
|
311
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities status --json
|
|
312
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities disable context.explore
|
|
313
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities reset context.explore
|
|
314
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities logging enable
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Process overrides take precedence over project values, which take precedence
|
|
318
|
+
over compatibility defaults. `reset` removes an explicit override and restores
|
|
319
|
+
the inherited state; it does not mean enabled. Changes to the four MCP
|
|
320
|
+
capabilities (`memory.write`, `memory.search`, `route.check`, and
|
|
321
|
+
`context.explore`) require a fresh memory-server start and disabled tools are
|
|
322
|
+
omitted from `tools/list`. Offline and operating workflows resolve state at
|
|
323
|
+
each invocation. Enabling the master does not enable `notes.distill` or graph
|
|
324
|
+
when their compatibility inputs remain off.
|
|
325
|
+
|
|
326
|
+
Callback records are local, payload-free operating evidence, not evaluation
|
|
327
|
+
results or telemetry. They require the contract, callback logging, and local
|
|
328
|
+
trajectory capture to be enabled together. Cairnkeep makes no capability gain,
|
|
329
|
+
memory-quality, or efficiency claim from this instrumentation; Phase 19 must
|
|
330
|
+
first create an explicit all-enabled baseline and measure one-disabled states.
|
|
331
|
+
See the [operating guide](docs/operating.md#managed-capability-contract-opt-in),
|
|
332
|
+
[storage contract](docs/storage.md#capability-callback-storage), and
|
|
333
|
+
[privacy flow](docs/privacy-and-data-flow.md#capability-callback-flow).
|
|
334
|
+
|
|
335
|
+
### Evaluation harness (opt-in, measurement only)
|
|
336
|
+
|
|
337
|
+
`CAIRN_EVAL=1` enables `cairn eval` for a committed schema-v1 task set and an
|
|
338
|
+
explicit operator-owned adapter program. `validate` resolves immutable inputs,
|
|
339
|
+
limits, commands, digests, output containment, and a deterministic serial
|
|
340
|
+
schedule without invoking the adapter. `run` measures from-scratch Run 1 versus
|
|
341
|
+
a fresh Run 2 that can see only its own task's immutable note snapshot.
|
|
342
|
+
`ablate` measures an explicit all-eight-capabilities-on baseline against one
|
|
343
|
+
exactly-one-disabled treatment, with both passes in both arms. Execution prints
|
|
344
|
+
the invocation estimate and requires `--yes`; there is no retry, inference,
|
|
345
|
+
provider, endpoint, credential, model, or network default.
|
|
346
|
+
|
|
347
|
+
The canonical local JSON report records optional reported turns/tokens/cost,
|
|
348
|
+
independently verified pass state, full and note-eligible populations,
|
|
349
|
+
missingness, paired deltas, capability/notes/revision digests, and seeded
|
|
350
|
+
bootstrap uncertainty. Turns compare only under exact matching turn-semantics
|
|
351
|
+
compatibility IDs; token totals are never inferred and unknown verifier results
|
|
352
|
+
are never counted as pass or fail. Reports describe estimates and
|
|
353
|
+
inconclusive/small-sample conditions; they do not claim causality,
|
|
354
|
+
significance, quality change, or efficiency change.
|
|
355
|
+
|
|
356
|
+
The bundled fake task set and adapter are deterministic, offline framework
|
|
357
|
+
fixtures. They cannot support a Cairnkeep performance statement. Any future
|
|
358
|
+
efficiency statement requires a separate committed `live-evaluation` artifact
|
|
359
|
+
whose source, task-set, report, schema, note-snapshot, missingness, runtime, and
|
|
360
|
+
claim anchors all pass `scripts/verify-phase19-runtime-evidence.mjs`. No such
|
|
361
|
+
live claim or evidence artifact is shipped here, and external paper calibration
|
|
362
|
+
is neither a Cairnkeep result nor an acceptance target.
|
|
363
|
+
|
|
364
|
+
Reports and note snapshots stay under
|
|
365
|
+
`.agentfs/eval/experiments/<experiment-id>/`; default uninstall retains them,
|
|
366
|
+
while explicit purge is backup-first and revertible. Cancellation retains an
|
|
367
|
+
inspectable partial report. POSIX process-group cleanup is tested; Windows
|
|
368
|
+
descendant-process-tree termination is not guaranteed. See the
|
|
369
|
+
[operating guide](docs/operating.md#evaluation-harness-opt-in),
|
|
370
|
+
[storage contract](docs/storage.md#evaluation-report-and-note-snapshot-storage),
|
|
371
|
+
and [privacy flow](docs/privacy-and-data-flow.md#evaluation-adapter-and-report-flow).
|
|
372
|
+
|
|
373
|
+
### Typed memory nodes and structured import (opt-in)
|
|
374
|
+
|
|
375
|
+
`CAIRN_TYPED_MEMORY_NODES=1` adds schema-v1 `node_type`, canonical `tags`,
|
|
376
|
+
`address_space`, hard list/search filters (`node_types`, `tags_all`,
|
|
377
|
+
`tags_any`), and exactly one new MCP tool: `memory_import`. The flag is read
|
|
378
|
+
when each server/session is created, so restart after changing it. Unset keeps
|
|
379
|
+
the existing 14 tools, schemas, response roots, raw values, files, processes,
|
|
380
|
+
network behavior, and output unchanged. It adds no read/edit/update/delete
|
|
381
|
+
aliases; `memory_supersede` remains the sole edit operation.
|
|
382
|
+
|
|
383
|
+
Core types are `memory`, `knowledge`, `hindsight`, `shared`, and `provenance`;
|
|
384
|
+
extensions use a namespaced form such as `team:runbook`. Tags are ASCII
|
|
385
|
+
lowercase, with whitespace and underscores normalized to hyphens, deduplicated,
|
|
386
|
+
and sorted. Filters are applied before ranking. Exact key/tag/type hits precede
|
|
387
|
+
semantic results; without a working configured embedding endpoint, search uses
|
|
388
|
+
stable local substring matching.
|
|
389
|
+
|
|
390
|
+
`memory_import` accepts one inline schema-v1 batch for one concrete scope and
|
|
391
|
+
one `memory`, `project-notes`, or `shared-notes` address. It supports 1–256
|
|
392
|
+
unique relative keys, values up to 256 KiB each and 5 MiB total, optional
|
|
393
|
+
`import_id`, `dry_run`, and `conflict_policy: reject|supersede`. Results contain
|
|
394
|
+
only digests, counts, keys, and actions—never supplied values. The default
|
|
395
|
+
reject policy cannot overwrite; explicit supersede preserves typed history.
|
|
396
|
+
Note addresses require `scope: project` and logical keys, never filesystem
|
|
397
|
+
paths. See the [operating guide](docs/operating.md#typed-memory-nodes-and-note-address-spaces-opt-in).
|
|
398
|
+
|
|
399
|
+
### Compaction continuity and artifacts (opt-in)
|
|
400
|
+
|
|
401
|
+
`CAIRN_COMPACTION_CAPTURE=1` captures only harness-produced compaction summaries
|
|
402
|
+
from the pinned Claude Code `PostCompact` 2.1.219 and 2.1.220 payloads and
|
|
403
|
+
OpenCode `session.compacted` 1.17.20 seam. It stores redacted immutable revisions locally and injects the latest
|
|
404
|
+
valid structured goals, decisions, TODOs, and critical errors when a session
|
|
405
|
+
starts. A resumed session is preferred; a fresh session falls back to the
|
|
406
|
+
newest valid project summary and marks stale context for validation. The raw
|
|
407
|
+
redacted summary is available only through an explicit read. Cairnkeep never
|
|
408
|
+
generates or triggers compaction.
|
|
409
|
+
|
|
410
|
+
`CAIRN_ARTIFACT_STORE=1` independently exposes exactly four stdio MCP tools:
|
|
411
|
+
`artifact_write`, `artifact_read`, `artifact_list`, and `artifact_delete`.
|
|
412
|
+
The initial kinds are exactly `compaction_summary`, `diff`, `test_output`, and
|
|
413
|
+
`generated_file`. Generated-file paths are labels only; the server never reads
|
|
414
|
+
them. Operators can inspect retained local data whether or not MCP writes are
|
|
415
|
+
currently enabled:
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
cairn artifact list --kind compaction_summary --json
|
|
419
|
+
cairn artifact show ARTIFACT-ID --json
|
|
420
|
+
cairn artifact delete ARTIFACT-ID --dry-run --json
|
|
421
|
+
cairn artifact prune --dry-run --include-protected --json
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Both capabilities are default-off, local, and require no key, model, endpoint,
|
|
425
|
+
telemetry, or network. Remote tools require double consent:
|
|
426
|
+
`CAIRN_ARTIFACT_STORE=1` plus `CAIRN_ARTIFACT_HTTP=1`, as well as the existing
|
|
427
|
+
bearer, `Host`, and validated `X-Cairn-Project` controls. Artifact HTTP never
|
|
428
|
+
exposes trajectory data. See the [operating guide](docs/operating.md#compaction-continuity-and-artifacts-opt-in),
|
|
429
|
+
[storage contract](docs/storage.md#artifact-storage), and
|
|
430
|
+
[privacy flows](docs/privacy-and-data-flow.md#compaction-and-artifact-flows).
|
|
431
|
+
|
|
206
432
|
## More
|
|
207
433
|
|
|
208
434
|
- **Guided learning paths and video scripts** — [docs/learning/README.md](docs/learning/README.md)
|
package/bin/cairn
CHANGED
|
@@ -32,8 +32,30 @@ Usage:
|
|
|
32
32
|
Install/update the Claude Code operating layer (commands,
|
|
33
33
|
agents, hooks) into ~/.claude, or into DIR for a single
|
|
34
34
|
project (--live-root <project>/.claude).
|
|
35
|
+
cairn sync-pi [--apply] [--live-root DIR]
|
|
36
|
+
Install/update the Pi trajectory extension into
|
|
37
|
+
~/.pi/agent, or into DIR for an isolated Pi root.
|
|
35
38
|
cairn doctor Health-check the memory server and configured LLM /
|
|
36
|
-
embedding endpoints, git provider, and
|
|
39
|
+
embedding endpoints, git provider, and stores.
|
|
40
|
+
Use --repair for derived trajectory/typed metadata,
|
|
41
|
+
indexes, and interrupted note transactions.
|
|
42
|
+
cairn trajectory <list|show|prune>
|
|
43
|
+
Inspect and prune opt-in local session trajectories.
|
|
44
|
+
cairn artifact <list|show|delete|prune>
|
|
45
|
+
Inspect and delete opt-in local artifacts. List/show
|
|
46
|
+
support --json; delete supports --dry-run; prune
|
|
47
|
+
supports --dry-run and --include-protected.
|
|
48
|
+
cairn capabilities <list|status|enable|disable|reset|logging>
|
|
49
|
+
Inspect and manage project capability state. MCP changes
|
|
50
|
+
require a memory-server restart; operating changes apply
|
|
51
|
+
on the next invocation.
|
|
52
|
+
cairn notes <distill|search-error|promote|doctor>
|
|
53
|
+
Compile closed trajectories into local hindsight notes,
|
|
54
|
+
search exact failure signatures, promote corroborated
|
|
55
|
+
notes, or validate the note store.
|
|
56
|
+
cairn eval <validate|run|ablate|report|prune|delete>
|
|
57
|
+
Validate or run default-off local evaluations, inspect
|
|
58
|
+
reports, and manage retained experiment results.
|
|
37
59
|
cairn memory <path|export|import>
|
|
38
60
|
Relocate global-scope memory. `path` prints its location;
|
|
39
61
|
`export <file.tgz>` takes a WAL-safe snapshot (requires
|
|
@@ -41,7 +63,8 @@ Usage:
|
|
|
41
63
|
cairn audit-timer [--on-calendar SPEC] [--para-root PATH] [--render-only DIR]
|
|
42
64
|
Install (opt-in) a systemd user timer that runs the
|
|
43
65
|
memory+wiki audit on a schedule; prints a cron alternative.
|
|
44
|
-
cairn uninstall [--dry-run] [--yes] [--purge-memory] [--live-root DIR]
|
|
66
|
+
cairn uninstall [--dry-run] [--yes] [--purge-memory] [--live-root DIR]
|
|
67
|
+
[--pi-live-root DIR] [PROJECT ...]
|
|
45
68
|
Reverse what cairnkeep installed/modified (operating
|
|
46
69
|
layer, hook registrations, MCP registration, audit
|
|
47
70
|
timer, and any given projects' bootstrap scaffold).
|
|
@@ -72,9 +95,27 @@ case "$cmd" in
|
|
|
72
95
|
# claude mcp add cairn-memory -s user -- cairn memory-server
|
|
73
96
|
exec node "$CAIRN_ROOT/mcp-memory-server/dist/index.js" "$@"
|
|
74
97
|
;;
|
|
98
|
+
trajectory)
|
|
99
|
+
exec node "$CAIRN_ROOT/mcp-memory-server/dist/trajectory-cli.js" "$@"
|
|
100
|
+
;;
|
|
101
|
+
artifact)
|
|
102
|
+
exec node "$CAIRN_ROOT/mcp-memory-server/dist/artifact-cli.js" "$@"
|
|
103
|
+
;;
|
|
104
|
+
capabilities)
|
|
105
|
+
exec node "$CAIRN_ROOT/mcp-memory-server/dist/capability-cli.js" "$@"
|
|
106
|
+
;;
|
|
107
|
+
notes)
|
|
108
|
+
exec node "$CAIRN_ROOT/mcp-memory-server/dist/note-cli.js" "$@"
|
|
109
|
+
;;
|
|
110
|
+
eval)
|
|
111
|
+
exec node "$CAIRN_ROOT/mcp-memory-server/dist/eval-cli.js" "$@"
|
|
112
|
+
;;
|
|
75
113
|
sync)
|
|
76
114
|
exec "$CAIRN_ROOT/scripts/sync-claude-assets.sh" "$@"
|
|
77
115
|
;;
|
|
116
|
+
sync-pi)
|
|
117
|
+
exec "$CAIRN_ROOT/scripts/sync-pi-assets.sh" "$@"
|
|
118
|
+
;;
|
|
78
119
|
audit-timer)
|
|
79
120
|
exec "$CAIRN_ROOT/scripts/install-audit-timer.sh" "$@"
|
|
80
121
|
;;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Stop/StopFailure/CwdChanged/SessionEnd hook: lifecycle settlement transport.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
case "${CAIRN_CAPABILITY_CONTRACT:-}" in
|
|
6
|
+
1|true|TRUE|yes|YES|on|ON) ;;
|
|
7
|
+
*) exit 0 ;;
|
|
8
|
+
esac
|
|
9
|
+
|
|
10
|
+
INFRA_ROOT="@@INFRA_ROOT@@"
|
|
11
|
+
COORDINATOR="$INFRA_ROOT/mcp-memory-server/dist/capability-cli.js"
|
|
12
|
+
[ -f "$COORDINATOR" ] || exit 0
|
|
13
|
+
|
|
14
|
+
input=$(cat) || exit 0
|
|
15
|
+
validated=$(printf '%s' "$input" | python3 /dev/fd/3 3<<'PY'
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
common = {"session_id", "transcript_path", "cwd", "hook_event_name"}
|
|
21
|
+
optional = {"prompt_id", "permission_mode", "effort", "agent_id", "agent_type"}
|
|
22
|
+
shapes = {
|
|
23
|
+
"Stop": ({"stop_hook_active", "last_assistant_message", "background_tasks", "session_crons"}, set()),
|
|
24
|
+
"StopFailure": ({"error"}, {"error_details", "last_assistant_message"}),
|
|
25
|
+
"CwdChanged": ({"old_cwd", "new_cwd"}, set()),
|
|
26
|
+
"SessionEnd": ({"reason"}, set()),
|
|
27
|
+
}
|
|
28
|
+
errors = {
|
|
29
|
+
"rate_limit", "overloaded", "authentication_failed", "oauth_org_not_allowed",
|
|
30
|
+
"billing_error", "invalid_request", "model_not_found", "server_error",
|
|
31
|
+
"max_output_tokens", "unknown",
|
|
32
|
+
}
|
|
33
|
+
reasons = {"clear", "resume", "logout", "prompt_input_exit", "bypass_permissions_disabled", "other"}
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
value = json.load(sys.stdin)
|
|
37
|
+
if not isinstance(value, dict) or not common <= set(value):
|
|
38
|
+
raise ValueError
|
|
39
|
+
event = value["hook_event_name"]
|
|
40
|
+
if event not in shapes:
|
|
41
|
+
raise ValueError
|
|
42
|
+
event_required, event_optional = shapes[event]
|
|
43
|
+
required = common | event_required
|
|
44
|
+
if not required <= set(value) or set(value) - required - optional - event_optional:
|
|
45
|
+
raise ValueError
|
|
46
|
+
for name in ("session_id", "transcript_path", "cwd"):
|
|
47
|
+
if not isinstance(value[name], str):
|
|
48
|
+
raise ValueError
|
|
49
|
+
session = value["session_id"]
|
|
50
|
+
if not isinstance(session, str) or not re.fullmatch(r"(?:cairn:)?[A-Za-z0-9][A-Za-z0-9._:-]{0,255}", session) or session == "unknown":
|
|
51
|
+
raise ValueError
|
|
52
|
+
if event == "Stop":
|
|
53
|
+
if not isinstance(value["stop_hook_active"], bool) or not isinstance(value["last_assistant_message"], str):
|
|
54
|
+
raise ValueError
|
|
55
|
+
if not isinstance(value["background_tasks"], list) or not isinstance(value["session_crons"], list):
|
|
56
|
+
raise ValueError
|
|
57
|
+
operation, body = "harness-terminal", {"outcome": "success"}
|
|
58
|
+
elif event == "StopFailure":
|
|
59
|
+
if value["error"] not in errors:
|
|
60
|
+
raise ValueError
|
|
61
|
+
operation, body = "harness-terminal", {"outcome": "error"}
|
|
62
|
+
elif event == "SessionEnd":
|
|
63
|
+
if value["reason"] not in reasons:
|
|
64
|
+
raise ValueError
|
|
65
|
+
operation, body = "harness-terminal", {"outcome": "abandoned"}
|
|
66
|
+
else:
|
|
67
|
+
if not isinstance(value["old_cwd"], str) or not isinstance(value["new_cwd"], str):
|
|
68
|
+
raise ValueError
|
|
69
|
+
operation, body = "harness-cwd", {"old_cwd": value["old_cwd"], "new_cwd": value["new_cwd"]}
|
|
70
|
+
body.update({"schema_version": 1, "harness": "claude-code", "session_id": session})
|
|
71
|
+
print(operation)
|
|
72
|
+
print(json.dumps(body, separators=(",", ":")))
|
|
73
|
+
except Exception:
|
|
74
|
+
sys.exit(1)
|
|
75
|
+
PY
|
|
76
|
+
) || exit 0
|
|
77
|
+
|
|
78
|
+
operation=${validated%%$'\n'*}
|
|
79
|
+
payload=${validated#*$'\n'}
|
|
80
|
+
printf '%s' "$payload" | node "$COORDINATOR" "$operation" >/dev/null 2>&1 || true
|
|
81
|
+
exit 0
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# UserPromptExpansion hook: deterministic operating-capability admission.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
case "${CAIRN_CAPABILITY_CONTRACT:-}" in
|
|
6
|
+
1|true|TRUE|yes|YES|on|ON) ;;
|
|
7
|
+
*) printf '{}\n'; exit 0 ;;
|
|
8
|
+
esac
|
|
9
|
+
|
|
10
|
+
INFRA_ROOT="@@INFRA_ROOT@@"
|
|
11
|
+
COORDINATOR="$INFRA_ROOT/mcp-memory-server/dist/capability-cli.js"
|
|
12
|
+
FIXED_BLOCK='{"decision":"block","reason":"capability disabled"}'
|
|
13
|
+
|
|
14
|
+
block() {
|
|
15
|
+
printf '%s\n' "$FIXED_BLOCK"
|
|
16
|
+
exit 2
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[ -f "$COORDINATOR" ] || block
|
|
20
|
+
input=$(cat) || block
|
|
21
|
+
|
|
22
|
+
validated=$(printf '%s' "$input" | python3 /dev/fd/3 "$PWD" 3<<'PY'
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import re
|
|
26
|
+
import sys
|
|
27
|
+
|
|
28
|
+
required = {
|
|
29
|
+
"session_id", "transcript_path", "cwd", "hook_event_name",
|
|
30
|
+
"expansion_type", "command_name", "command_args", "command_source", "prompt",
|
|
31
|
+
}
|
|
32
|
+
optional = {"prompt_id", "permission_mode", "effort", "agent_id", "agent_type"}
|
|
33
|
+
commands = {"wiki-ingest", "wiki-query", "wiki-lint", "graphify", "security-audit"}
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
value = json.load(sys.stdin)
|
|
37
|
+
if not isinstance(value, dict) or set(value) - required - optional or not required <= set(value):
|
|
38
|
+
raise ValueError
|
|
39
|
+
if value["hook_event_name"] != "UserPromptExpansion":
|
|
40
|
+
raise ValueError
|
|
41
|
+
if value["expansion_type"] not in {"slash_command", "mcp_prompt"}:
|
|
42
|
+
raise ValueError
|
|
43
|
+
if value["command_name"] not in commands:
|
|
44
|
+
raise ValueError
|
|
45
|
+
for name in required - {"hook_event_name", "expansion_type"}:
|
|
46
|
+
if not isinstance(value[name], str):
|
|
47
|
+
raise ValueError
|
|
48
|
+
session = value["session_id"]
|
|
49
|
+
if not isinstance(session, str) or not re.fullmatch(r"(?:cairn:)?[A-Za-z0-9][A-Za-z0-9._:-]{0,255}", session) or session == "unknown":
|
|
50
|
+
raise ValueError
|
|
51
|
+
event_root = os.path.realpath(value["cwd"])
|
|
52
|
+
process_root = os.path.realpath(sys.argv[1])
|
|
53
|
+
if not os.path.isabs(value["cwd"]) or event_root != process_root or not os.path.isdir(event_root):
|
|
54
|
+
raise ValueError
|
|
55
|
+
print(json.dumps({
|
|
56
|
+
"schema_version": 1,
|
|
57
|
+
"harness": "claude-code",
|
|
58
|
+
"command": value["command_name"],
|
|
59
|
+
"session_id": session,
|
|
60
|
+
"project_root": event_root,
|
|
61
|
+
}, separators=(",", ":")))
|
|
62
|
+
except Exception:
|
|
63
|
+
sys.exit(1)
|
|
64
|
+
PY
|
|
65
|
+
) || block
|
|
66
|
+
|
|
67
|
+
decision=$(printf '%s' "$validated" | node "$COORDINATOR" harness-before 2>/dev/null) || {
|
|
68
|
+
printf '{}\n'
|
|
69
|
+
exit 0
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
case "$decision" in
|
|
73
|
+
'{"schema_version":1,"decision":"block","reason":"capability-disabled"}') block ;;
|
|
74
|
+
'{"schema_version":1,"decision":"allow"}') printf '{}\n' ;;
|
|
75
|
+
*) printf '{}\n' ;;
|
|
76
|
+
esac
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PostCompact hook: persist the harness-produced compaction summary locally.
|
|
3
|
+
# The hook never generates or changes a summary and always fails open.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
case "${CAIRN_COMPACTION_CAPTURE:-}" in
|
|
7
|
+
1|true|TRUE|yes|YES|on|ON) ;;
|
|
8
|
+
*) exit 0 ;;
|
|
9
|
+
esac
|
|
10
|
+
|
|
11
|
+
repo="$(pwd)"
|
|
12
|
+
ARTIFACT_ENTRY="@@INFRA_ROOT@@/mcp-memory-server/dist/artifact-cli.js"
|
|
13
|
+
[ -f "$ARTIFACT_ENTRY" ] || exit 0
|
|
14
|
+
|
|
15
|
+
# The payload has no version field. Resolve the running harness locally so an
|
|
16
|
+
# unpinned future shape cannot be accepted merely because its keys look known.
|
|
17
|
+
harness_version=$(claude --version 2>/dev/null | sed -nE 's/[^0-9]*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' | head -1)
|
|
18
|
+
[ -n "$harness_version" ] || harness_version=unknown
|
|
19
|
+
|
|
20
|
+
# Forward the documented PostCompact payload unchanged. The local CLI owns
|
|
21
|
+
# shape validation, redaction, and persistence; this boundary stays bounded
|
|
22
|
+
# and cannot block or fail the harness event.
|
|
23
|
+
node "$ARTIFACT_ENTRY" capture-claude "$repo" --harness-version "$harness_version" <&0 >/dev/null 2>&1 &
|
|
24
|
+
capture_pid=$!
|
|
25
|
+
(
|
|
26
|
+
sleep 3
|
|
27
|
+
kill -KILL "$capture_pid" >/dev/null 2>&1 || true
|
|
28
|
+
) &
|
|
29
|
+
watchdog_pid=$!
|
|
30
|
+
wait "$capture_pid" >/dev/null 2>&1 || true
|
|
31
|
+
kill "$watchdog_pid" >/dev/null 2>&1 || true
|
|
32
|
+
wait "$watchdog_pid" >/dev/null 2>&1 || true
|
|
33
|
+
|
|
34
|
+
exit 0
|