@cairnkeep/cli 2.15.0 → 2.15.2

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 CHANGED
@@ -5,6 +5,34 @@ All notable user-facing changes are documented here. This project follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [2.15.2] - 2026-08-18
9
+
10
+ ### Added
11
+
12
+ - Add a generic, ownership-safe durable-context protocol to the managed project
13
+ `AGENTS.md` block. Compatible agents derive one short project-memory query
14
+ before broad exploration when prior decisions or conventions may matter,
15
+ verify referenced repository sources, fall back cleanly when retrieval is
16
+ unavailable, and never promote memory automatically.
17
+ - Extend setup, bootstrap, installed-package, native Windows, uninstall, and
18
+ documentation coverage for the managed retrieval guidance.
19
+
20
+ ### Fixed
21
+
22
+ - Serialize same-process playbook configuration mutations before taking the
23
+ filesystem lock, avoiding Windows CI lock starvation under concurrent
24
+ profile and reset operations while preserving cross-process exclusion.
25
+
26
+ ## [2.15.1] - 2026-08-17
27
+
28
+ ### Fixed
29
+
30
+ - Make concurrent playbook policy updates tolerate lock handoff races,
31
+ including transient Windows directory-removal errors, while retaining
32
+ fail-closed validation for unsafe lock objects.
33
+ - Strengthen the playbook concurrency regression with repeated mixed profile
34
+ and reset operations across the supported Node and Windows CI matrix.
35
+
8
36
  ## [2.15.0] - 2026-08-17
9
37
 
10
38
  ### Added
@@ -398,7 +426,8 @@ stored memories.
398
426
  - Preserve executable permissions and Bash 3.2 portability on macOS.
399
427
  - Add backup-first uninstall and SQLite-safe memory export/import guidance.
400
428
 
