@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
|
@@ -17,6 +17,21 @@ request unless the corresponding endpoint and credential are configured.
|
|
|
17
17
|
| `route_check` | A health request, with no memory or prompt content | `CAIRN_ROUTE_ENDPOINT` |
|
|
18
18
|
| `context_explore` | Repository path and query are passed to the configured local executable | `CAIRN_EXPLORE_BINARY`; any further data flow is controlled by that tool |
|
|
19
19
|
| Remote HTTP memory | MCP requests and responses, including memory content | The explicitly registered Cairnkeep HTTP server |
|
|
20
|
+
| Opt-in trajectory capture | None | Local `<project>/.agentfs/trajectory.db` only; no model or HTTP path exists |
|
|
21
|
+
| Opt-in capability callback records | None | Payload-free final metadata in local `<project>/.agentfs/trajectory.db`; HTTP transport is always skipped |
|
|
22
|
+
| Opt-in deterministic note distillation | None | Reads redacted closed trajectories; writes local Markdown + manifest under `${CAIRN_AGENTFS_BASE_DIR:-~/.cairnkeep}/notes/` |
|
|
23
|
+
| Separately opted-in note enrichment | `CAIRN_LLM_API_KEY` | Sends bounded redacted note evidence to the explicit `CAIRN_LLM_API_URL` chat endpoint |
|
|
24
|
+
| Typed lifecycle and inline `memory_import` over local stdio | None | Values, metadata, digests, replay bindings, and history remain in the selected local store |
|
|
25
|
+
| Typed lifecycle and inline `memory_import` over authenticated HTTP | MCP requests and responses, including supplied values | The explicitly registered Cairnkeep HTTP server; import results omit values |
|
|
26
|
+
| Project/shared note lifecycle over local stdio | None | Canonical Markdown, history, replay, and journals remain in the server-controlled notes root |
|
|
27
|
+
| Project/shared note lifecycle over authenticated HTTP | MCP requests and responses, including complete note records | The explicitly registered server; clients send logical keys, never server filesystem paths |
|
|
28
|
+
| Claude `PostCompact` compaction capture | None | Redacted local `<project>/.agentfs/artifacts.db`; no model or HTTP path |
|
|
29
|
+
| OpenCode `session.compacted` + local SDK fetch | None | Redacted local `<project>/.agentfs/artifacts.db`; no model or HTTP path |
|
|
30
|
+
| Explicit artifact tools over local stdio | None | Inline artifact values remain in the local project artifact store |
|
|
31
|
+
| Separately enabled artifact tools over HTTP | MCP artifact requests and explicit read responses | The authenticated server selected by the client; requires `CAIRN_ARTIFACT_STORE`, `CAIRN_ARTIFACT_HTTP`, bearer/Host checks, and validated project identity |
|
|
32
|
+
| Automatic compaction recovery | None | Structured categories are injected locally; raw summary and other bodies are excluded |
|
|
33
|
+
| Explicit artifact read/show | The redacted body only when HTTP is separately enabled and the operator/client explicitly reads it | Local terminal/stdio, or the explicitly registered authenticated server |
|
|
34
|
+
| Opt-in evaluation coordinator | Adapter-defined inference may leave the machine only according to the explicit operator-owned adapter and inherited environment | Local adapter subprocess; Cairnkeep supplies no provider, endpoint, credential, model, or network default |
|
|
20
35
|
|
|
21
36
|
Model endpoints may be local or remote. Cairnkeep cannot determine a provider's
|
|
22
37
|
retention, training, or logging policy; verify it before sending confidential
|
|
@@ -36,6 +51,408 @@ Project-scoped and named/global database locations are documented in
|
|
|
36
51
|
the remote server host; changing a storage environment variable on the client
|
|
37
52
|
does not relocate that server's databases.
|
|
38
53
|
|
|
54
|
+
Typed metadata adds no default egress. Values, canonical types/tags, complete
|
|
55
|
+
history snapshots, SHA-256 import digests, replay bindings, and note transaction
|
|
56
|
+
backups/journals are sensitive local data at rest. Dry-run and commit responses
|
|
57
|
+
contain scopes/address spaces, digests, keys, actions, and counts—not supplied
|
|
58
|
+
or displaced values. No model, API key, endpoint, or network is required.
|
|
59
|
+
|
|
60
|
+
The existing explicitly configured embedding search is the sole related egress:
|
|
61
|
+
eligible key/value/type/tag text and the query may be sent to
|
|
62
|
+
`CAIRN_MEMORY_EMBEDDING_URL` (or its documented fallback). Hard filters run
|
|
63
|
+
before that request; endpoint failure returns to local substring search. Note
|
|
64
|
+
search is always local and never uses embeddings.
|
|
65
|
+
|
|
66
|
+
Canonical note storage includes manifest records, Markdown, indexes, history,
|
|
67
|
+
import replay state, staged bytes, backups, and journals. Prepared/committing
|
|
68
|
+
recovery restores verified pre-images. Committed-before-cleanup recovery
|
|
69
|
+
verifies and preserves the completed mutation, then removes only transaction
|
|
70
|
+
artifacts. Unverifiable committed state remains blocked and is not rolled back.
|
|
71
|
+
Default uninstall retains this state; explicit `--purge-memory` backs it up
|
|
72
|
+
before removal and its `revert.sh` restores it.
|
|
73
|
+
|
|
74
|
+
Artifact envelopes, redacted content, digests, indexes, dedupe bindings,
|
|
75
|
+
revision counters, latest pointers, SQLite sidecars, backups, and explicit
|
|
76
|
+
read/CLI output are sensitive data at rest. They are not application-level
|
|
77
|
+
encrypted. Default uninstall retains them; purge is backup-first and the
|
|
78
|
+
generated revert restores exact bytes. Hard delete and explicit prune remove
|
|
79
|
+
content plus derived references without keeping a tombstone.
|
|
80
|
+
|
|
81
|
+
Evaluation reports and task-local note snapshots are also sensitive local data
|
|
82
|
+
at rest under `<project>/.agentfs/eval/experiments/`. Directories are private,
|
|
83
|
+
reports are mode `0600`, snapshots are read-only, and checkpoints are bounded
|
|
84
|
+
atomic replacements. Default uninstall retains them; explicit
|
|
85
|
+
`--purge-memory PROJECT` backs up the whole `.agentfs/` boundary before removal
|
|
86
|
+
and its generated `revert.sh` restores exact bytes, modes, and layout. Explicit
|
|
87
|
+
`cairn eval delete` and `prune` remove selected contained experiment trees with
|
|
88
|
+
no hidden tombstone.
|
|
89
|
+
|
|
90
|
+
## Evaluation adapter and report flow
|
|
91
|
+
|
|
92
|
+
`CAIRN_EVAL` is unset/off by default. With it off, `cairn eval` returns a fixed
|
|
93
|
+
disabled result before task-set or adapter reads, workspace/report creation,
|
|
94
|
+
database access, subprocess execution, or network activity. A credential in
|
|
95
|
+
the environment never enables evaluation. When enabled, Cairnkeep remains a
|
|
96
|
+
local coordinator; the operator selects and owns any inference performed by
|
|
97
|
+
the explicit adapter program.
|
|
98
|
+
|
|
99
|
+
The per-observation flow is:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
validated committed task set + explicit adapter program/args
|
|
103
|
+
→ fresh task/pass/arm HOME, TMP, XDG, workspace, notes, and output roots
|
|
104
|
+
→ one bounded schema-v1 request on adapter stdin
|
|
105
|
+
→ exactly one bounded strict schema-v1 observation on adapter stdout
|
|
106
|
+
→ independent deterministic task verifier
|
|
107
|
+
→ allow-listed local observation + atomic partial/final report checkpoint
|
|
108
|
+
→ workspace cleanup
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The request fields are exactly schema version, experiment/task identity, arm,
|
|
112
|
+
repetition, pass, relative workspace path, nullable relative notes path, fixed
|
|
113
|
+
task input, declared limits, paired seed, expected capability digest, and
|
|
114
|
+
relative output path. The fixed task input is prompt-like content delivered to
|
|
115
|
+
the adapter for execution; it is not copied into the report. Run 2 can receive
|
|
116
|
+
only the immutable note snapshot distilled from that same task's Run 1
|
|
117
|
+
trajectory. No other task's notes, checkout, HOME, temporary directory, XDG
|
|
118
|
+
state, or output directory is reused.
|
|
119
|
+
|
|
120
|
+
The supplied `workspace_path` is the task's Cairnkeep project root for
|
|
121
|
+
trajectory-producing harness work. Offline Run 1 distillation performs an
|
|
122
|
+
exact session lookup only in that task workspace's local
|
|
123
|
+
`.agentfs/trajectory.db`; `trajectory_ref` is a bounded session identifier and
|
|
124
|
+
not a path. If the exact session is absent or stored under a different root,
|
|
125
|
+
the report retains failed note missingness and Run 2 receives no snapshot.
|
|
126
|
+
Cairnkeep does not retry the source or parent root, recursively discover
|
|
127
|
+
stores, inspect siblings, or accept an adapter-selected absolute locator.
|
|
128
|
+
|
|
129
|
+
The strict stdout observation can contain only terminal status and a value-free
|
|
130
|
+
error code; turns with an exact semantics ID; independently optional input,
|
|
131
|
+
output, reasoning, cache-read, cache-write, and total token counts; optional
|
|
132
|
+
amount-plus-currency cost; bounded harness/adapter/model/config identities;
|
|
133
|
+
observed capability digest; and bounded trajectory/artifact references. It has
|
|
134
|
+
no pass field—the verifier owns pass state. Unknown fields, oversized output,
|
|
135
|
+
invalid UTF-8/JSON, semantic mismatches, and capability-digest mismatches are
|
|
136
|
+
rejected or retained as explicit missing/invalid observations rather than
|
|
137
|
+
being inferred.
|
|
138
|
+
|
|
139
|
+
The adapter inherits the operator's process environment so an operator-owned
|
|
140
|
+
harness can use its existing secrets. Cairnkeep overrides only isolated
|
|
141
|
+
task-local HOME/TMP/XDG roots and explicit capability-arm values. Secret values
|
|
142
|
+
and full environment snapshots are never report fields. Adapter stderr is
|
|
143
|
+
inherited for live operator diagnostics and is never buffered into evidence.
|
|
144
|
+
Adapter stdout is discarded after strict observation validation. Prompts,
|
|
145
|
+
model outputs, verifier stdout/stderr, arbitrary errors, workspace contents,
|
|
146
|
+
and complete environment values are not persisted in reports. Identifiers and
|
|
147
|
+
references are bounded and value-minimized so metadata cannot become a free
|
|
148
|
+
text channel.
|
|
149
|
+
|
|
150
|
+
Reports persist only the versioned schedule and terminal/process/verifier
|
|
151
|
+
states; allow-listed observations; expected/observed capability state and
|
|
152
|
+
digests; task-local note outcome/manifests/digests; revisions and task/adapter
|
|
153
|
+
digests; runtime/component identifiers; explicit optional metrics; populations,
|
|
154
|
+
missingness, warnings, and uncertainty metadata. The stable JSON report is the
|
|
155
|
+
source of truth; human output is rendered only from validated JSON. Local
|
|
156
|
+
report and snapshot retention/removal is documented in
|
|
157
|
+
[storage](storage.md#evaluation-report-and-note-snapshot-storage).
|
|
158
|
+
|
|
159
|
+
`validate` performs no adapter or network call. `run` and `ablate` print the
|
|
160
|
+
deterministic serial invocation estimate and require explicit `--yes` before
|
|
161
|
+
execution. Cairnkeep supplies no live adapter, provider, endpoint, credential,
|
|
162
|
+
model, retry, or network default. The packaged fake adapter is deterministic,
|
|
163
|
+
network-free, and permanently scoped as framework-only evidence.
|
|
164
|
+
|
|
165
|
+
SIGINT/SIGTERM stops new schedule admission, terminates the active adapter,
|
|
166
|
+
checkpoints cancellation, performs bounded cleanup, and retains a partial
|
|
167
|
+
report. POSIX process groups receive TERM followed by bounded KILL escalation.
|
|
168
|
+
There is no Windows descendant-process-tree termination guarantee.
|
|
169
|
+
|
|
170
|
+
Turns aggregate only under exact matching compatibility IDs. Missing token
|
|
171
|
+
components/totals, unknown verifier outcomes, incompatible turn semantics, and
|
|
172
|
+
failed or absent note snapshots remain explicit missingness. Reports show both
|
|
173
|
+
the full committed population and note-eligible subset with paired counts and
|
|
174
|
+
seeded uncertainty; they do not convert framework output into a causal,
|
|
175
|
+
significance, quality, or efficiency claim.
|
|
176
|
+
|
|
177
|
+
## Compaction and artifact flows
|
|
178
|
+
|
|
179
|
+
Both `CAIRN_COMPACTION_CAPTURE` and `CAIRN_ARTIFACT_STORE` are default-off and
|
|
180
|
+
independent. With a flag off, its adapter returns before new parsing, SDK,
|
|
181
|
+
subprocess, file/database, network, stdout/stderr, or context-injection work.
|
|
182
|
+
Credentials never imply either flag. No model call, telemetry, automatic
|
|
183
|
+
remote discovery, or default egress is introduced.
|
|
184
|
+
|
|
185
|
+
Claude local capture:
|
|
186
|
+
|
|
187
|
+
```text
|
|
188
|
+
documented PostCompact stdin (session/cwd/trigger/compact_summary)
|
|
189
|
+
→ supported-version validation
|
|
190
|
+
→ recursive redaction
|
|
191
|
+
→ truncate / digest / index / write
|
|
192
|
+
→ local .agentfs/artifacts.db
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
OpenCode local capture:
|
|
196
|
+
|
|
197
|
+
```text
|
|
198
|
+
session.compacted session ID
|
|
199
|
+
→ local SDK get(session) + messages(session)
|
|
200
|
+
→ select the pinned completed summary shape
|
|
201
|
+
→ recursive redaction
|
|
202
|
+
→ truncate / digest / index / write
|
|
203
|
+
→ local .agentfs/artifacts.db
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Only Claude Code `PostCompact` 2.1.219 and 2.1.220 and OpenCode
|
|
207
|
+
`session.compacted` 1.17.20 are pinned. Unknown versions/shapes fail open. Their payload is not logged, serialized,
|
|
208
|
+
temporarily copied, digested, indexed, or retained; doctor receives only a
|
|
209
|
+
bounded value-free reason. Artifact candidates are redacted before digest, index, temporary storage, or any Cairnkeep write.
|
|
210
|
+
Truncation also happens only after redaction. The same recursive
|
|
211
|
+
built-ins and bounded project redaction file used by trajectory capture apply.
|
|
212
|
+
|
|
213
|
+
Explicit artifact ingress:
|
|
214
|
+
|
|
215
|
+
```text
|
|
216
|
+
local stdio artifact_write (CAIRN_ARTIFACT_STORE)
|
|
217
|
+
→ bounded inline schema → redact → truncate → digest/index/write locally
|
|
218
|
+
|
|
219
|
+
authenticated HTTP artifact_write (both artifact flags)
|
|
220
|
+
→ bearer + Host/CORS + X-Cairn-Project
|
|
221
|
+
→ server-derived project root → same bounded redaction/write path
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The four accepted kinds are `compaction_summary`, `diff`, `test_output`, and
|
|
225
|
+
`generated_file`. Generated-file paths are labels only and are never read;
|
|
226
|
+
binary or oversized bodies become metadata-only. There is no ambient command
|
|
227
|
+
output capture, filesystem watcher, or caller-selected path dereference.
|
|
228
|
+
|
|
229
|
+
Recovery egress is local and concise:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
current-session latest valid compaction, else newest valid project compaction
|
|
233
|
+
→ provenance/freshness/completeness + four structured categories
|
|
234
|
+
→ harness SessionStart/system-transform context
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Raw summaries are on-demand only through explicit `artifact_read` or
|
|
238
|
+
`cairn artifact show`; automatic recovery never injects them or another
|
|
239
|
+
artifact body. Lists, writes, deletes, pruning, and doctor omit bodies. Stored
|
|
240
|
+
redacted content is still sensitive and can be exposed by an explicit read.
|
|
241
|
+
|
|
242
|
+
HTTP artifact egress is separately enabled by `CAIRN_ARTIFACT_HTTP` in
|
|
243
|
+
addition to `CAIRN_ARTIFACT_STORE` and existing authenticated transport
|
|
244
|
+
controls. It exposes only the four artifact tools, never trajectories,
|
|
245
|
+
compaction hooks, or a generic filesystem. With HTTP consent absent, remote
|
|
246
|
+
clients cannot observe artifact schemas or content. Artifacts have no default egress.
|
|
247
|
+
Artifacts have no telemetry; local capture/recovery never uses the HTTP route.
|
|
248
|
+
|
|
249
|
+
## Structured trajectory capture
|
|
250
|
+
|
|
251
|
+
`CAIRN_TRAJECTORY_CAPTURE` is unset and off by default. When explicitly set to
|
|
252
|
+
`1`, `true`, `yes`, or `on`, the existing Claude Code SessionEnd hook reads the
|
|
253
|
+
harness-owned transcript file named in its hook event, or the existing OpenCode
|
|
254
|
+
session-idle plugin requests that session's structured messages and parts from
|
|
255
|
+
the local SDK, or the Pi `session_shutdown` extension reads Pi's active branch
|
|
256
|
+
through its read-only session manager. Cairnkeep does not change, copy, retain,
|
|
257
|
+
or delete Claude Code's source transcript, and it does not control OpenCode or
|
|
258
|
+
Pi's own source retention.
|
|
259
|
+
Those harness-owned sources remain a separate privacy boundary.
|
|
260
|
+
|
|
261
|
+
The capture path allow-lists user messages, visible model outputs, tool
|
|
262
|
+
invocations, tool results, system events, timestamps, and usage/cost fields
|
|
263
|
+
when the harness exposes them. It does not store hidden reasoning text;
|
|
264
|
+
reasoning blocks and unknown record types are counted as omissions. Records are
|
|
265
|
+
normalized into the versioned trajectory schema, recursively redacted, bounded
|
|
266
|
+
by UTF-8 serialized size, and only then passed to AgentFS. Built-in rules redact
|
|
267
|
+
secret-like object keys, bearer/API-key/password forms, credential-bearing URLs,
|
|
268
|
+
private-key blocks, and exact values of secret-like environment variables.
|
|
269
|
+
For Pi, model and thinking-level changes become system events; hidden thinking
|
|
270
|
+
blocks are never written. Provider error messages become redacted system events
|
|
271
|
+
so failed sessions remain useful to later hindsight processing. Only the active branch is captured. The extension
|
|
272
|
+
passes the structured branch to the same local normalizer/store path, kills a
|
|
273
|
+
stalled capture subprocess after three seconds, and always fails open so a
|
|
274
|
+
capture error cannot change the Pi session's outcome.
|
|
275
|
+
|
|
276
|
+
Bootstrap writes `.ai/trajectory-redaction.json` with no custom rules and does
|
|
277
|
+
not enable capture. A project may add up to 32 bounded regular expressions to
|
|
278
|
+
that file, or select another project-contained file with
|
|
279
|
+
`CAIRN_TRAJECTORY_REDACTION_FILE`. Invalid, unreadable, outside-project, or
|
|
280
|
+
uncompilable configuration fails that capture attempt before any partial write.
|
|
281
|
+
Custom patterns are defense in depth: they can miss an unknown secret shape or
|
|
282
|
+
redact too broadly, so captured sessions must still be treated as sensitive.
|
|
283
|
+
|
|
284
|
+
The redacted v1 session and time index live only at
|
|
285
|
+
`<project>/.agentfs/trajectory.db`. Default limits are 5 MiB per session, 256
|
|
286
|
+
MiB logical total and 30 days. Capture and explicit `cairn trajectory prune`
|
|
287
|
+
apply age and oldest-first budget retention. `list`, `show`, `prune --dry-run`,
|
|
288
|
+
doctor output, SQLite `-wal`/`-shm` files, backups and terminal output remain
|
|
289
|
+
local but can expose redacted project content, paths, error output and metadata
|
|
290
|
+
to anyone who can access them. Cairnkeep provides no application-level
|
|
291
|
+
encryption; use host encryption and access controls.
|
|
292
|
+
|
|
293
|
+
Trajectory capture has no MCP tool or remote HTTP endpoint and never calls an
|
|
294
|
+
LLM, embedding service, AnythingLLM, telemetry service, or other network
|
|
295
|
+
destination. With the flag unset, the hook/plugin does not create or touch the
|
|
296
|
+
trajectory database. `cairn doctor --repair` may rebuild missing metadata and
|
|
297
|
+
indexes from valid full records but does not discard an invalid full record;
|
|
298
|
+
only capture retention, explicit prune, or explicit uninstall purge removes
|
|
299
|
+
trajectory sessions.
|
|
300
|
+
|
|
301
|
+
## Capability callback flow
|
|
302
|
+
|
|
303
|
+
Callback measurement has three consents, all separately default-off where
|
|
304
|
+
applicable:
|
|
305
|
+
|
|
306
|
+
```text
|
|
307
|
+
CAIRN_CAPABILITY_CONTRACT enabled
|
|
308
|
+
+ managed logging.callbacks enabled (or CAIRN_CAPABILITY_LOGGING)
|
|
309
|
+
+ CAIRN_TRAJECTORY_CAPTURE enabled
|
|
310
|
+
+ local non-HTTP invocation
|
|
311
|
+
-> resolve effective state and digest
|
|
312
|
+
-> durably issue one payload-free local operating marker
|
|
313
|
+
-> run the unchanged capability owner
|
|
314
|
+
-> check current three-consent authorization and effective state again
|
|
315
|
+
-> consume the exact issued marker once with one payload-free final record
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
The resulting three-state privacy contract is precise:
|
|
319
|
+
|
|
320
|
+
- With the master contract off, Cairnkeep preserves exact legacy behavior. It
|
|
321
|
+
installs or invokes no capability hook/plugin, never introduces a capability
|
|
322
|
+
block, and creates no pending lease, callback final, or other capability
|
|
323
|
+
measurement state.
|
|
324
|
+
- With the master contract on and the target disabled, the fixed block always
|
|
325
|
+
occurs before owner I/O. When all three consents are enabled, the issued
|
|
326
|
+
lease is atomically consumed into exactly one D-25/D-26 value-free
|
|
327
|
+
`disabled` final. If either measurement consent—managed callback logging or
|
|
328
|
+
local trajectory capture—is off, the same fixed block remains in force and
|
|
329
|
+
no pending or final state is written.
|
|
330
|
+
- With the master contract on and the target enabled, turning either
|
|
331
|
+
measurement consent off leaves owner execution unchanged and writes no
|
|
332
|
+
pending or final state.
|
|
333
|
+
|
|
334
|
+
Consent affects measurement, never the disabled policy decision. No branch may
|
|
335
|
+
record arguments, results, prompts, query text, paths, raw errors, or secrets.
|
|
336
|
+
|
|
337
|
+
An operating start with absent consent, HTTP transport, or a local-store fault
|
|
338
|
+
returns the existing unmeasured bypass without issuing a handle. At finish,
|
|
339
|
+
the contract flag and local trajectory capture are checked before managed
|
|
340
|
+
status resolution; current three-consent authorization is checked again at finish,
|
|
341
|
+
and managed logging, capability enablement, state source, and the effective
|
|
342
|
+
configuration digest must still match. Revoked consent or stale
|
|
343
|
+
configuration defensively consumes a matching existing marker without a final
|
|
344
|
+
record. This invalidation never creates a database, remains value-free and
|
|
345
|
+
fail-open, and cannot resurrect the invocation after re-enable.
|
|
346
|
+
|
|
347
|
+
A schema-valid handle alone proves nothing. Unissued, strict-field-mismatched,
|
|
348
|
+
expired, stale, and replayed handles return a non-finalizing result and cannot
|
|
349
|
+
produce final callback evidence. A mismatch does not consume the authentic
|
|
350
|
+
marker; the untouched issued handle can still settle exactly once.
|
|
351
|
+
|
|
352
|
+
There is no remote/HTTP callback persistence. HTTP callbacks are never persisted.
|
|
353
|
+
Pending markers and final records never use remote project routing.
|
|
354
|
+
There is no payload, no telemetry, no analytics, no log export, and no callback
|
|
355
|
+
network request. This is a no-payload, no-telemetry, no-network boundary.
|
|
356
|
+
Existing authenticated HTTP MCP behavior is unchanged.
|
|
357
|
+
|
|
358
|
+
The strict schema permits only these final fields:
|
|
359
|
+
|
|
360
|
+
- `schema_version`
|
|
361
|
+
- `capability_id`
|
|
362
|
+
- `invocation_id` (`cap:<uuid>`, unique per invocation)
|
|
363
|
+
- `correlation_id` (the explicit harness session when exposed, otherwise one
|
|
364
|
+
stable per-process/run `cairn:<uuid>`; never `unknown`)
|
|
365
|
+
- `harness` (`claude-code`, `opencode`, `pi`, or `other`)
|
|
366
|
+
- `source` (`mcp`, `notes-cli`, `audit-timer`, `operating-command`, or
|
|
367
|
+
`operating-workflow`)
|
|
368
|
+
- `transport` (`stdio`, `local-process`, or `harness-command` for persisted
|
|
369
|
+
records; HTTP is skipped)
|
|
370
|
+
- `started_at`, `finished_at`, and non-negative `duration_ms`
|
|
371
|
+
- `outcome` (`success`, `error`, `timeout`, or `disabled`) and, for a
|
|
372
|
+
non-success outcome, one stable value-free `error_code`
|
|
373
|
+
- `state_source` (`environment`, `project`, or `compatibility`)
|
|
374
|
+
- `configuration_digest` (the SHA-256 digest of the effective state snapshot)
|
|
375
|
+
|
|
376
|
+
There is no start record in callback evidence. A transient marker under
|
|
377
|
+
`capability-callback/v1/pending/` contains only the same strict handle scalars;
|
|
378
|
+
it is not a trajectory session or callback record, is bounded by the callback
|
|
379
|
+
retention/cap policy, and is consumed once. Final records remain under the
|
|
380
|
+
unchanged `capability-callback/v1/record/` schema and allow-list. One atomic
|
|
381
|
+
final record is attempted after a terminal outcome; an operating disabled
|
|
382
|
+
result may record `disabled`. A store open, lock, schema, validation, or write
|
|
383
|
+
failure is fail-open: it cannot change the owner result, thrown error, timeout
|
|
384
|
+
behavior, stdout/stderr, or exit status.
|
|
385
|
+
|
|
386
|
+
Neither issuance nor the final-record constructor receives or persists
|
|
387
|
+
arguments, results, prompts, query text, memory values, file paths, stack
|
|
388
|
+
traces, raw errors, secrets, credentials, arbitrary metadata, or user-supplied
|
|
389
|
+
messages/details. The timer starts only immediately before the capability-owned
|
|
390
|
+
body after state resolution, and ends after its outcome before final
|
|
391
|
+
presentation; discovery, configuration, guard, and unrelated harness overhead
|
|
392
|
+
are excluded.
|
|
393
|
+
|
|
394
|
+
When one of `memory.write`, `memory.search`, `route.check`, or
|
|
395
|
+
`context.explore` is disabled, it is omitted from MCP registration and cannot
|
|
396
|
+
produce a callback record. The schema-v1 `cairn capabilities status --json`
|
|
397
|
+
snapshot and its `configuration_digest` are the evidence for that omitted tool.
|
|
398
|
+
This is operating evidence only, not a task result, telemetry event, or
|
|
399
|
+
evaluation/quality claim.
|
|
400
|
+
|
|
401
|
+
## Hindsight note distillation
|
|
402
|
+
|
|
403
|
+
`CAIRN_NOTE_DISTILLATION` is unset/off by default. With it off, every public
|
|
404
|
+
notes operation returns before reading trajectories, walking projects, opening
|
|
405
|
+
the note store, acquiring a lock, or making a request. Capture does not imply
|
|
406
|
+
distillation, and the presence of any API credential does not enable it.
|
|
407
|
+
|
|
408
|
+
The local deterministic flow is:
|
|
409
|
+
|
|
410
|
+
```text
|
|
411
|
+
harness-owned source
|
|
412
|
+
→ allow-listed, redacted, bounded trajectory in <project>/.agentfs/trajectory.db
|
|
413
|
+
→ conservative failure/validation evidence
|
|
414
|
+
→ versioned message + stack + component signature and lifecycle reducer
|
|
415
|
+
→ local managed Markdown, README indexes, and hidden manifest under ~/.cairnkeep/notes/
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
Only explicit failed tool results, structured nonzero statuses, provider-error
|
|
419
|
+
events, equivalent later successful validation calls, and a bounded set of
|
|
420
|
+
explicit abandonment phrases affect lifecycle. The note stores normalized
|
|
421
|
+
error/component data, session IDs/digests, timestamps, outcome evidence, and
|
|
422
|
+
optional generated prose; it does not copy full trajectories or hidden
|
|
423
|
+
reasoning. Visible Markdown omits absolute checkout roots. The hidden manifest
|
|
424
|
+
retains canonical project roots for local scheduling, lookup maps, lifecycle
|
|
425
|
+
records, and processed-session digests. Occurrence history is capped at 1024
|
|
426
|
+
entries per note and processed-session history at 4096 digests per project.
|
|
427
|
+
Notes have no automatic age deletion and survive trajectory pruning; inspect or
|
|
428
|
+
delete them under your local retention policy.
|
|
429
|
+
|
|
430
|
+
Markdown and manifest files, locks, backups, terminal JSON, and promoted shared
|
|
431
|
+
notes are sensitive derived project data. They are owner-readable local files,
|
|
432
|
+
not encrypted by Cairnkeep. Generated `cairnkeep:managed:v1` blocks may be
|
|
433
|
+
rewritten; text after the block is preserved. Promotion is explicit and local,
|
|
434
|
+
requires compatible evidence from two distinct projects plus `--confirm`, and
|
|
435
|
+
creates one shared canonical note with project provenance references.
|
|
436
|
+
|
|
437
|
+
Optional enrichment adds a second, independent egress boundary. It runs only
|
|
438
|
+
when `CAIRN_NOTE_ENRICHMENT` and the master flag are truthy and key, base URL,
|
|
439
|
+
and model are all explicitly configured. One changed note's bounded redacted
|
|
440
|
+
error, component, lifecycle, and attempt strings are sent to the configured
|
|
441
|
+
OpenAI-compatible `/chat/completions` endpoint; full trajectories, manifests,
|
|
442
|
+
manual Markdown, credentials, and hidden reasoning are not request fields.
|
|
443
|
+
Requests use a bounded output, timeout, strict response schema, and at most one
|
|
444
|
+
retry. Returned prose is labeled non-authoritative and cannot change identity,
|
|
445
|
+
lifecycle, exact keys, or provenance. Missing configuration or provider failure
|
|
446
|
+
leaves the deterministic note intact.
|
|
447
|
+
|
|
448
|
+
Redaction is best effort, not proof that content is non-sensitive. Unknown
|
|
449
|
+
secret formats or secrets embedded in unusual free text can survive imperfect
|
|
450
|
+
patterns and therefore reach local notes or, if enrichment is enabled, the
|
|
451
|
+
configured endpoint. Inspect redaction rules and representative local notes
|
|
452
|
+
before enabling enrichment for confidential projects. Endpoint operation,
|
|
453
|
+
retention, training, access control, jurisdiction, and deletion policy are the
|
|
454
|
+
operator's responsibility; Cairnkeep cannot verify them.
|
|
455
|
+
|
|
39
456
|
The official container stores all databases below `/data`. A named volume
|
|
40
457
|
persists them after container replacement and remains sensitive data. Sandbox
|
|
41
458
|
workspace mode also retains a repository copy in its named volume. Neither
|