@cairnkeep/cli 2.3.0 → 2.4.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 +78 -0
- package/README.md +221 -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 +1 -1
- package/docs/design/meta-agent.md +439 -0
- package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
- package/docs/learning/lessons/L01-safe-trial.md +3 -3
- package/docs/learning/lessons/L02-installation.md +2 -2
- package/docs/learning/lessons/L03-first-project.md +1 -1
- package/docs/operating.md +531 -4
- 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 +9 -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 +4 -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 +48 -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 +602 -3
- package/scripts/test-notes-cli.sh +114 -0
- package/scripts/test-package-install.sh +251 -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 +37 -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-opencode.sh.template +47 -5
- package/templates/start-pi.sh.template +30 -0
- package/templates/trajectory-redaction.json.template +4 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Quickstart
|
|
5
5
|
**Time:** 25 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.
|
|
6
|
+
**Tested with:** Cairnkeep 2.4.0 and Node.js 22 or newer
|
|
7
7
|
|
|
8
8
|
## Outcome
|
|
9
9
|
|
|
@@ -40,7 +40,7 @@ machine-level steps.
|
|
|
40
40
|
2. Install Cairnkeep:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
npm install --global @cairnkeep/cli@2.
|
|
43
|
+
npm install --global @cairnkeep/cli@2.4.0
|
|
44
44
|
cairn --version
|
|
45
45
|
```
|
|
46
46
|
|
package/docs/operating.md
CHANGED
|
@@ -17,7 +17,7 @@ installs. This guide covers all three in order.
|
|
|
17
17
|
## Prerequisites
|
|
18
18
|
|
|
19
19
|
- Node.js 22 or newer (for the memory server) and a supported harness: Claude
|
|
20
|
-
Code or
|
|
20
|
+
Code, OpenCode, or Pi.
|
|
21
21
|
- Optional: the `sqlite3` CLI for `cairn memory export`. Runtime memory and
|
|
22
22
|
`cairn memory import` do not require it.
|
|
23
23
|
- Optional: an OpenAI-compatible LLM endpoint for memory extraction and
|
|
@@ -93,11 +93,15 @@ Step 3 installs into `~/.claude` (override with `CLAUDE_CONFIG_DIR` or
|
|
|
93
93
|
`repo-review`, `graphify`, `context-explore`
|
|
94
94
|
- **7 agents** → `agents/`: `code-reviewer`, the three `security-*` agents, and
|
|
95
95
|
the three `wiki-*` agents
|
|
96
|
-
- **
|
|
96
|
+
- **5 hooks** → `hooks/`, registered in `settings.json`:
|
|
97
97
|
- `memory-wakeup.sh` on **SessionStart** — surfaces AgentFS memory + wiki index
|
|
98
98
|
- `memory-capture.sh` on **SessionEnd** — extracts memory candidates to staging
|
|
99
99
|
- `memory-recall.sh` on **PreToolUse** (Edit/Write/MultiEdit) — injects
|
|
100
100
|
file-specific memory before an edit
|
|
101
|
+
- `context-explore-pretask.sh` on **UserPromptSubmit** — inert unless the
|
|
102
|
+
separate context-exploration opt-in is enabled
|
|
103
|
+
- `compaction-capture.sh` on **PostCompact** — inert unless local compaction
|
|
104
|
+
continuity is enabled
|
|
101
105
|
- **scaffold templates** → `templates/`, used by `/security-audit` and `/wiki-*`
|
|
102
106
|
|
|
103
107
|
Re-running `sync-claude-assets.sh --apply` is idempotent; use `--check` to see
|
|
@@ -121,7 +125,7 @@ OpenCode is a secondary path. Steps 1, 4, and 5 are identical (use
|
|
|
121
125
|
The operating-layer assets are installed by topic-specific scripts:
|
|
122
126
|
|
|
123
127
|
```bash
|
|
124
|
-
scripts/sync-opencode-plugin-assets.sh --apply # memory
|
|
128
|
+
scripts/sync-opencode-plugin-assets.sh --apply # memory wakeup/capture/recall plugins
|
|
125
129
|
scripts/sync-opencode-memory-assets.sh --apply # memory-sync/review + code-review
|
|
126
130
|
scripts/sync-opencode-wiki-assets.sh --apply # wiki commands/agents/workflows
|
|
127
131
|
scripts/sync-opencode-security-assets.sh --apply # security-audit chain
|
|
@@ -153,6 +157,33 @@ Model selection stays operator-env-driven through the existing
|
|
|
153
157
|
variables (see "Configuration" below) — the harness commits no default model
|
|
154
158
|
and carries no known-good allowlist.
|
|
155
159
|
|
|
160
|
+
## Setup order (Pi)
|
|
161
|
+
|
|
162
|
+
Pi trajectory capture uses the same project scaffold and store, but its source
|
|
163
|
+
is a native TypeScript extension installed into Pi's agent root:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm install -g @cairnkeep/cli
|
|
167
|
+
cairn sync-pi --apply # default: ~/.pi/agent
|
|
168
|
+
cairn bootstrap /path/to/project
|
|
169
|
+
cp /path/to/project/.ai/env.example /path/to/project/.ai/.env
|
|
170
|
+
cd /path/to/project && cairn doctor && ./.ai/start-pi.sh
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
This command does not install an MCP bridge. Cairnkeep does not own or select a
|
|
174
|
+
Pi bridge; if you want `cairn memory-server` tools inside Pi as well, configure
|
|
175
|
+
a user-chosen Pi extension/bridge separately.
|
|
176
|
+
|
|
177
|
+
Use `cairn sync-pi --check` to report drift without writing, or
|
|
178
|
+
`--live-root DIR` to target an isolated Pi agent root. The command owns exactly
|
|
179
|
+
`extensions/cairnkeep-trajectory.ts`; `cairn uninstall --pi-live-root DIR`
|
|
180
|
+
removes that file backup-first and leaves every other Pi asset untouched.
|
|
181
|
+
|
|
182
|
+
The extension listens for Pi's native `session_shutdown` event and reads only
|
|
183
|
+
the active branch from the read-only session manager. It returns before doing
|
|
184
|
+
that work unless `CAIRN_TRAJECTORY_CAPTURE` is explicitly enabled. Capture is
|
|
185
|
+
local, fail-open, and capped at three seconds so it cannot hold Pi open.
|
|
186
|
+
|
|
156
187
|
Before burning a multi-run soak, a preflight probe drives one real tool call
|
|
157
188
|
and fails fast with a trait-named message if the configured model is not
|
|
158
189
|
tool-call-reliable. The harness keeps a three-tier speed structure:
|
|
@@ -175,6 +206,38 @@ vendor or host.
|
|
|
175
206
|
| `CAIRN_MEMORY_EMBEDDING_MODEL` | Embedding model name (required for semantic search) |
|
|
176
207
|
| `CAIRN_MEMORY_EMBEDDING_TIMEOUT_MS` | Embedding request timeout before substring fallback (default `15000`) |
|
|
177
208
|
| `CAIRN_AGENTFS_BASE_DIR` | Server-side base dir for named/global memory scopes (default `~/.cairnkeep`); it does not affect `project` scope |
|
|
209
|
+
| `CAIRN_TRAJECTORY_CAPTURE` | Opt in to local structured session capture (`1`, `true`, `yes`, or `on`; unset/default → no capture work) |
|
|
210
|
+
| `CAIRN_TRAJECTORY_SESSION_MAX_BYTES` | Maximum serialized bytes per session (default `5242880`, 5 MiB; minimum 1024) |
|
|
211
|
+
| `CAIRN_TRAJECTORY_STORE_MAX_BYTES` | Logical local trajectory budget (default `268435456`, 256 MiB; must be at least the session maximum) |
|
|
212
|
+
| `CAIRN_TRAJECTORY_RETENTION_DAYS` | Age retention applied on capture/prune (default `30`; `0` removes sessions once they are older than the current instant) |
|
|
213
|
+
| `CAIRN_TRAJECTORY_REDACTION_FILE` | Optional redaction JSON path contained by the project (default `.ai/trajectory-redaction.json` when that file exists) |
|
|
214
|
+
| `CAIRN_REDACTION_FILE` | Optional project-contained redaction JSON shared by trajectories and artifacts; takes precedence over `CAIRN_TRAJECTORY_REDACTION_FILE` |
|
|
215
|
+
| `CAIRN_COMPACTION_CAPTURE` | Opt in to supported local compaction capture and automatic structured recovery (off by default; unset means zero new work) |
|
|
216
|
+
| `CAIRN_ARTIFACT_STORE` | Expose the four local stdio artifact tools (off by default; independent of compaction capture) |
|
|
217
|
+
| `CAIRN_ARTIFACT_HTTP` | Separately expose artifact tools over authenticated HTTP (off by default; also requires `CAIRN_ARTIFACT_STORE`) |
|
|
218
|
+
| `CAIRN_ARTIFACT_MAX_BYTES` | Per-artifact stored-byte cap (default `1048576`, minimum `1024`) |
|
|
219
|
+
| `CAIRN_ARTIFACT_SESSION_MAX_BYTES` | Per-session logical-byte cap (default `16777216`; at least the artifact cap) |
|
|
220
|
+
| `CAIRN_ARTIFACT_STORE_MAX_BYTES` | Total logical-byte cap (default `268435456`; at least the session cap) |
|
|
221
|
+
| `CAIRN_ARTIFACT_RETENTION_DAYS` | Age retention in days (default `30`, minimum `0`) |
|
|
222
|
+
| `CAIRN_COMPACTION_MAX_REVISIONS` | Immutable compaction revisions retained per session (default `8`, minimum `1`) |
|
|
223
|
+
| `CAIRN_ARTIFACT_GENERATED_FILE_SNAPSHOT_MAX_BYTES` | Generated-file inline snapshot cap (default `262144`; effective cap is the lower of this and the artifact cap) |
|
|
224
|
+
| `CAIRN_NOTE_DISTILLATION` | Master opt-in for local one-shot/scheduled hindsight distillation and exact lookup (unset/default → disabled before I/O) |
|
|
225
|
+
| `CAIRN_NOTE_ENRICHMENT` | Separate opt-in for provider prose enrichment; credentials alone never enable it |
|
|
226
|
+
| `CAIRN_NOTE_ENRICHMENT_MODEL` | Explicit OpenAI-compatible chat model for note enrichment (no default) |
|
|
227
|
+
| `CAIRN_NOTE_ENRICHMENT_TIMEOUT_MS` | Enrichment timeout in milliseconds (default `15000`, allowed `100`–`120000`) |
|
|
228
|
+
| `CAIRN_TYPED_MEMORY_NODES` | Add typed metadata, filters, logical note address spaces, and `memory_import` (unset/default off; restart after changing) |
|
|
229
|
+
| `CAIRN_CAPABILITY_CONTRACT` | Enable the managed eight-capability contract (unset/default off) |
|
|
230
|
+
| `CAIRN_CAPABILITY_LOGGING` | Strict per-process callback-logging override (`1`/`0`; compatibility default off) |
|
|
231
|
+
| `CAIRN_CAPABILITY_MEMORY_WRITE` | Strict per-process override for `memory.write` |
|
|
232
|
+
| `CAIRN_CAPABILITY_MEMORY_SEARCH` | Strict per-process override for `memory.search` |
|
|
233
|
+
| `CAIRN_CAPABILITY_NOTES_DISTILL` | Strict per-process override for `notes.distill` |
|
|
234
|
+
| `CAIRN_CAPABILITY_WIKI` | Strict per-process override for `wiki` |
|
|
235
|
+
| `CAIRN_CAPABILITY_GRAPH` | Strict per-process override for `graph` |
|
|
236
|
+
| `CAIRN_CAPABILITY_SECURITY_AUDIT` | Strict per-process override for `security.audit` |
|
|
237
|
+
| `CAIRN_CAPABILITY_ROUTE_CHECK` | Strict per-process override for `route.check` |
|
|
238
|
+
| `CAIRN_CAPABILITY_CONTEXT_EXPLORE` | Strict per-process override for `context.explore` |
|
|
239
|
+
| `CAIRN_EVAL` | Opt in to the local evaluation coordinator (`1`, `true`, `yes`, or `on`; unset/default → stable disabled result before input reads, writes, or adapter execution) |
|
|
240
|
+
| `CAIRN_HARNESS_STATE_DIR` | Optional absolute local root for recoverable native capability leases (default `${XDG_STATE_HOME:-~/.local/state}/cairn/harness`) |
|
|
178
241
|
| `CAIRN_GIT_PROVIDER` | Git host for collaboration commands: `github`\|`gitlab`\|`codeberg`\|`forgejo`\|`none`. See [git-providers.md](git-providers.md) |
|
|
179
242
|
| `CAIRN_ROUTE_ENDPOINT` | Base URL of an already-running token-miser routing/tiering proxy (unset → the `route_check` tool is inert) |
|
|
180
243
|
| `CAIRN_EXPLORE_BINARY` | Absolute path to the `token_miser` binary used by `context_explore` (unset → the tool throws at call time) |
|
|
@@ -187,6 +250,208 @@ vendor or host.
|
|
|
187
250
|
| `CAIRN_ANYTHINGLLM_PROJECTS_FILE` | Override path to the bundled sync script's project configuration |
|
|
188
251
|
| `CAIRN_ANYTHINGLLM_STATE_FILE` | Override path to the bundled sync script's incremental state |
|
|
189
252
|
|
|
253
|
+
### Managed capability contract (opt-in)
|
|
254
|
+
|
|
255
|
+
The managed contract is a narrow state and measurement boundary around eight
|
|
256
|
+
existing owners. It adds no runtime dependency and does not move business logic
|
|
257
|
+
from the MCP server, note CLI/timer, installed workflows, or the external
|
|
258
|
+
token-miser delegates.
|
|
259
|
+
|
|
260
|
+
The canonical registry is exactly:
|
|
261
|
+
|
|
262
|
+
| ID | Kind | Owner | Compatibility default | Environment override | Restart required |
|
|
263
|
+
|---|---|---|---:|---|---:|
|
|
264
|
+
| `memory.write` | `mcp-tool` | `mcp-memory-server:index#memory_write` | on | `CAIRN_CAPABILITY_MEMORY_WRITE` | yes |
|
|
265
|
+
| `memory.search` | `mcp-tool` | `mcp-memory-server:index#memory_search` | on | `CAIRN_CAPABILITY_MEMORY_SEARCH` | yes |
|
|
266
|
+
| `notes.distill` | `offline-job` | `mcp-memory-server:note-cli#distill` | `CAIRN_NOTE_DISTILLATION`, otherwise off | `CAIRN_CAPABILITY_NOTES_DISTILL` | no |
|
|
267
|
+
| `wiki` | `operating-workflow` | `operating-layer:wiki` | on | `CAIRN_CAPABILITY_WIKI` | no |
|
|
268
|
+
| `graph` | `operating-workflow` | `operating-layer:graph` | `.planning/config.json` `graphify.enabled`, otherwise off | `CAIRN_CAPABILITY_GRAPH` | no |
|
|
269
|
+
| `security.audit` | `operating-workflow` | `operating-layer:security-audit` | on | `CAIRN_CAPABILITY_SECURITY_AUDIT` | no |
|
|
270
|
+
| `route.check` | `mcp-tool` | `mcp-memory-server:index#route_check` | on | `CAIRN_CAPABILITY_ROUTE_CHECK` | yes |
|
|
271
|
+
| `context.explore` | `mcp-tool` | `mcp-memory-server:index#context_explore` | on | `CAIRN_CAPABILITY_CONTEXT_EXPLORE` | yes |
|
|
272
|
+
|
|
273
|
+
`CAIRN_CAPABILITY_CONTRACT` is the default-off rollout gate. Master off is exact
|
|
274
|
+
legacy behavior: the launchers and sync commands preserve the legacy installed
|
|
275
|
+
assets byte-for-byte, install and invoke no capability hook or plugin, introduce
|
|
276
|
+
no capability block, and create no capability measurement state. Master on is
|
|
277
|
+
not enough to modify the normal harness root. The launcher must also select the
|
|
278
|
+
explicit `capability-overlay` mode; only that two-factor path renders the
|
|
279
|
+
isolated `.ai/capability-contract/` root and installs its native hooks/plugins.
|
|
280
|
+
Normal installed assets remain in place, and toggling never deletes
|
|
281
|
+
configuration, retained data, or installed files.
|
|
282
|
+
|
|
283
|
+
Bootstrap creates a mode-`0600` `.ai/capabilities.json` only if it is absent:
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"schema_version": 1,
|
|
288
|
+
"capabilities": {},
|
|
289
|
+
"logging": { "callbacks": false }
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Use the managed CLI; do not hand-edit the file:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities list
|
|
297
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities status
|
|
298
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities status --json
|
|
299
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities enable wiki
|
|
300
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities disable memory.search
|
|
301
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities reset memory.search
|
|
302
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities reset --all
|
|
303
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities logging enable
|
|
304
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities logging disable
|
|
305
|
+
CAIRN_CAPABILITY_CONTRACT=1 cairn capabilities logging reset
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Precedence is strict: the derived per-capability environment value (or
|
|
309
|
+
`CAIRN_CAPABILITY_LOGGING`) wins over the project value, which wins over the
|
|
310
|
+
compatibility resolver. Every derived key uses the `CAIRN_CAPABILITY_` prefix
|
|
311
|
+
followed by the uppercased ID with dots replaced by underscores. Accepted
|
|
312
|
+
values are `1|true|yes|on` and
|
|
313
|
+
`0|false|no|off`, case-insensitively. An invalid top-level value is reported
|
|
314
|
+
with a fixed value-free issue and falls directly back to compatibility; it does
|
|
315
|
+
not reveal the raw value or consult a lower project override. Unknown IDs and
|
|
316
|
+
invalid project rows are likewise reported without their values. Each bad row
|
|
317
|
+
falls back independently, so it cannot disable another capability or the
|
|
318
|
+
server.
|
|
319
|
+
|
|
320
|
+
`reset` removes the explicit override; `reset --all` clears every capability
|
|
321
|
+
and logging override. The returned schema-v1 status orders all eight rows and
|
|
322
|
+
reports `enabled`, `source` (`environment`, `project`, or `compatibility`),
|
|
323
|
+
`restart_required`, contract/logging state, fixed issue codes, and the SHA-256
|
|
324
|
+
`configuration_digest` of the canonical effective snapshot. The digest is
|
|
325
|
+
evidence, not a signature or secret. MCP state is resolved once before server
|
|
326
|
+
registration, so changes to `memory.write`, `memory.search`, `route.check`, or
|
|
327
|
+
`context.explore` require a new server start; a disabled tool is omitted from
|
|
328
|
+
`tools/list`. Notes and operating workflows resolve current state for the next
|
|
329
|
+
invocation. Disabled notes retain the existing structured `enabled: false`
|
|
330
|
+
offline result.
|
|
331
|
+
|
|
332
|
+
Wiki covers ingest, query, and lint; graph covers its command family; security
|
|
333
|
+
audit covers its command and workflow family. There are no subcommand-level
|
|
334
|
+
switches. The four enabled MCP tools retain their exact names, schemas,
|
|
335
|
+
responses, timeout/error behavior, and owners. In particular, `route_check`
|
|
336
|
+
and `context_explore` remain thin token-miser delegates; Cairnkeep does not gain
|
|
337
|
+
endpoint, model, tier, sandbox, or inference-loop ownership.
|
|
338
|
+
|
|
339
|
+
The five operating command surfaces are still `wiki-ingest`, `wiki-query`,
|
|
340
|
+
`wiki-lint`, `graphify`, and `security-audit`. Their installed commands, agents,
|
|
341
|
+
and workflows remain the owners described by D-10, D-12, and D-16; the native
|
|
342
|
+
boundary admits or blocks an invocation and settles evidence, but does not move
|
|
343
|
+
or duplicate owner logic.
|
|
344
|
+
|
|
345
|
+
#### Native operating lifecycle
|
|
346
|
+
|
|
347
|
+
Claude Code uses two native hooks. `capability-command-start.sh` runs on
|
|
348
|
+
`UserPromptExpansion`, before command or MCP-prompt expansion can enter owner
|
|
349
|
+
I/O. It validates the exact target-command event and binds the canonical
|
|
350
|
+
project root from the event to the process root. The coordinator then creates
|
|
351
|
+
an issued recoverable lease for an eligible measured invocation. That validated
|
|
352
|
+
project identity and lease are immutable for the invocation: terminal events
|
|
353
|
+
carry neither a replacement project path nor a caller-selected handle.
|
|
354
|
+
`capability-command-finish.sh` maps `Stop` to success and maps `StopFailure`
|
|
355
|
+
immediately to an error terminal; error settlement is not deferred to
|
|
356
|
+
`SessionEnd`. `SessionEnd` performs abandonment cleanup only for unfinished
|
|
357
|
+
leases, while `CwdChanged` updates lifecycle state without rebinding the
|
|
358
|
+
start-time project.
|
|
359
|
+
|
|
360
|
+
OpenCode uses the pinned native plugin for OpenCode 1.17.20.
|
|
361
|
+
`command.execute.before` validates the target command, session, output shape,
|
|
362
|
+
and the one canonical project identity supplied at plugin initialization before
|
|
363
|
+
expansion. `session.idle` and `session.status:idle` settle success,
|
|
364
|
+
`session.error` settles error, and `session.deleted` performs abandonment
|
|
365
|
+
cleanup only for an unfinished invocation. Plugin disposal likewise abandons
|
|
366
|
+
only unfinished leases. Both harnesses settle the issued lease atomically and
|
|
367
|
+
idempotently: one terminal can win, replay cannot add another final, and
|
|
368
|
+
crash-recovery cleanup cannot rewrite a settled outcome.
|
|
369
|
+
|
|
370
|
+
The three operating states are exact. With master off, no native capability
|
|
371
|
+
owner is installed or invoked and no measurement state exists. With master on
|
|
372
|
+
and a target disabled, the native boundary returns the fixed block before owner
|
|
373
|
+
I/O regardless of measurement consent. Only when all three consents are on may
|
|
374
|
+
that block settle exactly one D-25/D-26 value-free `disabled` final through an
|
|
375
|
+
issued lease; if either measurement consent is off, it blocks with no state.
|
|
376
|
+
With master on and a target enabled, either measurement consent being off
|
|
377
|
+
preserves owner execution unchanged and creates no measurement state.
|
|
378
|
+
|
|
379
|
+
Deterministic native-boundary tests prove pinned event shapes, admission before
|
|
380
|
+
owner delegation, terminal ordering, and overlay installation. They are not
|
|
381
|
+
exhaustive live real-owner evidence. Phase 18 also requires the complete live
|
|
382
|
+
eight-by-seven matrix: eight capabilities across seven target-disabled cells,
|
|
383
|
+
56 genuine owner executions in total. Any missing, failed, or unavailable cell
|
|
384
|
+
keeps Phase 18 incomplete.
|
|
385
|
+
|
|
386
|
+
Callback logging is separately default-off. When all three consents are on
|
|
387
|
+
(`CAIRN_CAPABILITY_CONTRACT`, managed callback logging, and
|
|
388
|
+
`CAIRN_TRAJECTORY_CAPTURE`), the native boundary measures only the capability-owned
|
|
389
|
+
invocation. State is resolved first; the timer starts immediately before the
|
|
390
|
+
owned body and stops after its terminal outcome but before final presentation.
|
|
391
|
+
Discovery, configuration resolution, guard work, and unrelated harness overhead
|
|
392
|
+
are excluded. Logging is payload-free, local-only, final-only, and fail-open;
|
|
393
|
+
HTTP callbacks are never persisted. See the privacy and storage guides for the
|
|
394
|
+
exact record and retention contract.
|
|
395
|
+
|
|
396
|
+
Phase 19 must explicitly enable all eight capabilities to establish its
|
|
397
|
+
baseline before disabling one at a time. This contract records status/digest
|
|
398
|
+
and callback evidence only: it does not implement tasks, a runner, turns/tokens,
|
|
399
|
+
statistics, confidence intervals, or a quality/efficiency claim.
|
|
400
|
+
|
|
401
|
+
### Typed memory nodes and note address spaces (opt-in)
|
|
402
|
+
|
|
403
|
+
Set `CAIRN_TYPED_MEMORY_NODES=1` in the memory-server process and restart it.
|
|
404
|
+
Tool schemas are selected when `createMemoryServer` constructs a stdio server
|
|
405
|
+
or authenticated HTTP session. With the flag unset, Cairnkeep retains the
|
|
406
|
+
existing 14-tool list, required inputs, structured response roots, raw KV
|
|
407
|
+
values, files, processes, network behavior, and output. Enabled mode adds
|
|
408
|
+
optional fields to the existing lifecycle tools and exactly `memory_import`;
|
|
409
|
+
it does not add `memory_edit`, `memory_update`, `memory_remove`, or duplicate
|
|
410
|
+
read/delete tools. Use `memory_supersede` for both content and metadata edits.
|
|
411
|
+
|
|
412
|
+
Types are `memory`, `knowledge`, `hindsight`, `shared`, `provenance`, or a
|
|
413
|
+
lowercase namespaced extension such as `team:runbook`. Tags are trimmed, ASCII
|
|
414
|
+
lowercased, normalize whitespace/underscore runs to one hyphen, collapse
|
|
415
|
+
hyphens, deduplicate, and sort. `memory_list` and `memory_search` accept
|
|
416
|
+
non-empty `node_types`, `tags_all`, and `tags_any`; these are hard eligibility
|
|
417
|
+
filters applied before `top_k`, cache lookup, or embedding. Case-insensitive
|
|
418
|
+
key matches and exact canonical tag/type matches sort before semantic results.
|
|
419
|
+
Endpoint failure or absent embedding configuration falls back to stable local
|
|
420
|
+
substring matching over key, value, type, and tags.
|
|
421
|
+
|
|
422
|
+
Enabled `memory_write` without any Phase 16 field preserves collision-safe
|
|
423
|
+
legacy overwrite behavior. Supplying `address_space`, `node_type`, `tags`, or
|
|
424
|
+
`note` makes it create-only on a differing live node and returns `CONFLICT`;
|
|
425
|
+
use `memory_supersede` to preserve the complete prior value/type/tags snapshot.
|
|
426
|
+
Delete also records the complete final snapshot, and recreation is allowed.
|
|
427
|
+
|
|
428
|
+
`memory_import` takes `schema_version: 1`, one concrete `scope`, optional
|
|
429
|
+
`address_space` (default `memory`), 1–256 `nodes`, optional `import_id`,
|
|
430
|
+
`dry_run`, and `conflict_policy` (default `reject`, or explicit `supersede`).
|
|
431
|
+
Each unique logical key is a contained relative slash path; values are limited
|
|
432
|
+
to 256 KiB UTF-8 each and 5 MiB per batch. The content digest excludes retry
|
|
433
|
+
controls, while `import_id` durably binds to it. Dry-run performs no create,
|
|
434
|
+
lock, cache, journal, or mutation and returns only the digest, sorted actions,
|
|
435
|
+
and counts. Committed and replay results likewise omit values. Stable failures
|
|
436
|
+
include `INVALID_SCHEMA`, `INVALID_SCOPE`, `INVALID_PATH`, `CONFLICT`,
|
|
437
|
+
`IMPORT_ID_REUSE`, and `UNSUPPORTED_TARGET`.
|
|
438
|
+
|
|
439
|
+
`project-notes` and `shared-notes` both require `scope: project`; no named
|
|
440
|
+
memory scope is reserved. Keys such as `knowledge/build-cache` are logical,
|
|
441
|
+
not client filesystem paths. Rich hindsight/shared/provenance imports require
|
|
442
|
+
the complete nested note record; knowledge values must still losslessly encode
|
|
443
|
+
the validated record. Canonical Markdown and its manifest remain authoritative.
|
|
444
|
+
Unmanaged collisions are refused, and bytes after the managed marker are
|
|
445
|
+
preserved exactly. Local stdio derives project identity from its working
|
|
446
|
+
directory. Authenticated HTTP project notes require validated
|
|
447
|
+
`X-Cairn-Project`; the bearer token still defines the trust domain.
|
|
448
|
+
|
|
449
|
+
An interrupted note mutation blocks later note writes with `RECOVERY_REQUIRED`.
|
|
450
|
+
`cairn doctor --repair` rolls prepared/committing journals back to verified
|
|
451
|
+
pre-images, but verifies and finalizes committed-before-cleanup journals without
|
|
452
|
+
undoing the completed operation. Unverifiable committed state remains failed
|
|
453
|
+
and untouched for backup-guided manual recovery.
|
|
454
|
+
|
|
190
455
|
### Domain knowledge (RAG via AnythingLLM, opt-in)
|
|
191
456
|
|
|
192
457
|
`domain_knowledge_query` / `domain_knowledge_sync` bridge to an optional
|
|
@@ -293,6 +558,7 @@ is guarded and **fails closed**:
|
|
|
293
558
|
| `CAIRN_MEMORY_HTTP_TOKEN` | **Required** in HTTP mode — clients send `Authorization: Bearer <token>`; the server refuses to start without it |
|
|
294
559
|
| `CAIRN_MEMORY_HTTP_ALLOWED_ORIGINS` | Comma-separated browser origins allowed via CORS (default: none — no cross-origin access) |
|
|
295
560
|
| `CAIRN_MEMORY_HTTP_ALLOWED_HOSTS` | Comma-separated allowed `Host` headers for DNS-rebinding protection (default: the bind host + `localhost` on the chosen port) |
|
|
561
|
+
| `CAIRN_ARTIFACT_HTTP` | Additional consent for artifact tools (default off; requires `CAIRN_ARTIFACT_STORE`, a valid `X-Cairn-Project`, bearer auth, and the normal Host/CORS checks) |
|
|
296
562
|
|
|
297
563
|
Requests without a valid bearer token get `401`; requests with an unexpected
|
|
298
564
|
`Host` header get `403`. Keep HTTP mode bound to `127.0.0.1` unless you have a
|
|
@@ -370,7 +636,7 @@ optional hooks around the harness, each a no-op when absent:
|
|
|
370
636
|
| Seam | When | Purpose |
|
|
371
637
|
|---|---|---|
|
|
372
638
|
| `.ai/pre-launch.sh` | sourced after `.env`, before launch | export env (e.g. a provider base URL / auth), refresh credentials, or abort by returning non-zero |
|
|
373
|
-
| `CAIRN_EXTRA_SETTINGS` | read just before launch | path to a settings file layered on the harness (`--settings` /
|
|
639
|
+
| `CAIRN_EXTRA_SETTINGS` | read just before launch | path to a settings file layered on the harness (`--settings` / `OPENCODE_CONFIG`); process env still wins over it |
|
|
374
640
|
| `.ai/post-exit.sh` | sourced after the harness exits | teardown; `CAIRN_EXIT_STATUS` holds the exit code |
|
|
375
641
|
|
|
376
642
|
A wrapper that needs a non-default provider drops a `pre-launch.sh` that renders
|
|
@@ -384,10 +650,265 @@ harness's remote HTTP registration. Unconfigured optional dependencies are
|
|
|
384
650
|
skipped; it exits non-zero when the local server probe fails or a configured
|
|
385
651
|
dependency (LLM/embedding endpoint, writable store) is unreachable.
|
|
386
652
|
|
|
653
|
+
It also checks an existing project-local trajectory database for SQLite
|
|
654
|
+
integrity, schema compatibility and index consistency. Because capture is
|
|
655
|
+
opt-in, a missing database is skipped. Metadata or indexes can be rebuilt from
|
|
656
|
+
valid full records only through the explicit repair operation:
|
|
657
|
+
|
|
387
658
|
```bash
|
|
388
659
|
cd /path/to/project && cairn doctor
|
|
660
|
+
cd /path/to/project && cairn doctor --repair
|
|
389
661
|
```
|
|
390
662
|
|
|
663
|
+
The same command checks `.agentfs/artifacts.db`. Absence is a healthy skip
|
|
664
|
+
because both producers are opt-in. A valid schema, full-record digest, index,
|
|
665
|
+
dedupe row, compaction pointer, and retention state passes. `--repair` may
|
|
666
|
+
rebuild only derived indexes/dedupe/pointers from valid authoritative records.
|
|
667
|
+
Unsupported schema, SQLite failure, invalid full records, or digest corruption
|
|
668
|
+
fails untouched with guidance to preserve the database before manual recovery.
|
|
669
|
+
|
|
670
|
+
### Evaluation harness (opt-in)
|
|
671
|
+
|
|
672
|
+
`cairn eval` is a local, serial experiment coordinator. It is disabled unless
|
|
673
|
+
`CAIRN_EVAL` is explicitly truthy. The disabled path returns before reading a
|
|
674
|
+
task set or adapter configuration, creating a workspace or report, opening a
|
|
675
|
+
database, starting a subprocess, or making a network request. Enabling the
|
|
676
|
+
flag does not choose a harness, model, endpoint, or credential: inference
|
|
677
|
+
remains owned by the operator-configured adapter process.
|
|
678
|
+
|
|
679
|
+
Task sets and adapters are strict schema-v1 JSON. Each task names an immutable
|
|
680
|
+
source commit, fixed input, shell-free preparation and verification commands,
|
|
681
|
+
and limits. An adapter configuration is one program-plus-arguments array and
|
|
682
|
+
an exact turn-semantics ID plus definition. Cairnkeep sends one bounded JSON
|
|
683
|
+
request on stdin and accepts exactly one bounded, strict JSON observation on
|
|
684
|
+
stdout. The adapter may report terminal status, turns under its declared
|
|
685
|
+
semantics, independently optional token components and total, optional
|
|
686
|
+
currency-bearing cost, component identities, capability digest, and local
|
|
687
|
+
trajectory/artifact references. The independent task verifier—not the
|
|
688
|
+
adapter—assigns pass, fail, or unknown. Arbitrary adapter stderr remains live
|
|
689
|
+
operator diagnostics and is not copied into the report.
|
|
690
|
+
|
|
691
|
+
The request's `workspace_path` is the task's Cairnkeep project root for all
|
|
692
|
+
trajectory-producing harness work. An adapter that returns `trajectory_ref`
|
|
693
|
+
must run that work against the supplied root so the closed trajectory is in
|
|
694
|
+
that task's local store. The reference is a bounded session identifier, not a
|
|
695
|
+
filesystem locator. A task manifest with `workspace.path: "."` remains the
|
|
696
|
+
compatible repository-root case; there is no second trajectory-root field.
|
|
697
|
+
|
|
698
|
+
Validate before spending or mutating:
|
|
699
|
+
|
|
700
|
+
```bash
|
|
701
|
+
export CAIRN_EVAL=1
|
|
702
|
+
cairn eval validate --task-set tasks.json --adapter adapter.json \
|
|
703
|
+
--output .agentfs/eval/experiments --json
|
|
704
|
+
|
|
705
|
+
# Two serial observations per task and repetition: Run 1, then fresh Run 2.
|
|
706
|
+
cairn eval run --task-set tasks.json --adapter adapter.json \
|
|
707
|
+
--output .agentfs/eval/experiments --repetitions 1 --seed trial-1 --yes --json
|
|
708
|
+
|
|
709
|
+
# Four serial observations per task and repetition: all-on and one-off,
|
|
710
|
+
# with Run 1 and Run 2 in each arm. Only one capability may be disabled.
|
|
711
|
+
cairn eval ablate --disable memory.search --task-set tasks.json \
|
|
712
|
+
--adapter adapter.json --output .agentfs/eval/experiments --seed trial-1
|
|
713
|
+
# Inspect the printed invocation estimate and both configuration digests, then
|
|
714
|
+
# repeat with --yes to confirm execution.
|
|
715
|
+
|
|
716
|
+
cairn eval report --experiment EXPERIMENT-ID --json
|
|
717
|
+
cairn eval prune --older-than-days 30 --dry-run --json
|
|
718
|
+
cairn eval prune --older-than-days 30 --json
|
|
719
|
+
cairn eval delete --experiment EXPERIMENT-ID --dry-run --json
|
|
720
|
+
cairn eval delete --experiment EXPERIMENT-ID --json
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
`validate` resolves task/adapter bytes and digests, immutable revisions,
|
|
724
|
+
commands, limits, output containment, seeds, and the complete deterministic
|
|
725
|
+
schedule without invoking the adapter. `run` requires `--yes` and prints its
|
|
726
|
+
serial invocation estimate. `ablate` first prints the estimate, the explicit
|
|
727
|
+
all-eight-enabled baseline, the exactly-one-disabled treatment, and their
|
|
728
|
+
configuration digests; execution likewise requires `--yes`. There are no
|
|
729
|
+
automatic retries: repetitions and paired seeds are explicit experiment
|
|
730
|
+
inputs.
|
|
731
|
+
|
|
732
|
+
The packaged fake workflow uses `examples/eval/task-set.json` and
|
|
733
|
+
`examples/eval/adapter.json` with the same `validate`, `run`, `report`,
|
|
734
|
+
`prune`, and `delete` commands. Its manifest must match the package-owned ID,
|
|
735
|
+
version, canonical bytes, and digest. It is deterministic and network-free,
|
|
736
|
+
but proves framework behavior only; it is not live performance evidence.
|
|
737
|
+
|
|
738
|
+
Run 1 starts every task from a fresh workspace without evaluation notes. After
|
|
739
|
+
a closed trajectory, the existing offline note distiller may create an
|
|
740
|
+
experiment-owned immutable snapshot. Run 2 uses another fresh workspace and
|
|
741
|
+
can see only its own task's snapshot. Tasks with `no_notes`, failed, or skipped
|
|
742
|
+
distillation still run and remain visible. Reports show the full committed
|
|
743
|
+
population and the note-eligible subset, plus executed, verified, paired, and
|
|
744
|
+
missing populations and reason-coded missingness.
|
|
745
|
+
|
|
746
|
+
Turns are paired or aggregated only when exact turn-semantics IDs match.
|
|
747
|
+
Token fields remain independent and totals are never inferred. Verified pass
|
|
748
|
+
rates exclude unknown verifier outcomes while retaining them in denominators
|
|
749
|
+
and missingness tables. Task-clustered paired bootstrap intervals use recorded
|
|
750
|
+
seeds and streams; fewer than two valid pairs has no interval and fewer than
|
|
751
|
+
20 emits a small-sample warning. Results are estimates and may be
|
|
752
|
+
inconclusive—reports do not make causal, significance, quality, or efficiency
|
|
753
|
+
claims.
|
|
754
|
+
|
|
755
|
+
SIGINT or SIGTERM stops schedule admission, terminates the active adapter,
|
|
756
|
+
checkpoints a `cancelled` observation, waits for bounded cleanup, and retains
|
|
757
|
+
an inspectable partial report. On POSIX systems the runner targets the child
|
|
758
|
+
process group with TERM then bounded KILL escalation. Windows descendant-tree
|
|
759
|
+
termination is not guaranteed and is not a supported evaluation claim.
|
|
760
|
+
|
|
761
|
+
See [storage](storage.md#evaluation-report-and-note-snapshot-storage) for local
|
|
762
|
+
retention/removal and [privacy](privacy-and-data-flow.md#evaluation-adapter-and-report-flow)
|
|
763
|
+
for the exact request, observation, environment, and persistence boundaries.
|
|
764
|
+
|
|
765
|
+
### Structured session trajectories (opt-in)
|
|
766
|
+
|
|
767
|
+
Trajectory capture is disabled by default. To enable it for a launched Claude
|
|
768
|
+
Code, OpenCode, or Pi session, set the flag in the project's private `.ai/.env`:
|
|
769
|
+
|
|
770
|
+
```bash
|
|
771
|
+
CAIRN_TRAJECTORY_CAPTURE=1
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
The Claude Code SessionEnd hook, OpenCode session-idle plugin, or Pi
|
|
775
|
+
`session_shutdown` extension then normalizes the closed session, redacts it,
|
|
776
|
+
and writes it locally without a model, API key, or remote request. Inspect and
|
|
777
|
+
manage the result from the project root:
|
|
778
|
+
|
|
779
|
+
```bash
|
|
780
|
+
cairn trajectory list
|
|
781
|
+
cairn trajectory show <session-id-or-unambiguous-prefix>
|
|
782
|
+
cairn trajectory prune --dry-run
|
|
783
|
+
cairn trajectory prune
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
All commands accept `--json`; `--dry-run` applies to `prune`. Bootstrap creates
|
|
787
|
+
`.ai/trajectory-redaction.json` with an empty custom-pattern list but does not
|
|
788
|
+
enable capture. Add bounded regular-expression entries there only for
|
|
789
|
+
project-specific secrets; built-in credential patterns always apply. See
|
|
790
|
+
[Privacy and data flow](privacy-and-data-flow.md) for the exact capture boundary
|
|
791
|
+
and [Memory storage and deployment](storage.md) for retention and backup.
|
|
792
|
+
|
|
793
|
+
### Compaction continuity and artifacts (opt-in)
|
|
794
|
+
|
|
795
|
+
The two flags are independent and off by default. Enable either in the private
|
|
796
|
+
project `.ai/.env`, sync the harness assets, and restart both the harness and
|
|
797
|
+
the MCP server when changing tool registration:
|
|
798
|
+
|
|
799
|
+
```bash
|
|
800
|
+
cd /path/to/project
|
|
801
|
+
printf '%s\n' 'CAIRN_COMPACTION_CAPTURE=1' >> .ai/.env
|
|
802
|
+
printf '%s\n' 'CAIRN_ARTIFACT_STORE=1' >> .ai/.env
|
|
803
|
+
cairn sync --apply # Claude Code PostCompact + SessionStart
|
|
804
|
+
# OpenCode: re-run scripts/sync-opencode-plugin-assets.sh --apply from a clone
|
|
805
|
+
# Restart the harness and cairn-memory after changing flags.
|
|
806
|
+
|
|
807
|
+
# Disable: remove/comment both lines, sync again, and restart.
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
Compaction continuity accepts only the pinned Claude Code `PostCompact`
|
|
811
|
+
2.1.219 and 2.1.220 payloads and OpenCode `session.compacted` 1.17.20 payload.
|
|
812
|
+
The Claude hook resolves the local CLI version and passes that exact version to
|
|
813
|
+
the normalizer. Unknown or malformed versions fail open, retain none of the
|
|
814
|
+
unknown payload, and leave only a
|
|
815
|
+
bounded value-free doctor diagnostic. The flag is checked before parsing,
|
|
816
|
+
SDK, subprocess, filesystem, database, network, stdout, stderr, or injection
|
|
817
|
+
work. Capture forwards the harness-produced summary unchanged to the local
|
|
818
|
+
normalizer; it never generates a summary, changes a prompt, or triggers
|
|
819
|
+
compaction.
|
|
820
|
+
|
|
821
|
+
Automatic recovery prefers the exact current/resumed harness session. When a
|
|
822
|
+
fresh session has no match, it chooses the newest valid project compaction. It
|
|
823
|
+
injects provenance, revision, time, age, completeness, and only structured
|
|
824
|
+
goals/decisions/TODOs/critical errors. Old state is still shown with a stale
|
|
825
|
+
warning to validate it against the repository. The redacted raw summary is
|
|
826
|
+
available only through explicit `artifact_read` or `cairn artifact show`.
|
|
827
|
+
|
|
828
|
+
`CAIRN_ARTIFACT_STORE=1` registers exactly `artifact_write`, `artifact_read`,
|
|
829
|
+
`artifact_list`, and `artifact_delete`. The first schema supports exactly
|
|
830
|
+
`compaction_summary`, `diff`, `test_output`, and `generated_file`. Writes are
|
|
831
|
+
bounded inline values; generated-file paths are labels and are never read.
|
|
832
|
+
Operator commands remain available for already-retained local data:
|
|
833
|
+
|
|
834
|
+
```bash
|
|
835
|
+
cairn artifact list --kind compaction_summary --session SESSION-REF --json
|
|
836
|
+
cairn artifact show ARTIFACT-ID --json
|
|
837
|
+
cairn artifact delete ARTIFACT-ID --dry-run --json
|
|
838
|
+
cairn artifact delete ARTIFACT-ID --json
|
|
839
|
+
cairn artifact prune --dry-run --json
|
|
840
|
+
cairn artifact prune --dry-run --include-protected --json
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
Defaults are 1 MiB per artifact, 16 MiB per session, 256 MiB total, 30 days,
|
|
844
|
+
eight compaction revisions, and a 256 KiB generated-file snapshot cap. Pruning
|
|
845
|
+
is oldest-first after age/revision eligibility and protects the newest valid
|
|
846
|
+
project compaction unless `--include-protected` or explicit delete is used.
|
|
847
|
+
Hard delete removes the body and derived rows with no tombstone.
|
|
848
|
+
|
|
849
|
+
No key, model, endpoint, or network is required. Stdio access needs only
|
|
850
|
+
`CAIRN_ARTIFACT_STORE`. HTTP requires double consent—both artifact flags—plus
|
|
851
|
+
the existing bearer token, allowed `Host`, CORS policy, and a valid
|
|
852
|
+
`X-Cairn-Project`; the latter derives an isolated server-side artifact root.
|
|
853
|
+
Artifact HTTP does not expose trajectories. See [storage](storage.md#artifact-storage)
|
|
854
|
+
and [privacy](privacy-and-data-flow.md#compaction-and-artifact-flows).
|
|
855
|
+
|
|
856
|
+
### Hindsight notes (opt-in)
|
|
857
|
+
|
|
858
|
+
Note distillation is a separate asynchronous/one-shot capability. It never runs
|
|
859
|
+
inside SessionEnd, session-idle, `session_shutdown`, or any other online agent
|
|
860
|
+
callback. It consumes only closed, schema-validated trajectories already
|
|
861
|
+
redacted by the capture path. Enable the master flag in the process that runs
|
|
862
|
+
the command:
|
|
863
|
+
|
|
864
|
+
```bash
|
|
865
|
+
export CAIRN_NOTE_DISTILLATION=1
|
|
866
|
+
|
|
867
|
+
# Incremental current project, or one exact session for deterministic replay
|
|
868
|
+
cd /path/to/project
|
|
869
|
+
cairn notes distill --json
|
|
870
|
+
cairn notes distill --session SESSION-ID --json
|
|
871
|
+
|
|
872
|
+
# Scheduled/manual sweep below one explicit PARA root
|
|
873
|
+
cairn notes distill --all-projects --para-root "$HOME/PARA" --json
|
|
874
|
+
|
|
875
|
+
# Exact signature lookup; stdin avoids quoting a real multiline stack trace
|
|
876
|
+
printf '%s\n' 'TypeError: cache closed' ' at loadCache (/tmp/src/cache.ts:44:2)' \
|
|
877
|
+
| cairn notes search-error --project /path/to/project --json
|
|
878
|
+
|
|
879
|
+
# Validate/rebuild generated indexes, or explicitly promote corroborated notes
|
|
880
|
+
cairn notes doctor --json
|
|
881
|
+
cairn notes doctor --repair --json
|
|
882
|
+
cairn notes promote NOTE-ID --with CORROBORATING-NOTE-ID --confirm --json
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
The hierarchy is `${CAIRN_AGENTFS_BASE_DIR:-~/.cairnkeep}/notes/README.md`,
|
|
886
|
+
`shared/`, and `projects/<slug--stable-id>/{README.md,knowledge/,hindsight/}`.
|
|
887
|
+
Each Markdown leaf has validated `id`, `title`, `description`, `keywords`,
|
|
888
|
+
`node_type`, and `tags` front matter. Hindsight nodes add a deterministic
|
|
889
|
+
signature and `unresolved`, `resolved`, or `abandoned` lifecycle. A later
|
|
890
|
+
recurrence reopens the same stable node. Generated content is enclosed by
|
|
891
|
+
`cairnkeep:managed:v1` markers; text after that block is preserved. An existing
|
|
892
|
+
unmarked target is treated as a collision and is never overwritten.
|
|
893
|
+
|
|
894
|
+
JSON distillation output separates `created`, `updated`, `already_processed`,
|
|
895
|
+
`enrichment_skipped`, `enrichment_failed`, and session-level `failed` results.
|
|
896
|
+
Project locks reject concurrent writers. Exact lookup normalizes the message,
|
|
897
|
+
causal stack, and component with the same versioned implementation used by the
|
|
898
|
+
index; it runs without embeddings or network access. Promotion requires two
|
|
899
|
+
compatible notes from distinct projects plus `--confirm`, creates one shared
|
|
900
|
+
canonical body, and converts each project note into a provenance reference.
|
|
901
|
+
|
|
902
|
+
Optional prose enrichment requires all of the master flag,
|
|
903
|
+
`CAIRN_NOTE_ENRICHMENT=1`, `CAIRN_LLM_API_KEY`, `CAIRN_LLM_API_URL`, and an
|
|
904
|
+
explicit `CAIRN_NOTE_ENRICHMENT_MODEL`. It sends bounded already-redacted
|
|
905
|
+
evidence to `{CAIRN_LLM_API_URL}/chat/completions`, labels returned prose as
|
|
906
|
+
non-authoritative, and cannot change signature, lifecycle, or provenance. Any
|
|
907
|
+
missing configuration, malformed response, timeout, or provider failure leaves
|
|
908
|
+
the deterministic note usable and is reported as skipped/failed. Review the
|
|
909
|
+
[privacy data flow](privacy-and-data-flow.md#hindsight-note-distillation) before
|
|
910
|
+
enabling it.
|
|
911
|
+
|
|
391
912
|
### `cairn memory export|import|path`
|
|
392
913
|
|
|
393
914
|
Relocate named/global memory (one SQLite `.db` per scope under
|
|
@@ -414,3 +935,9 @@ cairn audit-timer --on-calendar daily # install + enable the timer
|
|
|
414
935
|
cairn audit-timer --render-only ./units # just render the unit files
|
|
415
936
|
# no systemd? cron: @daily .../scripts/memory-wiki-audit.sh --para-root "$HOME/PARA" --report ...
|
|
416
937
|
```
|
|
938
|
+
|
|
939
|
+
The timer inherits its process environment. With `CAIRN_NOTE_DISTILLATION`
|
|
940
|
+
truthy it launches exactly one separate `cairn notes distill --all-projects`
|
|
941
|
+
process after the wiki scan and reports its bounded status. With the flag unset
|
|
942
|
+
it performs no note work. Note failure does not replace wiki findings or change
|
|
943
|
+
their actionable exit status; no credentials are embedded in rendered units.
|