401
- [Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.15.0...HEAD
429
+ [Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.15.1...HEAD
430
+ [2.15.1]: https://github.com/cairnkeep/cairnkeep/compare/v2.15.0...v2.15.1
402
431
  [2.15.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.14.0...v2.15.0
403
432
  [2.14.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.13.1...v2.14.0
404
433
  [2.13.1]: https://github.com/cairnkeep/cairnkeep/compare/v2.13.0...v2.13.1
package/README.md CHANGED
@@ -51,6 +51,9 @@ 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.2 adds a generic durable-context protocol to the ownership-safe
55
+ managed project instructions so compatible agents can derive one project
56
+ memory query before broad exploration and verify its repository provenance.
54
57
 
55
58
  ## Compatibility
56
59
 
@@ -203,7 +206,11 @@ The exact command rendering depends on the client. Any MCP client can call
203
206
  `memory_write` and `memory_search` directly.
204
207
 
205
208
  Setup also installs a balanced `.ai/playbooks.json` policy and an ownership-safe
206
- managed block in `AGENTS.md`. Agents can evaluate it at task boundaries:
209
+ managed block in `AGENTS.md`. The block directs compatible agents to make one
210
+ task-derived, project-scoped memory search for nontrivial work involving prior
211
+ decisions, conventions, constraints, or failures. Results are locators, not
212
+ authority; referenced repository sources must be verified, and memory is never
213
+ promoted automatically. Agents can evaluate the playbook at task boundaries:
207
214
 
208
215
  ```bash
209
216
  cairn playbook check start --complexity standard --familiarity mixed
@@ -17,18 +17,20 @@ 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 playbook
30
- instructions, but not Cairnkeep-specific commands, hooks, agents, or automatic
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. Harness behavior remains probabilistic;
32
+ instruction presence must not be reported as a tool invocation without runtime
33
+ evidence.
32
34
 
33
35
  Every MCP client receives complete tool annotations and may use a Cairnkeep
34
36
  least-authority profile independent of harness assets. Context-pack tools are
@@ -240,6 +242,26 @@ The launcher loads `.ai/.env`, runs optional pre/post hooks, changes to the
240
242
  project root, and passes all arguments to `codex`. It does not install native
241
243
  Codex Skills or instructions and does not activate approved context-pack skills.
242
244
 
245
+ Codex uses MCP annotations when deciding whether a tool needs approval. In
246
+ non-interactive `codex exec`, an unapproved mutating call is cancelled rather
247
+ than silently executed. Cairnkeep intentionally does not autoapprove memory
248
+ writes during setup. An operator who has explicitly authorized a bounded,
249
+ unattended workflow may add narrow per-tool policy to the isolated Codex config:
250
+
251
+ ```toml
252
+ [mcp_servers.cairn-memory.tools.memory_write]
253
+ approval_mode = "approve"
254
+
255
+ [mcp_servers.cairn-memory.tools.memory_supersede]
256
+ approval_mode = "approve"
257
+ ```
258
+
259
+ Do not add this to shared or ordinary interactive configuration merely to avoid
260
+ prompts. Keep the allowlist limited to the authorized tools and continue to use
261
+ Cairn MCP profiles and project isolation. See the
262
+ [official Codex MCP configuration reference](https://developers.openai.com/codex/mcp)
263
+ for approval-mode semantics.
264
+
243
265
  ## Candidate memory clients
244
266
 
245
267
  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.0
4
- **Last reviewed:** 2026-08-17
3
+ **Baseline:** Cairnkeep 2.15.2
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, managed agent guidance, enforcement, and private receipts | L25 | L25 | Ready; balanced/local by default; actor identity unverified |
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.0
3
+ **Baseline:** Cairnkeep 2.15.2
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,9 @@ 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.2 adds generic task-derived, project-scoped memory guidance to the
24
+ same ownership-safe managed instructions. Retrieval remains a locator and
25
+ actual tool invocation must be verified from runtime evidence.
23
26
 
24
27
  ## The three-layer model
25
28
 
@@ -65,7 +68,7 @@ prerequisites for ordinary memory.
65
68
  | 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
69
  | 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
70
  | 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 | Inspect status/digests, enforce truthful `must` evidence, inspect receipts, reset overrides, remove only the managed `AGENTS.md` block | `course-13-playbooks` |
71
+ | 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
72
 
70
73
  ## Storage and optional topology
71
74
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 10 minutes
6
- **Tested with:** Cairnkeep 2.15.0
6
+ **Tested with:** Cairnkeep 2.15.2
7
7
 
8
8
  ## Outcome
9
9
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 15 minutes
6
- **Tested with:** Cairnkeep 2.15.0
6
+ **Tested with:** Cairnkeep 2.15.2
7
7
 
8
8
  ## Outcome
9
9
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 25 minutes
6
- **Tested with:** Cairnkeep 2.15.0 and Node.js 22 or newer
6
+ **Tested with:** Cairnkeep 2.15.2 and Node.js 22 or newer
7
7
 
8
8
  ## Outcome
9
9
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 25 minutes
6
- **Tested with:** Cairnkeep 2.15.0
6
+ **Tested with:** Cairnkeep 2.15.2
7
7
 
8
8
  ## Outcome
9
9
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Evidence and Evaluation
5
5
  **Time:** 50 minutes
6
- **Tested with:** Cairnkeep 2.15.0
6
+ **Tested with:** Cairnkeep 2.15.2
7
7
 
8
8
  ## Outcome
9
9
 
@@ -1,7 +1,7 @@
1
1
  # L20 - Least-authority MCP tool profiles
2
2
 
3
3
  **Status:** Ready
4
- **Tested with:** Cairnkeep 2.15.0 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.15.2 and Node.js 22 or newer
5
5
  **Time:** 25 minutes
6
6
 
7
7
  ## Outcome
@@ -1,7 +1,7 @@
1
1
  # L21 - Immutable context packs and skill approval
2
2
 
3
3
  **Status:** Ready
4
- **Tested with:** Cairnkeep 2.15.0 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.15.2 and Node.js 22 or newer
5
5
  **Time:** 40 minutes
6
6
 
7
7
  ## Outcome
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Operator
5
5
  **Time:** 30 minutes
6
- **Tested with:** Cairnkeep 2.15.0, Windows x64, and Node.js 22 or newer
6
+ **Tested with:** Cairnkeep 2.15.2, Windows x64, and Node.js 22 or newer
7
7
 
8
8
  ## Outcome
9
9
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart and Operator
5
5
  **Time:** 35 minutes
6
- **Tested with:** Cairnkeep 2.15.0; Pi 0.84.1; Node.js 22, 24, and 26
6
+ **Tested with:** Cairnkeep 2.15.2; Pi 0.84.1; Node.js 22, 24, and 26
7
7
 
8
8
  ## Outcome
9
9
 
@@ -1,7 +1,7 @@
1
1
  # L24 - Reviewed knowledge exchange
2
2
 
3
3
  **Status:** Ready
4
- **Tested with:** Cairnkeep 2.15.0 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.15.2 and Node.js 22 or newer
5
5
  **Time:** 35 minutes
6
6
 
7
7
  ## Outcome
@@ -1,7 +1,7 @@
1
1
  # L25 - Bounded workflow playbooks
2
2
 
3
3
  **Status:** Ready
4
- **Tested with:** Cairnkeep 2.15.0 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.15.2 and Node.js 22 or newer
5
5
  **Time:** 35 minutes
6
6
 
7
7
  ## Outcome
@@ -86,6 +86,13 @@ cairn playbook set balanced
86
86
 
87
87
  ## Privacy and trust boundary
88
88
 
89
+ The managed `AGENTS.md` block also gives compatible agents a bounded durable
90
+ context protocol: derive one short project query for a nontrivial task, treat
91
+ memory as a locator, and verify the maintained source. It does not contain a
92
+ task-specific query, force a tool call, or authorize an automatic memory write.
93
+ When evaluating the protocol, inspect the actual `memory_search` event rather
94
+ than assuming the instruction was followed.
95
+
89
96
  Checks are offline and store nothing. Explicit receipts contain bounded
90
97
  identifiers, digests, event/action/outcome/reason, and a timestamp, but no
91
98
  prompt, file body, diff, command output, credential, or environment snapshot.
@@ -111,4 +118,6 @@ rm -rf "$lab"
111
118
  evidence clears the relevant block.
112
119
  - The receipt is private, project-bound, bounded, and visible to `doctor`.
113
120
  - Removing managed instructions preserves all surrounding `AGENTS.md` content.
121
+ - The installed memory guidance contains no task-specific query and degrades to
122
+ ordinary inspection when `memory_search` is unavailable.
114
123
  - No check executes an action, contacts a network service, or grants approval.
@@ -9,7 +9,8 @@
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, treats memory as a locator, and never writes automatically.
13
14
  3. Compare `minimal`, `balanced`, and `strict` with `cairn playbook status`.
14
15
  Customize one canonical action and show that an arbitrary command or unknown
15
16
  field is rejected.
@@ -23,7 +24,8 @@
23
24
  absent.
24
25
  7. Show `/cairn-work` in Claude or OpenCode and the portable `AGENTS.md`
25
26
  guidance for Codex/Qwen. State that adapters route to the same CLI and do not
26
- automatically activate skills.
27
+ automatically activate skills. Show one real `memory_search` event so the
28
+ instruction is not mistaken for proof of invocation.
27
29
  8. Remove the managed instruction block, prove user instructions remain, and
28
30
  close on the design-only team boundary.
29
31
 
package/docs/operating.md CHANGED
@@ -838,6 +838,15 @@ 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 task query and call `memory_search` with `scope: project` before broad
845
+ exploration. A result is only a locator: the maintained repository source must
846
+ still be read and verified. Missing tools and zero results fall back to normal
847
+ inspection, and the protocol never authorizes an automatic memory write,
848
+ supersede, or approval.
849
+
841
850
  ```bash
842
851
  cairn playbook list
843
852
  cairn playbook status --project .
@@ -881,8 +890,10 @@ cairn playbook instructions remove
881
890
 
882
891
  Claude and OpenCode receive `/cairn-work`; Pi and Kimi receive corresponding
883
892
  thin prompt/Skill adapters when their explicit machine sync runs. Codex and
884
- Qwen follow the project `AGENTS.md` block. These surfaces route to the same CLI
885
- and do not create a Cairnkeep-owned agent loop.
893
+ Qwen follow the project `AGENTS.md` block. Instruction exposure does not prove
894
+ tool invocation, so evaluations and audits should verify the actual
895
+ `memory_search` event. These surfaces route to the same CLI and do not create a
896
+ Cairnkeep-owned agent loop.
886
897
 
887
898
  ## The workflow
888
899
 
@@ -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
- playbook block in `AGENTS.md` while preserving every surrounding user byte and
74
- file mode. It initializes Git only with explicit
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
 
@@ -94,8 +97,10 @@ cairn playbook check finish --changed README.md --completed docs.update --enforc
94
97
 
95
98
  `must` can produce a non-zero enforcement result; `should` is advisory with a
96
99
  recorded reason when skipped; `may` is optional. A decision executes nothing
97
- and grants no permission. `cairn playbook instructions remove` removes only the
98
- managed `AGENTS.md` block.
100
+ and grants no permission. The memory protocol also degrades to ordinary
101
+ repository inspection when the tool is unavailable or returns no relevant
102
+ result. `cairn playbook instructions remove` removes only the managed
103
+ `AGENTS.md` block, including that protocol.
99
104
 
100
105
  For all harnesses, remote HTTP, storage, profiles, context packs, overlays, and
101
106
  recovery details, continue with [Operating Cairnkeep](operating.md) or the
@@ -1 +1 @@
1
- {"identifier":"cairn-offline-fake-v1","package_version":"2.15.0","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
1
+ {"identifier":"cairn-offline-fake-v1","package_version":"2.15.2","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
@@ -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,22 +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
- for (let attempt = 0; attempt < LOCK_ATTEMPTS; attempt += 1) {
185
- try {
186
- await mkdir(lock, { mode: 0o700 });
187
- return () => rm(lock, { recursive: true, force: true });
188
- }
189
- catch (error) {
190
- if (error.code !== "EEXIST")
191
- throw error;
192
- const info = await lstat(lock);
193
- if (!info.isDirectory() || info.isSymbolicLink())
194
- throw new Error("Playbook configuration lock is unsafe.");
195
- await delay(LOCK_WAIT_MS);
208
+ const releaseLocal = await acquireLocalLock(lock);
209
+ try {
210
+ for (let attempt = 0; attempt < LOCK_ATTEMPTS; attempt += 1) {
211
+ try {
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
+ };
221
+ }
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;
240
+ }
241
+ await delay(LOCK_WAIT_MS);
242
+ }
196
243
  }
244
+ throw new Error("Playbook configuration is locked; retry after the active update finishes.");
245
+ }
246
+ catch (error) {
247
+ releaseLocal();
248
+ throw error;
197
249
  }
198
- throw new Error("Playbook configuration is locked; retry after the active update finishes.");
199
250
  }
200
251
  async function atomicConfigWrite(path, value) {
201
252
  const bytes = Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cairnkeep/cli",
3
- "version": "2.15.0",
3
+ "version": "2.15.2",
4
4
  "description": "A durable, harness-agnostic memory + context layer for coding agents and MCP clients.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -50,6 +50,8 @@ 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 'Treat returned memory as a locator, not authority.' "$tmp/project/AGENTS.md" || fail "bootstrap did not install memory provenance guidance"
53
55
 
54
56
  (cd "$tmp/project" && cairn doctor) >/dev/null || fail "installed package failed cairn doctor"
55
57
  env -u CAIRN_NOTE_DISTILLATION cairn notes --help >/dev/null \
@@ -12,6 +12,10 @@ 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 'Treat returned memory as a locator, not authority.' "$project/AGENTS.md"
18
+ grep -qF 'Do not write, supersede, or approve durable memory' "$project/AGENTS.md"
15
19
  [[ $(stat -c '%a' "$project/AGENTS.md") == 640 ]]
16
20
  before=$(sha256sum "$project/AGENTS.md" | cut -d' ' -f1)
17
21
  node "$ROOT/scripts/playbook-instructions.mjs" "$project" >/dev/null
@@ -22,6 +26,7 @@ after=$(sha256sum "$project/AGENTS.md" | cut -d' ' -f1)
22
26
  node "$ROOT/scripts/playbook-instructions.mjs" "$project" --remove >/dev/null
23
27
  grep -qF 'Keep this line.' "$project/AGENTS.md"
24
28
  ! grep -qF 'cairnkeep:playbook' "$project/AGENTS.md"
29
+ ! grep -qF 'Cairnkeep Durable Context' "$project/AGENTS.md"
25
30
 
26
31
  printf '%s\n%s\n%s\n' \
27
32
  '<!-- cairnkeep:playbook:v1:start -->' \
@@ -40,6 +40,8 @@ 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"), /Treat returned memory as a locator, not authority\./);
43
45
  assert.match(readFileSync(join(project, "AGENTS.md"), "utf8"), /Keep this line\./);
44
46
 
45
47
  const claudeRoot = join(sandbox, "Claude Config");
@@ -1,4 +1,20 @@
1
1
  <!-- cairnkeep:playbook:v1:start -->
2
+ ## Cairnkeep Durable Context
3
+
4
+ Before broad repository exploration on a nontrivial task that may depend on
5
+ existing project decisions, conventions, constraints, recurring failures, or
6
+ prior work:
7
+
8
+ - If `memory_search` is available, derive one short query from the task and
9
+ search `scope: project` once.
10
+ - Treat returned memory as a locator, not authority. Read and verify the
11
+ maintained repository sources it references before implementing a result.
12
+ - If the tool is unavailable or no relevant result exists, continue with
13
+ ordinary repository inspection. Do not repeat or broaden searches merely to
14
+ force a result.
15
+ - Do not write, supersede, or approve durable memory unless the user or an
16
+ applicable reviewed workflow explicitly requests capture.
17
+
2
18
  ## Cairnkeep Playbooks
3
19
 
4
20
  Use Cairnkeep's bounded playbook policy to select workflow steps. It advises or