@cairnkeep/cli 2.15.1 → 2.15.3
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 +35 -0
- package/README.md +9 -1
- package/docs/harness-compatibility.md +29 -5
- package/docs/learning/CURRICULUM-MAP.md +3 -3
- package/docs/learning/FEATURE-GUIDE.md +6 -2
- package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
- package/docs/learning/lessons/L01-safe-trial.md +1 -1
- package/docs/learning/lessons/L02-installation.md +1 -1
- package/docs/learning/lessons/L03-first-project.md +1 -1
- package/docs/learning/lessons/L19-validated-skill-improvement.md +1 -1
- package/docs/learning/lessons/L20-mcp-tool-profiles.md +1 -1
- package/docs/learning/lessons/L21-context-packs.md +1 -1
- package/docs/learning/lessons/L22-native-windows.md +1 -1
- package/docs/learning/lessons/L23-guided-setup.md +1 -1
- package/docs/learning/lessons/L24-okf-exchange.md +1 -1
- package/docs/learning/lessons/L25-playbooks.md +14 -1
- package/docs/learning/video-scripts/V25-playbooks.md +8 -5
- package/docs/operating.md +28 -8
- package/docs/quickstart.md +10 -4
- package/examples/eval/bundled-fake.json +1 -1
- package/mcp-memory-server/dist/playbook-cli.js +38 -0
- package/mcp-memory-server/dist/playbook.js +60 -22
- package/package.json +1 -1
- package/scripts/test-cli-dispatch.sh +8 -0
- package/scripts/test-learning-docs.sh +2 -0
- package/scripts/test-package-install.sh +4 -0
- package/scripts/test-playbook-instructions.sh +10 -0
- package/scripts/test-windows-native.mjs +4 -0
- package/templates/playbook-agent-instructions.md.template +19 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,41 @@ All notable user-facing changes are documented here. This project follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [2.15.3] - 2026-08-18
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Require the generic managed memory step before repository inventory or
|
|
13
|
+
search commands, with task-derived query guidance that does not need an
|
|
14
|
+
exploratory file read first.
|
|
15
|
+
- Make the managed playbook receipt guidance directly executable, including
|
|
16
|
+
the lifecycle event, action, outcome, session, optional reason, and one-call
|
|
17
|
+
per-action boundary.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Add successful command-scoped help for `cairn playbook check --help` and
|
|
22
|
+
`cairn playbook record --help`, including the bounded event, outcome,
|
|
23
|
+
identity, project, and output options agents need to avoid CLI probing.
|
|
24
|
+
|
|
25
|
+
## [2.15.2] - 2026-08-18
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Add a generic, ownership-safe durable-context protocol to the managed project
|
|
30
|
+
`AGENTS.md` block. Compatible agents derive one short project-memory query
|
|
31
|
+
before broad exploration when prior decisions or conventions may matter,
|
|
32
|
+
verify referenced repository sources, fall back cleanly when retrieval is
|
|
33
|
+
unavailable, and never promote memory automatically.
|
|
34
|
+
- Extend setup, bootstrap, installed-package, native Windows, uninstall, and
|
|
35
|
+
documentation coverage for the managed retrieval guidance.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Serialize same-process playbook configuration mutations before taking the
|
|
40
|
+
filesystem lock, avoiding Windows CI lock starvation under concurrent
|
|
41
|
+
profile and reset operations while preserving cross-process exclusion.
|
|
42
|
+
|
|
8
43
|
## [2.15.1] - 2026-08-17
|
|
9
44
|
|
|
10
45
|
### Fixed
|
package/README.md
CHANGED
|
@@ -51,6 +51,10 @@ launchers, including native Windows, without capturing prompts or replacing Git.
|
|
|
51
51
|
Version 2.15 adds bounded project playbooks that help agents select existing
|
|
52
52
|
recall, planning, verification, review, security, documentation, and learning
|
|
53
53
|
steps without becoming an agent runtime or granting approval.
|
|
54
|
+
Version 2.15.3 tightens the generic durable-context protocol so compatible
|
|
55
|
+
agents derive one project-memory query before repository inventory or search,
|
|
56
|
+
verify its repository provenance, and receive executable playbook receipt
|
|
57
|
+
syntax with command-scoped help.
|
|
54
58
|
|
|
55
59
|
## Compatibility
|
|
56
60
|
|
|
@@ -203,7 +207,11 @@ The exact command rendering depends on the client. Any MCP client can call
|
|
|
203
207
|
`memory_write` and `memory_search` directly.
|
|
204
208
|
|
|
205
209
|
Setup also installs a balanced `.ai/playbooks.json` policy and an ownership-safe
|
|
206
|
-
managed block in `AGENTS.md`.
|
|
210
|
+
managed block in `AGENTS.md`. The block directs compatible agents to make one
|
|
211
|
+
task-derived, project-scoped memory search for nontrivial work involving prior
|
|
212
|
+
decisions, conventions, constraints, or failures. Results are locators, not
|
|
213
|
+
authority; referenced repository sources must be verified, and memory is never
|
|
214
|
+
promoted automatically. Agents can evaluate the playbook at task boundaries:
|
|
207
215
|
|
|
208
216
|
```bash
|
|
209
217
|
cairn playbook check start --complexity standard --familiarity mixed
|
|
@@ -17,18 +17,22 @@ Cairnkeep commands, hooks or native trajectory capture.
|
|
|
17
17
|
| Claude Code | Memory MCP, commands (including `/cairn-work`), agents, hooks, launcher | Exercised by Cairnkeep tests |
|
|
18
18
|
| OpenCode | Memory MCP, commands (including `/cairn-work`), workflows, plugins, launcher | Exercised by Cairnkeep tests |
|
|
19
19
|
| Kimi Code | Memory MCP, `AGENTS.md`, launcher, opt-in graph and cairn-work Skills | Launcher tested; remote MCP tested with Kimi Code 0.30.0; Skills contract-tested |
|
|
20
|
-
| Qwen Code | Memory MCP, launcher, project `AGENTS.md` playbook guidance | Launcher tested; stdio and remote MCP tested with Qwen Code 0.21.1 |
|
|
20
|
+
| Qwen Code | Memory MCP, launcher, project `AGENTS.md` durable-context and playbook guidance | Launcher tested; stdio and remote MCP tested with Qwen Code 0.21.1 |
|
|
21
21
|
| Pi | Memory MCP through maintained local stdio extension, native opt-in trajectory extension, launcher, graph and cairn-work prompts | Pi 0.84.1 validated minimum; deterministic and real bridge/lifecycle tests |
|
|
22
|
-
| Codex CLI | Project-scoped memory MCP, launcher, and project `AGENTS.md` playbook guidance | Setup and launcher contract-tested on POSIX and simulated native Windows; project trust remains operator-controlled |
|
|
22
|
+
| Codex CLI | Project-scoped memory MCP, launcher, and project `AGENTS.md` durable-context and playbook guidance | Setup and launcher contract-tested on POSIX and simulated native Windows; project trust remains operator-controlled |
|
|
23
23
|
| Other MCP clients | Memory plus optional domain-knowledge and context-pack tools | Protocol-compatible; not automatically runtime-tested |
|
|
24
24
|
|
|
25
25
|
Only Claude Code and OpenCode currently receive the complete operating layer.
|
|
26
26
|
Kimi receives narrow graph and playbook Skills, while Pi receives matching narrow prompts;
|
|
27
27
|
neither is equivalent to the full commands, agents, hooks, and plugins surface.
|
|
28
28
|
Qwen skills and hooks still require harness-specific adaptation and validation.
|
|
29
|
-
Codex receives a project-local MCP entry, launcher, and portable
|
|
30
|
-
instructions, but not Cairnkeep-specific commands, hooks, agents,
|
|
31
|
-
skill activation.
|
|
29
|
+
Codex receives a project-local MCP entry, launcher, and portable durable-context
|
|
30
|
+
and playbook instructions, but not Cairnkeep-specific commands, hooks, agents,
|
|
31
|
+
or automatic skill activation. The durable-context protocol places its
|
|
32
|
+
task-derived search before repository inventory or search, and the playbook
|
|
33
|
+
instructions provide executable receipt syntax plus command-scoped help.
|
|
34
|
+
Harness behavior remains probabilistic; instruction presence must not be
|
|
35
|
+
reported as a tool invocation without runtime evidence.
|
|
32
36
|
|
|
33
37
|
Every MCP client receives complete tool annotations and may use a Cairnkeep
|
|
34
38
|
least-authority profile independent of harness assets. Context-pack tools are
|
|
@@ -240,6 +244,26 @@ The launcher loads `.ai/.env`, runs optional pre/post hooks, changes to the
|
|
|
240
244
|
project root, and passes all arguments to `codex`. It does not install native
|
|
241
245
|
Codex Skills or instructions and does not activate approved context-pack skills.
|
|
242
246
|
|
|
247
|
+
Codex uses MCP annotations when deciding whether a tool needs approval. In
|
|
248
|
+
non-interactive `codex exec`, an unapproved mutating call is cancelled rather
|
|
249
|
+
than silently executed. Cairnkeep intentionally does not autoapprove memory
|
|
250
|
+
writes during setup. An operator who has explicitly authorized a bounded,
|
|
251
|
+
unattended workflow may add narrow per-tool policy to the isolated Codex config:
|
|
252
|
+
|
|
253
|
+
```toml
|
|
254
|
+
[mcp_servers.cairn-memory.tools.memory_write]
|
|
255
|
+
approval_mode = "approve"
|
|
256
|
+
|
|
257
|
+
[mcp_servers.cairn-memory.tools.memory_supersede]
|
|
258
|
+
approval_mode = "approve"
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Do not add this to shared or ordinary interactive configuration merely to avoid
|
|
262
|
+
prompts. Keep the allowlist limited to the authorized tools and continue to use
|
|
263
|
+
Cairn MCP profiles and project isolation. See the
|
|
264
|
+
[official Codex MCP configuration reference](https://developers.openai.com/codex/mcp)
|
|
265
|
+
for approval-mode semantics.
|
|
266
|
+
|
|
243
267
|
## Candidate memory clients
|
|
244
268
|
|
|
245
269
|
The following clients have documented MCP support and are reasonable adapter
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Curriculum Coverage Map
|
|
2
2
|
|
|
3
|
-
**Baseline:** Cairnkeep 2.15.
|
|
4
|
-
**Last reviewed:** 2026-08-
|
|
3
|
+
**Baseline:** Cairnkeep 2.15.3
|
|
4
|
+
**Last reviewed:** 2026-08-18
|
|
5
5
|
|
|
6
6
|
This map prevents the course from drifting behind the product. It assigns each
|
|
7
7
|
user-facing surface to a lesson and records whether the lesson is complete or
|
|
@@ -40,7 +40,7 @@ been rehearsed.
|
|
|
40
40
|
| Guided project setup, selected harness state, and Git-less limitations | L03 | L03 and L23 | Ready |
|
|
41
41
|
| Pi local stdio memory bridge, trusted annotation details, and explicit lifecycle | L23 | L23 | Ready; Pi 0.84.1 validated minimum |
|
|
42
42
|
| OKF 0.1/0.2 validation/import, provenance, links, regressions, and reviewed 0.2 export | L24 | L24 | Ready; local/offline by default |
|
|
43
|
-
| Bounded project playbooks,
|
|
43
|
+
| Bounded project playbooks, generic memory retrieval guidance, enforcement, and private receipts | L25 | L25 | Ready; balanced/local by default; invocation requires runtime evidence; actor identity unverified |
|
|
44
44
|
|
|
45
45
|
## Release Review
|
|
46
46
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Cairnkeep feature guide
|
|
2
2
|
|
|
3
|
-
**Baseline:** Cairnkeep 2.15.
|
|
3
|
+
**Baseline:** Cairnkeep 2.15.3
|
|
4
4
|
|
|
5
5
|
This is the step-back map for choosing and operating Cairnkeep features. The
|
|
6
6
|
[course labs](https://github.com/cairnkeep/cairnkeep-course-labs) provide one
|
|
@@ -20,6 +20,10 @@ deterministic links, and reviewed OKF 0.2 export; see
|
|
|
20
20
|
[L24](lessons/L24-okf-exchange.md).
|
|
21
21
|
Version 2.15 adds local bounded playbooks and private outcome receipts; see
|
|
22
22
|
[L25](lessons/L25-playbooks.md).
|
|
23
|
+
Version 2.15.3 makes generic task-derived, project-scoped retrieval precede
|
|
24
|
+
repository inventory or search and adds executable playbook receipt guidance
|
|
25
|
+
with command-scoped help. Retrieval remains a locator and actual tool
|
|
26
|
+
invocation must be verified from runtime evidence.
|
|
23
27
|
|
|
24
28
|
## The three-layer model
|
|
25
29
|
|
|
@@ -65,7 +69,7 @@ prerequisites for ordinary memory.
|
|
|
65
69
|
| Repository quality | `/repo-review`, `/security-audit` | On-demand workflow; findings are hypotheses until reproduced | Require file/line evidence and regression tests | `course-03-quality` |
|
|
66
70
|
| Guided project setup | `cairn setup PATH --git init\|existing\|none --harness LIST --memory local\|none --yes` | Reconciles only selected project assets from one harness registry; private `.ai/cairnkeep.json`; machine sync is never automatic | Repeat deterministically, run doctor, or replay its recovery command; Git-less mode remains limited | `course-12-guided-setup` |
|
|
67
71
|
| Codex project memory | Select `--harness codex --memory local` | Writes `.codex/config.toml` plus POSIX/native Windows launchers; local stdio; user-wide configuration and trust remain untouched | Review the MCP table, accept Codex project trust, run doctor, and relaunch; uninstall is backup-first | `course-01-bootstrap` |
|
|
68
|
-
| Workflow playbooks | `cairn playbook check start|check|finish`; project `minimal`, `balanced`, or `strict` policy | Balanced by default; private `.ai/playbooks.json`; optional receipts in `.agentfs/playbooks/`; checks are offline and execute nothing |
|
|
72
|
+
| Workflow playbooks and durable-context guidance | `cairn playbook check start|check|finish`; project `minimal`, `balanced`, or `strict` policy; managed `AGENTS.md` retrieval protocol | Balanced by default; private `.ai/playbooks.json`; one task-derived project search when applicable; optional receipts in `.agentfs/playbooks/`; checks are offline and execute nothing | Verify the actual memory tool event and maintained source, inspect status/digests, enforce truthful `must` evidence, inspect receipts, reset overrides, remove only the managed `AGENTS.md` block | `course-13-playbooks` |
|
|
69
73
|
|
|
70
74
|
## Storage and optional topology
|
|
71
75
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# L25 - Bounded workflow playbooks
|
|
2
2
|
|
|
3
3
|
**Status:** Ready
|
|
4
|
-
**Tested with:** Cairnkeep 2.15.
|
|
4
|
+
**Tested with:** Cairnkeep 2.15.3 and Node.js 22 or newer
|
|
5
5
|
**Time:** 35 minutes
|
|
6
6
|
|
|
7
7
|
## Outcome
|
|
@@ -65,6 +65,10 @@ cairn playbook receipts list
|
|
|
65
65
|
cairn playbook doctor
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
`cairn playbook record --help` prints this command's bounded event, action,
|
|
69
|
+
outcome, identity, session, project, and output options. A receipt records one
|
|
70
|
+
action outcome; use another call only for another material outcome.
|
|
71
|
+
|
|
68
72
|
Try a bounded customization, then restore the profile behavior:
|
|
69
73
|
|
|
70
74
|
```bash
|
|
@@ -86,6 +90,13 @@ cairn playbook set balanced
|
|
|
86
90
|
|
|
87
91
|
## Privacy and trust boundary
|
|
88
92
|
|
|
93
|
+
The managed `AGENTS.md` block also gives compatible agents a bounded durable
|
|
94
|
+
context protocol: derive one short project query before repository inventory or search,
|
|
95
|
+
treat memory as a locator, and verify the maintained source. It does not
|
|
96
|
+
contain a task-specific query or authorize an automatic memory write. When
|
|
97
|
+
evaluating the protocol, inspect the actual `memory_search` event rather than
|
|
98
|
+
assuming the instruction was followed.
|
|
99
|
+
|
|
89
100
|
Checks are offline and store nothing. Explicit receipts contain bounded
|
|
90
101
|
identifiers, digests, event/action/outcome/reason, and a timestamp, but no
|
|
91
102
|
prompt, file body, diff, command output, credential, or environment snapshot.
|
|
@@ -111,4 +122,6 @@ rm -rf "$lab"
|
|
|
111
122
|
evidence clears the relevant block.
|
|
112
123
|
- The receipt is private, project-bound, bounded, and visible to `doctor`.
|
|
113
124
|
- Removing managed instructions preserves all surrounding `AGENTS.md` content.
|
|
125
|
+
- The installed memory guidance contains no task-specific query and degrades to
|
|
126
|
+
ordinary inspection when `memory_search` is unavailable.
|
|
114
127
|
- No check executes an action, contacts a network service, or grants approval.
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
harness remains the agent runtime and every approval remains in force.
|
|
10
10
|
2. Run guided setup in a synthetic project. Show `.ai/playbooks.json` mode and
|
|
11
11
|
the delimited Cairnkeep block inside an `AGENTS.md` that already has user
|
|
12
|
-
content.
|
|
12
|
+
content. Point out the generic durable-context protocol: it derives a query
|
|
13
|
+
from the task before repository inventory or search, treats memory as a
|
|
14
|
+
locator, and never writes automatically.
|
|
13
15
|
3. Compare `minimal`, `balanced`, and `strict` with `cairn playbook status`.
|
|
14
16
|
Customize one canonical action and show that an arbitrary command or unknown
|
|
15
17
|
field is rejected.
|
|
@@ -18,12 +20,13 @@
|
|
|
18
20
|
5. Run a security-sensitive `check finish --enforce` without evidence and show
|
|
19
21
|
exit 3. Perform synthetic verification, then re-run with completed and
|
|
20
22
|
reasoned skipped evidence.
|
|
21
|
-
6.
|
|
22
|
-
|
|
23
|
-
absent.
|
|
23
|
+
6. Run `cairn playbook record --help`, then record one outcome with exact
|
|
24
|
+
policy and decision digests. Inspect the private receipt and show that
|
|
25
|
+
changed paths, prompts, source, and output are absent.
|
|
24
26
|
7. Show `/cairn-work` in Claude or OpenCode and the portable `AGENTS.md`
|
|
25
27
|
guidance for Codex/Qwen. State that adapters route to the same CLI and do not
|
|
26
|
-
automatically activate skills.
|
|
28
|
+
automatically activate skills. Show one real `memory_search` event so the
|
|
29
|
+
instruction is not mistaken for proof of invocation.
|
|
27
30
|
8. Remove the managed instruction block, prove user instructions remain, and
|
|
28
31
|
close on the design-only team boundary.
|
|
29
32
|
|
package/docs/operating.md
CHANGED
|
@@ -838,6 +838,16 @@ project's `AGENTS.md`. `--untracked` bootstrap leaves the shared `AGENTS.md`
|
|
|
838
838
|
untouched. The policy can select only eight canonical Cairnkeep actions; it
|
|
839
839
|
cannot contain commands, prompts, URLs, or extensions.
|
|
840
840
|
|
|
841
|
+
The same ownership-safe block contains a generic durable-context protocol. For
|
|
842
|
+
nontrivial work that may depend on existing decisions, conventions,
|
|
843
|
+
constraints, recurring failures, or prior work, compatible agents derive one
|
|
844
|
+
short query directly from the task and call `memory_search` with
|
|
845
|
+
`scope: project` before repository inventory or search commands such as
|
|
846
|
+
`rg --files`, `find`, `tree`, or broad text search. A result is only a locator:
|
|
847
|
+
the maintained repository source must still be read and verified. Missing
|
|
848
|
+
tools and zero results fall back to normal inspection, and the protocol never
|
|
849
|
+
authorizes an automatic memory write, supersede, or approval.
|
|
850
|
+
|
|
841
851
|
```bash
|
|
842
852
|
cairn playbook list
|
|
843
853
|
cairn playbook status --project .
|
|
@@ -864,12 +874,20 @@ advisory and should carry a concrete `--skipped ACTION=REASON` when omitted.
|
|
|
864
874
|
Checking never executes the displayed commands, contacts a service, enables a
|
|
865
875
|
capability, or grants approval.
|
|
866
876
|
|
|
867
|
-
Material outcomes can be stored
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
877
|
+
Material outcomes can be stored one action per call using the exact policy and
|
|
878
|
+
decision digests from the check:
|
|
879
|
+
|
|
880
|
+
```bash
|
|
881
|
+
cairn playbook record --policy POLICY_DIGEST --decision DECISION_DIGEST \
|
|
882
|
+
--event finish --action verify.tests --outcome completed \
|
|
883
|
+
--session SESSION --reason 'targeted tests passed'
|
|
884
|
+
cairn playbook record --help
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
Inspect receipts with `cairn playbook receipts list|show`; validate state with
|
|
888
|
+
`cairn playbook doctor`. Actor and session options are provenance labels only:
|
|
889
|
+
v2.15 does not authenticate them and does not provide team ACLs. See
|
|
890
|
+
[team mode](design/team-mode.md) for the future admission contract.
|
|
873
891
|
|
|
874
892
|
The managed instruction lifecycle is explicit and ownership-safe:
|
|
875
893
|
|
|
@@ -881,8 +899,10 @@ cairn playbook instructions remove
|
|
|
881
899
|
|
|
882
900
|
Claude and OpenCode receive `/cairn-work`; Pi and Kimi receive corresponding
|
|
883
901
|
thin prompt/Skill adapters when their explicit machine sync runs. Codex and
|
|
884
|
-
Qwen follow the project `AGENTS.md` block.
|
|
885
|
-
|
|
902
|
+
Qwen follow the project `AGENTS.md` block. Instruction exposure does not prove
|
|
903
|
+
tool invocation, so evaluations and audits should verify the actual
|
|
904
|
+
`memory_search` event. These surfaces route to the same CLI and do not create a
|
|
905
|
+
Cairnkeep-owned agent loop.
|
|
886
906
|
|
|
887
907
|
## The workflow
|
|
888
908
|
|
package/docs/quickstart.md
CHANGED
|
@@ -70,8 +70,11 @@ result should survive the restart.
|
|
|
70
70
|
|
|
71
71
|
`cairn setup` creates only the selected harness assets plus the common `.ai`,
|
|
72
72
|
`.planning`, and `.agentfs` scaffold. It also reconciles Cairnkeep's delimited
|
|
73
|
-
|
|
74
|
-
file mode.
|
|
73
|
+
instruction block in `AGENTS.md` while preserving every surrounding user byte
|
|
74
|
+
and file mode. The block tells compatible agents when to make one
|
|
75
|
+
task-derived, project-scoped memory search, to verify maintained repository
|
|
76
|
+
sources, and never to promote memory automatically. It initializes Git only
|
|
77
|
+
with explicit
|
|
75
78
|
`--git init`, preserves unrelated files, does not overwrite modified files it
|
|
76
79
|
does not own, and records managed digests in private `.ai/cairnkeep.json`.
|
|
77
80
|
|
|
@@ -90,12 +93,15 @@ workflow checks apply. Inspect it directly before relying on agent routing:
|
|
|
90
93
|
cairn playbook status
|
|
91
94
|
cairn playbook check start --complexity standard --familiarity mixed
|
|
92
95
|
cairn playbook check finish --changed README.md --completed docs.update --enforce
|
|
96
|
+
cairn playbook record --help
|
|
93
97
|
```
|
|
94
98
|
|
|
95
99
|
`must` can produce a non-zero enforcement result; `should` is advisory with a
|
|
96
100
|
recorded reason when skipped; `may` is optional. A decision executes nothing
|
|
97
|
-
and grants no permission.
|
|
98
|
-
|
|
101
|
+
and grants no permission. The memory protocol also degrades to ordinary
|
|
102
|
+
repository inspection when the tool is unavailable or returns no relevant
|
|
103
|
+
result. `cairn playbook instructions remove` removes only the managed
|
|
104
|
+
`AGENTS.md` block, including that protocol.
|
|
99
105
|
|
|
100
106
|
For all harnesses, remote HTTP, storage, profiles, context packs, overlays, and
|
|
101
107
|
recovery details, continue with [Operating Cairnkeep](operating.md) or the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"identifier":"cairn-offline-fake-v1","package_version":"2.15.
|
|
1
|
+
{"identifier":"cairn-offline-fake-v1","package_version":"2.15.3","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
|
|
@@ -36,6 +36,37 @@ contacts a network service, or grants approval. Actor identity is caller-supplie
|
|
|
36
36
|
and unauthenticated until a future team deployment binds it to authentication.
|
|
37
37
|
`;
|
|
38
38
|
}
|
|
39
|
+
function checkUsage() {
|
|
40
|
+
return `Usage:
|
|
41
|
+
cairn playbook check start|check|finish [signals] [evidence] [--enforce] [--json]
|
|
42
|
+
|
|
43
|
+
Signals:
|
|
44
|
+
--complexity trivial|standard|complex --familiarity known|mixed|unfamiliar
|
|
45
|
+
--risk low|normal|high|security --public-change
|
|
46
|
+
--changed PATH... --change-type TYPE...
|
|
47
|
+
|
|
48
|
+
Evidence and provenance:
|
|
49
|
+
--completed ACTION... --skipped ACTION=REASON...
|
|
50
|
+
--failed ACTION=REASON... --actor ID --actor-kind user|agent|service
|
|
51
|
+
--session ID
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
function recordUsage() {
|
|
55
|
+
return `Usage:
|
|
56
|
+
cairn playbook record --policy DIGEST --decision DIGEST --event start|check|finish \\
|
|
57
|
+
--action ACTION --outcome completed|skipped|failed [--reason REASON] \\
|
|
58
|
+
[--actor ID] [--actor-kind user|agent|service] [--session ID] \\
|
|
59
|
+
[--project PATH] [--json]
|
|
60
|
+
|
|
61
|
+
Record one material action outcome per call using the exact policy and decision
|
|
62
|
+
digests returned by the corresponding check. Actor identity is caller-supplied
|
|
63
|
+
and unauthenticated in this release.
|
|
64
|
+
|
|
65
|
+
Actions:
|
|
66
|
+
context.recall context.explore work.plan verify.tests
|
|
67
|
+
review.repository review.security docs.update learning.capture
|
|
68
|
+
`;
|
|
69
|
+
}
|
|
39
70
|
const VALUE_OPTIONS = new Set([
|
|
40
71
|
"--project", "--complexity", "--familiarity", "--risk", "--changed", "--change-type",
|
|
41
72
|
"--completed", "--skipped", "--failed", "--actor", "--actor-kind", "--session",
|
|
@@ -214,6 +245,13 @@ async function main() {
|
|
|
214
245
|
process.stdout.write(usage());
|
|
215
246
|
return;
|
|
216
247
|
}
|
|
248
|
+
if (["check", "record"].includes(command) && raw.length === 1 && ["--help", "-h"].includes(raw[0])) {
|
|
249
|
+
if (command === "check")
|
|
250
|
+
process.stdout.write(checkUsage());
|
|
251
|
+
else
|
|
252
|
+
process.stdout.write(recordUsage());
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
217
255
|
const parsed = parse(raw);
|
|
218
256
|
if (command === "list") {
|
|
219
257
|
ensureAllowed(parsed, [], ["--json"]);
|
|
@@ -8,6 +8,7 @@ const MAX_CONFIG_BYTES = 64 * 1024;
|
|
|
8
8
|
const LOCK_ATTEMPTS = 200;
|
|
9
9
|
const LOCK_WAIT_MS = 10;
|
|
10
10
|
const SESSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
11
|
+
const localLockTails = new Map();
|
|
11
12
|
export const PLAYBOOK_ACTIONS = Object.freeze([
|
|
12
13
|
{ id: "context.recall", title: "Recall durable context", command: "/recall <task topic>", description: "Read accepted project memory and derived knowledge before committing to an approach." },
|
|
13
14
|
{ id: "context.explore", title: "Explore focused code context", command: "/context-explore <question>", description: "Collect compact citations when the relevant code is unfamiliar or structurally complex." },
|
|
@@ -180,35 +181,72 @@ export async function resolvePlaybookStatus(options = {}) {
|
|
|
180
181
|
issues,
|
|
181
182
|
};
|
|
182
183
|
}
|
|
184
|
+
async function acquireLocalLock(lock) {
|
|
185
|
+
let state = localLockTails.get(lock);
|
|
186
|
+
if (!state) {
|
|
187
|
+
state = { tail: Promise.resolve(), users: 0 };
|
|
188
|
+
localLockTails.set(lock, state);
|
|
189
|
+
}
|
|
190
|
+
const predecessor = state.tail;
|
|
191
|
+
let releaseGate;
|
|
192
|
+
const gate = new Promise((resolveGate) => { releaseGate = resolveGate; });
|
|
193
|
+
state.tail = predecessor.then(() => gate);
|
|
194
|
+
state.users += 1;
|
|
195
|
+
await predecessor;
|
|
196
|
+
let released = false;
|
|
197
|
+
return () => {
|
|
198
|
+
if (released)
|
|
199
|
+
return;
|
|
200
|
+
released = true;
|
|
201
|
+
releaseGate();
|
|
202
|
+
state.users -= 1;
|
|
203
|
+
if (state.users === 0 && localLockTails.get(lock) === state)
|
|
204
|
+
localLockTails.delete(lock);
|
|
205
|
+
};
|
|
206
|
+
}
|
|
183
207
|
async function acquireLock(lock) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return () => rm(lock, { recursive: true, force: true });
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
const code = error.code;
|
|
191
|
-
if (code !== "EEXIST" && !(process.platform === "win32" && code === "EPERM"))
|
|
192
|
-
throw error;
|
|
208
|
+
const releaseLocal = await acquireLocalLock(lock);
|
|
209
|
+
try {
|
|
210
|
+
for (let attempt = 0; attempt < LOCK_ATTEMPTS; attempt += 1) {
|
|
193
211
|
try {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
212
|
+
await mkdir(lock, { mode: 0o700 });
|
|
213
|
+
return async () => {
|
|
214
|
+
try {
|
|
215
|
+
await rm(lock, { recursive: true, force: true });
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
releaseLocal();
|
|
219
|
+
}
|
|
220
|
+
};
|
|
197
221
|
}
|
|
198
|
-
catch (
|
|
199
|
-
const
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
await
|
|
204
|
-
|
|
222
|
+
catch (error) {
|
|
223
|
+
const code = error.code;
|
|
224
|
+
if (code !== "EEXIST" && !(process.platform === "win32" && code === "EPERM"))
|
|
225
|
+
throw error;
|
|
226
|
+
try {
|
|
227
|
+
const info = await lstat(lock);
|
|
228
|
+
if (!info.isDirectory() || info.isSymbolicLink())
|
|
229
|
+
throw new Error("Playbook configuration lock is unsafe.");
|
|
230
|
+
}
|
|
231
|
+
catch (inspectionError) {
|
|
232
|
+
const inspectionCode = inspectionError.code;
|
|
233
|
+
if (inspectionCode === "ENOENT")
|
|
234
|
+
continue;
|
|
235
|
+
if (process.platform === "win32" && (inspectionCode === "EPERM" || inspectionCode === "EBUSY")) {
|
|
236
|
+
await delay(LOCK_WAIT_MS);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
throw inspectionError;
|
|
205
240
|
}
|
|
206
|
-
|
|
241
|
+
await delay(LOCK_WAIT_MS);
|
|
207
242
|
}
|
|
208
|
-
await delay(LOCK_WAIT_MS);
|
|
209
243
|
}
|
|
244
|
+
throw new Error("Playbook configuration is locked; retry after the active update finishes.");
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
releaseLocal();
|
|
248
|
+
throw error;
|
|
210
249
|
}
|
|
211
|
-
throw new Error("Playbook configuration is locked; retry after the active update finishes.");
|
|
212
250
|
}
|
|
213
251
|
async function atomicConfigWrite(path, value) {
|
|
214
252
|
const bytes = Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8");
|
package/package.json
CHANGED
|
@@ -28,6 +28,14 @@ env -u CAIRN_NOTE_DISTILLATION "$cairn" notes --help >/dev/null 2>&1 || fail "ca
|
|
|
28
28
|
"$cairn" artifact --help | grep -q "cairn artifact list" || fail "cairn artifact dispatch"
|
|
29
29
|
"$cairn" evidence --help | grep -q "cairn evidence list" || fail "cairn evidence dispatch"
|
|
30
30
|
"$cairn" playbook --help | grep -q "cairn playbook list" || fail "cairn playbook dispatch"
|
|
31
|
+
"$cairn" playbook check --help | grep -q "check start|check|finish" || fail "cairn playbook check help"
|
|
32
|
+
"$cairn" playbook record --help >"$tmp/playbook-record-help" || fail "cairn playbook record help"
|
|
33
|
+
grep -qF -- '--event start|check|finish' "$tmp/playbook-record-help" || fail "playbook record help missing events"
|
|
34
|
+
grep -qF -- '--outcome completed|skipped|failed' "$tmp/playbook-record-help" || fail "playbook record help missing outcomes"
|
|
35
|
+
grep -qF 'review.security' "$tmp/playbook-record-help" || fail "playbook record help missing actions"
|
|
36
|
+
if "$cairn" playbook unknown --help >/dev/null 2>&1; then
|
|
37
|
+
fail "unknown playbook command help should fail"
|
|
38
|
+
fi
|
|
31
39
|
"$cairn" capabilities --help >"$tmp/capabilities-help" 2>/dev/null || fail "cairn capabilities dispatch"
|
|
32
40
|
"$cairn" mcp-tools list --json >"$tmp/mcp-tools.json" || fail "cairn mcp-tools dispatch"
|
|
33
41
|
CAIRN_PACK_BASE_DIR="$tmp/pack-store" "$cairn" pack list --json >"$tmp/packs.json" || fail "cairn pack dispatch"
|
|
@@ -153,6 +153,8 @@ for phrase in \
|
|
|
153
153
|
'cairn playbook check finish' \
|
|
154
154
|
'--enforce' \
|
|
155
155
|
'cairn playbook record' \
|
|
156
|
+
'cairn playbook record --help' \
|
|
157
|
+
'before repository inventory or search' \
|
|
156
158
|
'unauthenticated' \
|
|
157
159
|
'does not run'; do
|
|
158
160
|
grep -qF -- "$phrase" "$l25" || {
|
|
@@ -50,6 +50,10 @@ bootstrap_output=$(cairn bootstrap "$tmp/project")
|
|
|
50
50
|
[[ -f "$tmp/project/.planning/config.json" ]] || fail "bootstrap did not install the planning scaffold"
|
|
51
51
|
[[ -f "$tmp/project/.ai/playbooks.json" ]] || fail "bootstrap did not install the playbook policy"
|
|
52
52
|
grep -qF '<!-- cairnkeep:playbook:v1:start -->' "$tmp/project/AGENTS.md" || fail "bootstrap did not install playbook agent guidance"
|
|
53
|
+
grep -qF 'derive one short query from the task' "$tmp/project/AGENTS.md" || fail "bootstrap did not install generic memory retrieval guidance"
|
|
54
|
+
grep -qF 'before running repository inventory or search' "$tmp/project/AGENTS.md" || fail "bootstrap did not install retrieval ordering guidance"
|
|
55
|
+
grep -qF 'cairn playbook record --help' "$tmp/project/AGENTS.md" || fail "bootstrap did not install actionable receipt guidance"
|
|
56
|
+
grep -qF 'Treat returned memory as a locator, not authority.' "$tmp/project/AGENTS.md" || fail "bootstrap did not install memory provenance guidance"
|
|
53
57
|
|
|
54
58
|
(cd "$tmp/project" && cairn doctor) >/dev/null || fail "installed package failed cairn doctor"
|
|
55
59
|
env -u CAIRN_NOTE_DISTILLATION cairn notes --help >/dev/null \
|
|
@@ -12,6 +12,15 @@ chmod 0640 "$project/AGENTS.md"
|
|
|
12
12
|
node "$ROOT/scripts/playbook-instructions.mjs" "$project" >/dev/null
|
|
13
13
|
grep -qF 'Keep this line.' "$project/AGENTS.md"
|
|
14
14
|
[[ $(grep -cF '<!-- cairnkeep:playbook:v1:start -->' "$project/AGENTS.md") -eq 1 ]]
|
|
15
|
+
grep -qF 'derive one short query from the task' "$project/AGENTS.md"
|
|
16
|
+
grep -qF 'search `scope: project` once' "$project/AGENTS.md"
|
|
17
|
+
grep -qF 'before running repository inventory or search' "$project/AGENTS.md"
|
|
18
|
+
grep -qF '`rg --files`, `find`, `tree`' "$project/AGENTS.md"
|
|
19
|
+
grep -qF "do not inspect" "$project/AGENTS.md"
|
|
20
|
+
grep -qF 'Treat returned memory as a locator, not authority.' "$project/AGENTS.md"
|
|
21
|
+
grep -qF 'Do not write, supersede, or approve durable memory' "$project/AGENTS.md"
|
|
22
|
+
grep -qF 'cairn playbook record --policy POLICY_DIGEST --decision DECISION_DIGEST' "$project/AGENTS.md"
|
|
23
|
+
grep -qF 'cairn playbook record --help' "$project/AGENTS.md"
|
|
15
24
|
[[ $(stat -c '%a' "$project/AGENTS.md") == 640 ]]
|
|
16
25
|
before=$(sha256sum "$project/AGENTS.md" | cut -d' ' -f1)
|
|
17
26
|
node "$ROOT/scripts/playbook-instructions.mjs" "$project" >/dev/null
|
|
@@ -22,6 +31,7 @@ after=$(sha256sum "$project/AGENTS.md" | cut -d' ' -f1)
|
|
|
22
31
|
node "$ROOT/scripts/playbook-instructions.mjs" "$project" --remove >/dev/null
|
|
23
32
|
grep -qF 'Keep this line.' "$project/AGENTS.md"
|
|
24
33
|
! grep -qF 'cairnkeep:playbook' "$project/AGENTS.md"
|
|
34
|
+
! grep -qF 'Cairnkeep Durable Context' "$project/AGENTS.md"
|
|
25
35
|
|
|
26
36
|
printf '%s\n%s\n%s\n' \
|
|
27
37
|
'<!-- cairnkeep:playbook:v1:start -->' \
|
|
@@ -40,6 +40,10 @@ try {
|
|
|
40
40
|
assert.match(launcherPowerShell(), /evidence run --harness/);
|
|
41
41
|
assert.match(launcherPowerShell(), /CAIRN_WORK_EVIDENCE/);
|
|
42
42
|
assert.match(readFileSync(join(project, "AGENTS.md"), "utf8"), /cairnkeep:playbook:v1:start/);
|
|
43
|
+
assert.match(readFileSync(join(project, "AGENTS.md"), "utf8"), /derive one short query from the task/);
|
|
44
|
+
assert.match(readFileSync(join(project, "AGENTS.md"), "utf8"), /before running repository inventory or search/);
|
|
45
|
+
assert.match(readFileSync(join(project, "AGENTS.md"), "utf8"), /cairn playbook record --help/);
|
|
46
|
+
assert.match(readFileSync(join(project, "AGENTS.md"), "utf8"), /Treat returned memory as a locator, not authority\./);
|
|
43
47
|
assert.match(readFileSync(join(project, "AGENTS.md"), "utf8"), /Keep this line\./);
|
|
44
48
|
|
|
45
49
|
const claudeRoot = join(sandbox, "Claude Config");
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
<!-- cairnkeep:playbook:v1:start -->
|
|
2
|
+
## Cairnkeep Durable Context
|
|
3
|
+
|
|
4
|
+
At the start of a nontrivial task that may depend on existing project
|
|
5
|
+
decisions, conventions, constraints, recurring failures, or prior work,
|
|
6
|
+
perform this retrieval step before running repository inventory or search
|
|
7
|
+
commands such as `rg --files`, `find`, `tree`, or broad text searches:
|
|
8
|
+
|
|
9
|
+
- If `memory_search` is available, derive one short query from the task and
|
|
10
|
+
search `scope: project` once. Derive it from the user's task; do not inspect
|
|
11
|
+
the repository first merely to formulate the query.
|
|
12
|
+
- Treat returned memory as a locator, not authority. Read and verify the
|
|
13
|
+
maintained repository sources it references before implementing a result.
|
|
14
|
+
- If the tool is unavailable or no relevant result exists, continue with
|
|
15
|
+
ordinary repository inspection. Do not repeat or broaden searches merely to
|
|
16
|
+
force a result.
|
|
17
|
+
- Do not write, supersede, or approve durable memory unless the user or an
|
|
18
|
+
applicable reviewed workflow explicitly requests capture.
|
|
19
|
+
|
|
2
20
|
## Cairnkeep Playbooks
|
|
3
21
|
|
|
4
22
|
Use Cairnkeep's bounded playbook policy to select workflow steps. It advises or
|
|
@@ -8,7 +26,7 @@ enforces existing capabilities; it does not execute a workflow for you.
|
|
|
8
26
|
- Re-run `cairn playbook check check` when scope, familiarity, complexity, or risk changes materially.
|
|
9
27
|
- Before claiming completion, run `cairn playbook check finish --session SESSION --changed PATH... --risk LEVEL --public-change --completed ACTION... --skipped ACTION=REASON... --enforce` with accurate signals and evidence.
|
|
10
28
|
- A non-zero enforcement result means applicable `must` evidence is missing. Perform the action and check again; do not relabel a skipped or failed action as completed.
|
|
11
|
-
-
|
|
29
|
+
- After a successful finish check, record only material outcomes with `cairn playbook record --policy POLICY_DIGEST --decision DECISION_DIGEST --event finish --action ACTION --outcome OUTCOME --session SESSION [--reason REASON]`, using one call per recorded action and the exact digests returned by the check. Run `cairn playbook record --help` for the bounded values. Actor identity is an unverified local assertion in this release.
|
|
12
30
|
- Existing approval and capability boundaries still apply. A playbook cannot enable a disabled capability, grant approval, write durable memory automatically, run arbitrary commands, or authorize destructive work.
|
|
13
31
|
- If the CLI or an applicable capability is unavailable, state that limitation and follow the policy intent manually; never invent a receipt or successful result.
|
|
14
32
|
<!-- cairnkeep:playbook:v1:end -->
|