@cairnkeep/cli 2.17.3 → 2.19.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/CONTRIBUTING.md +1 -1
  3. package/docs/harness-compatibility.md +48 -0
  4. package/docs/learning/CURRICULUM-MAP.md +2 -1
  5. package/docs/learning/FEATURE-GUIDE.md +2 -1
  6. package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
  7. package/docs/learning/lessons/L01-safe-trial.md +1 -1
  8. package/docs/learning/lessons/L02-installation.md +1 -1
  9. package/docs/learning/lessons/L03-first-project.md +1 -1
  10. package/docs/learning/lessons/L19-validated-skill-improvement.md +1 -1
  11. package/docs/learning/lessons/L20-mcp-tool-profiles.md +1 -1
  12. package/docs/learning/lessons/L21-context-packs.md +1 -1
  13. package/docs/learning/lessons/L22-native-windows.md +1 -1
  14. package/docs/learning/lessons/L23-guided-setup.md +18 -7
  15. package/docs/learning/lessons/L24-okf-exchange.md +1 -1
  16. package/docs/learning/lessons/L25-playbooks.md +1 -1
  17. package/docs/operating.md +13 -6
  18. package/examples/eval/bundled-fake.json +1 -1
  19. package/mcp-memory-server/dist/artifact-schema.js +1 -1
  20. package/mcp-memory-server/dist/pi-bridge-child.js +109 -0
  21. package/mcp-memory-server/dist/pi-mcp-bridge.js +15 -3
  22. package/mcp-memory-server/dist/work-evidence-schema.js +1 -1
  23. package/mcp-memory-server/dist/work-evidence-store.js +1 -1
  24. package/mcp-memory-server/package.json +5 -3
  25. package/omp/extensions/cairnkeep-capture.ts +226 -0
  26. package/omp/extensions/cairnkeep-memory.ts +288 -0
  27. package/package.json +77 -76
  28. package/schemas/artifact.schema.json +1 -1
  29. package/schemas/cairnkeep-setup-policy.schema.json +3 -3
  30. package/schemas/cairnkeep-setup.schema.json +1 -1
  31. package/scripts/cairn-cli.mjs +2 -0
  32. package/scripts/completion.sh +8 -3
  33. package/scripts/harness-registry.mjs +15 -3
  34. package/scripts/lib/omp-capture-stage.mjs +103 -0
  35. package/scripts/setup.mjs +10 -5
  36. package/scripts/sync-omp-assets.sh +96 -0
  37. package/scripts/test-bootstrap-untracked.sh +1 -1
  38. package/scripts/test-cli-dispatch.sh +2 -0
  39. package/scripts/test-completion.sh +4 -2
  40. package/scripts/test-harness-registry.sh +28 -1
  41. package/scripts/test-setup-output.sh +20 -1
  42. package/scripts/test-setup-preflight.mjs +1 -1
  43. package/scripts/test-work-evidence-cli.sh +1 -1
  44. package/scripts/uninstall.sh +1 -0
  45. package/scripts/verify-omp-capture.mjs +370 -0
  46. package/scripts/verify-omp-mcp-bridge.mjs +333 -0
  47. package/templates/start-omp.sh.template +47 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,44 @@ All notable user-facing changes are documented here. This project follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [2.19.0] - 2026-09-28
9
+
10
+ ### Added
11
+
12
+ - Include oh-my-pi (OMP) in guided setup with a project launcher and explicit,
13
+ opt-in machine sync instructions.
14
+ - Report every required machine sync command when multiple harnesses are
15
+ selected, while retaining the singular JSON field for compatibility.
16
+ - Support OMP in opt-in Git-linked work evidence and preserve its diff-artifact
17
+ provenance.
18
+
19
+ ## [2.18.0] - 2026-09-28
20
+
21
+ ### Added
22
+
23
+ - oh-my-pi (omp) integration: `omp/extensions/cairnkeep-memory.ts` registers
24
+ the cairn-memory MCP tools as native omp tools (collision-guarded), and
25
+ `omp/extensions/cairnkeep-capture.ts` stages durable-memory candidates at
26
+ session stop and surfaces them on the next session start, with a
27
+ `/cairn-staged` review command. The bridge runs as a node child process so
28
+ it also works under compiled Bun standalone binaries.
29
+ - `cairn sync-omp` command, bash/zsh/fish completion entries, and
30
+ `verify-omp-mcp-bridge.mjs` / `verify-omp-capture.mjs` verification gates.
31
+ - Smoke gates for the pi-mcp-bridge child environment: Bun node-shim PATH
32
+ stripping, `MCP_HTTP_PORT` isolation, and the node child bridge protocol.
33
+
34
+ ### Fixed
35
+
36
+ - `pi-mcp-bridge` strips Bun `/tmp/bun-node-*` shim dirs from the stdio child
37
+ environment; grandchildren like `cairn memory-server` spawn a real node.
38
+ - Work-evidence smoke used fixed calendar dates that aged past the retention
39
+ window; timestamps are relative to the run.
40
+
41
+ ### Documentation
42
+
43
+ - `docs/harness-compatibility.md`: oh-my-pi (omp) section.
44
+ - `docs/operating.md`: `CAIRN_PI_BRIDGE_COMMAND` / `CAIRN_PI_BRIDGE_ARGS`.
45
+
8
46
  ## [2.17.3] - 2026-09-03
9
47
 
10
48
  ### Security
@@ -534,7 +572,9 @@ stored memories.
534
572
  - Preserve executable permissions and Bash 3.2 portability on macOS.
535
573
  - Add backup-first uninstall and SQLite-safe memory export/import guidance.
536
574
 
537
- [Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.15.1...HEAD
575
+ [Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.19.0...HEAD
576
+ [2.19.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.18.0...v2.19.0
577
+ [2.18.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.17.3...v2.18.0
538
578
  [2.15.1]: https://github.com/cairnkeep/cairnkeep/compare/v2.15.0...v2.15.1
539
579
  [2.15.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.14.0...v2.15.0
540
580
  [2.14.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.13.1...v2.14.0
package/CONTRIBUTING.md CHANGED
@@ -43,7 +43,7 @@ endpoints. They are not part of the default offline test suite.
43
43
  Node-based CLI implementations.
44
44
  - `bin/cairn` is the installed command entry point.
45
45
  - `templates/` contains project scaffolding and managed instruction assets.
46
- - `claude/`, `opencode/`, `pi/`, and `kimi/` contain harness-specific operating
46
+ - `claude/`, `opencode/`, `pi/`, `omp/`, and `kimi/` contain harness-specific operating
47
47
  assets.
48
48
  - `scripts/` contains sync, lifecycle, packaging, and contract checks.
49
49
  - `docs/` contains the versioned user and operator references indexed from
@@ -19,6 +19,7 @@ Cairnkeep commands, hooks or native trajectory capture.
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
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
+ | oh-my-pi (omp) | Memory MCP through maintained local stdio extension (Pi-successor API) | Smoke-tested against the local omp checkout with the deterministic bridge verification |
22
23
  | 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
24
  | Other MCP clients | Memory plus optional domain-knowledge and context-pack tools | Protocol-compatible; not automatically runtime-tested |
24
25
 
@@ -77,6 +78,53 @@ release, together with Node.js 22/24/26, Bash 3.2, and native Windows. The
77
78
  executable paths were distinct; both reported 0.84.1 because that was also the
78
79
  registry-current release.
79
80
 
81
+ ## oh-my-pi (omp)
82
+
83
+ Select OMP in `cairn setup` to create the project launcher, then run
84
+ `cairn sync-omp --apply` explicitly to install
85
+ `extensions/cairnkeep-memory.ts` and `extensions/cairnkeep-capture.ts` under
86
+ the omp agent root (default
87
+ `~/.omp/agent`; `PI_CODING_AGENT_DIR` overrides it, matching omp's agent
88
+ directory resolution). Use `--check` for drift. Uninstall removes only that
89
+ owned path, backup-first.
90
+
91
+ The extension is the Pi memory extension ported to omp's successor extension
92
+ API: it supervises `cairn memory-server` as a local stdio child through the
93
+ same bridge, discovers the effective MCP catalog dynamically, and registers
94
+ each tool natively with omp under its bare MCP name. omp accepts the MCP input
95
+ schema as a plain JSON Schema document and normalizes results to its
96
+ `AgentToolResult` shape, preserving the trusted call metadata in `details`. A
97
+ `cairn-memory` entry in the omp MCP config coexists without collision:
98
+ config-served MCP tools are minted with an `mcp__` name prefix, so the two
99
+ surfaces never claim the same tool name. Server feature gates, capability
100
+ state, and least-authority profiles continue to decide which tools exist.
101
+
102
+ Startup, calls, results, stderr retention, cancellation, and shutdown are
103
+ bounded. The extension adds tools only: it does not run prompts, activate
104
+ context-pack skills, create an autonomous loop, or add a remote transport.
105
+ `bun scripts/verify-omp-mcp-bridge.mjs` renders, loads, and exercises the
106
+ installed extension against a supervised memory server, including catalog
107
+ parity, the result shape, cancellation, shutdown, orphan-freedom, and
108
+ tool-name collision refusal.
109
+
110
+ Sync also installs `extensions/cairnkeep-capture.ts`, the omp port of the
111
+ Claude SessionEnd/SessionStart `memory-capture` + `memory-wakeup` hook pair.
112
+ On the first `session_stop` of a main session (the event never fires for
113
+ task/subagent sessions), it converts the persisted branch to transcript text
114
+ (user/assistant text only, capped at 12000 characters keeping the most recent
115
+ turns) and pipes it to a detached staging child that runs the shared
116
+ extraction and writes candidates to `.planning/memory-staging/` — one file
117
+ per session, retention capped at 5 — so staging completes even if the agent
118
+ process exits first. Candidates are staged for review only: writes to AgentFS
119
+ stay agent-gated via the `memory_write` tool. On `session_start` of the main
120
+ session, staged candidates are surfaced through a UI notification and a
121
+ `deliverAs: "nextTurn"` context message injected at the next user turn; the
122
+ `/cairn-staged` command lists the staged files on demand. Both halves are
123
+ fail-open and skip ephemeral side-turn runtimes whose extension actions are
124
+ not initialized. `bun scripts/verify-omp-capture.mjs` exercises the guards,
125
+ transcript shaping, staging contract, retention cap, session de-dupe, wakeup
126
+ injection, and the skip paths.
127
+
80
128
  ## Kimi Code
81
129
 
82
130
  Kimi Code reads three MCP files, in increasing precedence:
@@ -1,6 +1,6 @@
1
1
  # Curriculum Coverage Map
2
2
 
3
- **Baseline:** Cairnkeep 2.17.3
3
+ **Baseline:** Cairnkeep 2.19.0
4
4
  **Last reviewed:** 2026-08-19
5
5
 
6
6
  This map prevents the course from drifting behind the product. It assigns each
@@ -91,6 +91,7 @@ against `cairn help` so a new command cannot bypass a curriculum decision.
91
91
  | `cairn sync` | L02 |
92
92
  | `cairn sync-pi` | L13 and L23 |
93
93
  | `cairn sync-kimi` | L02 |
94
+ | `cairn sync-omp` | L02 |
94
95
  | `cairn doctor` | L03; advanced repair in L13-L14 |
95
96
  | `cairn playbook` | L25 |
96
97
  | `cairn trajectory` | L13 |
@@ -1,6 +1,6 @@
1
1
  # Cairnkeep feature guide
2
2
 
3
- **Baseline:** Cairnkeep 2.17.3
3
+ **Baseline:** Cairnkeep 2.19.0
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
@@ -86,6 +86,7 @@ prerequisites for ordinary memory.
86
86
  | Context packs | Manual local or commit-pinned Git install plus project enablement | Immutable objects and atomic pointers under `CAIRN_PACK_BASE_DIR`; no background sync | Validate, inspect digest, check/apply update, disable/remove | `course-10-trust-context` |
87
87
  | OKF exchange | `cairn pack validate-okf`, `import-okf`, and preview-confirm `export-okf` | Local import/export by default; explicit file/shared-note allowlist; redacted output | Inspect diagnostics/provenance/output list; exact-digest apply; disable/remove imported pack | `course-10-trust-context` |
88
88
  | Pi local stdio memory | Select Pi during setup, then explicitly run `cairn sync-pi --apply` | Local memory-server child; dynamic effective tool catalog; annotations retained in trusted details, not a native Pi field | `cairn sync-pi --check`, `cairn doctor`, cancel one call, then observe awaited shutdown with no orphan | `course-12-guided-setup` |
89
+ | OMP local stdio memory | Select OMP during setup, then explicitly run `cairn sync-omp --apply` | Local memory-server child; dynamic effective tool catalog; capture stages candidates for review | `cairn sync-omp --check`, `cairn doctor`, cancel one call, then verify session-stop staging and no orphan | `course-12-guided-setup` |
89
90
 
90
91
  ## Evidence, governance, and measurement
91
92
 
@@ -3,7 +3,7 @@
3
3
  **Status:** Ready
4
4
  **Track:** Quickstart
5
5
  **Time:** 10 minutes
6
- **Tested with:** Cairnkeep 2.17.3
6
+ **Tested with:** Cairnkeep 2.19.0
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.17.3
6
+ **Tested with:** Cairnkeep 2.19.0
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.17.3 and Node.js 22 or newer
6
+ **Tested with:** Cairnkeep 2.19.0 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.17.3
6
+ **Tested with:** Cairnkeep 2.19.0
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.17.3
6
+ **Tested with:** Cairnkeep 2.19.0
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.17.3 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.19.0 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.17.3 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.19.0 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.17.3, Windows x64, and Node.js 22 or newer
6
+ **Tested with:** Cairnkeep 2.19.0, 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.17.3; Pi 0.84.1; Node.js 22, 24, and 26
6
+ **Tested with:** Cairnkeep 2.19.0; Pi 0.84.1; Node.js 22, 24, and 26
7
7
 
8
8
  ## Outcome
9
9
 
@@ -13,13 +13,14 @@ Pi's local stdio memory bridge, and recover or uninstall every managed asset
13
13
  without hidden machine changes.
14
14
 
15
15
  The selected harnesses come from Cairnkeep's declarative registry. Codex is a
16
- supported selection: it receives `.codex/config.toml` and a launcher, while Pi
17
- continues to require its separate explicit machine sync.
16
+ supported selection: it receives `.codex/config.toml` and a launcher. Pi and
17
+ OMP receive project launchers and each require a separate, explicit machine
18
+ sync; selecting both reports both sync commands.
18
19
 
19
20
  ## Prerequisites
20
21
 
21
22
  - Node.js 22 or newer, npm, and Git for the main exercise.
22
- - Pi 0.84.1 or newer.
23
+ - Pi 0.84.1 or newer; OMP is optional.
23
24
  - A disposable parent directory containing no credentials, secrets, private
24
25
  state, or identifying project data.
25
26
 
@@ -32,7 +33,7 @@ cairn setup /tmp/cairnkeep-guided-selector-lab
32
33
  ```
33
34
 
34
35
  Choose Git with Up/Down and Enter, tick Pi with Space in the harness checklist,
35
- keep local memory, then inspect the plan before confirming. Pressing Escape or
36
+ optionally tick OMP as well, keep local memory, then inspect the plan before confirming. Pressing Escape or
36
37
  Ctrl-C cancels; redirected and limited terminals use the documented text-input
37
38
  fallback. Remove that disposable selector lab before continuing if you applied
38
39
  the plan.
@@ -63,6 +64,14 @@ cairn doctor
63
64
  ./.ai/start-pi.sh
64
65
  ```
65
66
 
67
+ If OMP was selected, run its separate sync and use the generated launcher:
68
+
69
+ ```bash
70
+ cairn sync-omp --apply
71
+ cairn sync-omp --check
72
+ ./.ai/start-omp.sh
73
+ ```
74
+
66
75
  In the disposable Pi session, list the registered Cairnkeep tools and make one
67
76
  harmless read-only memory call. The extension starts `cairn memory-server` as a
68
77
  local stdio child in this project; it does not select HTTP or a remote server.
@@ -107,9 +116,10 @@ cairn sync-pi --check
107
116
  cairn doctor
108
117
  ```
109
118
 
110
- Doctor reports project-state drift separately from missing or drifted Pi
119
+ Doctor reports project-state drift separately from missing or drifted harness
111
120
  machine assets. Setup repairs only recorded project assets; `cairn sync-pi
112
- --apply` repairs only the package-owned Pi extension and prompt paths.
121
+ --apply` and `cairn sync-omp --apply` repair only their respective package-owned
122
+ machine paths.
113
123
 
114
124
  Preview backup-first removal before confirming it:
115
125
 
@@ -128,6 +138,7 @@ and context packs remain unless their separate purge flags are supplied.
128
138
  | Setup refuses a missing target | The non-interactive command omitted an explicit choice or `--yes` | Run `cairn setup PATH` in a terminal, or supply the target, `--git`, `--harness`, `--memory`, and `--yes` together |
129
139
  | Setup refuses `--git existing` | The target is not inside a Git work tree | Choose an existing repository, or explicitly authorize `--git init`; use `--git none` only when limited mode is intended |
130
140
  | Doctor reports missing or drifted Pi assets | Project setup selected Pi but machine sync is incomplete | Run `cairn sync-pi --apply`, then `cairn sync-pi --check` and `cairn doctor` |
141
+ | OMP is missing an extension | Project setup selected OMP but its explicit machine sync was not applied | Run `cairn sync-omp --apply`, then `cairn sync-omp --check` and `cairn doctor` |
131
142
  | A cancelled call ends the session | The Pi/bridge version does not satisfy the per-call cancellation contract | Preserve sanitized diagnostics, close the session, and do not claim release readiness |
132
143
  | Pi exits but a child process remains | Shutdown did not complete or the tested extension drifted | Preserve process-state evidence, run the sync check, and treat the release gate as failed |
133
144
  | A client expects native annotation hints | Pi's public tool API has no annotations field | Inspect trusted bridge metadata/result `details`; never claim native propagation |
@@ -1,7 +1,7 @@
1
1
  # L24 - Reviewed knowledge exchange
2
2
 
3
3
  **Status:** Ready
4
- **Tested with:** Cairnkeep 2.17.3 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.19.0 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.17.3 and Node.js 22 or newer
4
+ **Tested with:** Cairnkeep 2.19.0 and Node.js 22 or newer
5
5
  **Time:** 35 minutes
6
6
 
7
7
  ## Outcome
package/docs/operating.md CHANGED
@@ -75,7 +75,7 @@ cairn setup /path/to/project --git init --harness claude,pi --memory local --yes
75
75
  ```
76
76
 
77
77
  The deterministic form accepts `--git init|existing|none`, a comma-separated
78
- subset of `claude,opencode,pi,kimi,qwen,codex`, and `--memory local|none`. `--git
78
+ subset of `claude,opencode,pi,omp,kimi,qwen,codex`, and `--memory local|none`. `--git
79
79
  existing` requires the target to be in an existing work tree. `--git init`
80
80
  requires Git and is the only non-interactive authorization to initialize a
81
81
  repository. `--git none` is an explicit limited mode: repository-aware features
@@ -95,16 +95,21 @@ selected harnesses, and digests/modes/template identifiers for setup-owned
95
95
  assets. It contains no credentials, endpoints, or absolute paths.
96
96
 
97
97
  Setup never installs or refreshes machine-level harness assets. Its
98
- `machine_sync.automatic` field is always false, and the human output labels the
99
- reported command as not run automatically. For selections such as Codex and
100
- Qwen that need no machine sync, `machine_sync.command` is `null` and the human
101
- output says that sync is not required. Apply any reported command explicitly,
102
- check it, then diagnose and launch:
98
+ `machine_sync.automatic` field is always false, and the human output labels each
99
+ reported command as not run automatically. The JSON result's
100
+ `machine_sync.commands` lists every required command; the older singular
101
+ `machine_sync.command` field remains as the first command for compatibility.
102
+ For selections such as Codex and Qwen that need no machine sync,
103
+ `machine_sync.commands` is empty and the human output says that sync is not
104
+ required. Apply each reported command explicitly, check the corresponding
105
+ assets, then diagnose and launch:
103
106
 
104
107
  ```bash
105
108
  cairn sync --apply # Claude Code operating assets
106
109
  cairn sync-pi --apply # Pi extension and prompt
107
110
  cairn sync-pi --check
111
+ cairn sync-omp --apply # OMP extensions
112
+ cairn sync-omp --check
108
113
  cd /path/to/project && cairn doctor
109
114
  ./.ai/start-pi.sh
110
115
  ```
@@ -461,6 +466,8 @@ vendor or host.
461
466
  | `CAIRN_LLM_API_KEY` | API key for the extraction / embeddings endpoint (unset → substring-only memory) |
462
467
  | `CAIRN_LLM_API_URL` | Base URL of the OpenAI-compatible endpoint |
463
468
  | `CAIRN_LLM_EXTRACTION_MODEL` | Chat model for `memory-capture` extraction |
469
+ | `CAIRN_PI_BRIDGE_COMMAND` | Memory-server command for the `pi-bridge-child` stdio host (default `cairn`) |
470
+ | `CAIRN_PI_BRIDGE_ARGS` | JSON argument array for the bridge child server command (default `["memory-server"]`) |
464
471
  | `CAIRN_MEMORY_EMBEDDING_URL` | Embeddings endpoint (falls back to `CAIRN_LLM_API_URL`) |
465
472
  | `CAIRN_MEMORY_EMBEDDING_MODEL` | Embedding model name (required for semantic search) |
466
473
  | `CAIRN_MEMORY_EMBEDDING_TIMEOUT_MS` | Embedding request timeout before substring fallback (default `15000`) |
@@ -1 +1 @@
1
- {"identifier":"cairn-offline-fake-v1","package_version":"2.17.3","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
1
+ {"identifier":"cairn-offline-fake-v1","package_version":"2.19.0","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
@@ -32,7 +32,7 @@ export const artifactNodeRefSchema = z.object({
32
32
  export const artifactProvenanceSchema = z.object({
33
33
  producer: z.string().min(1).max(256).refine((value) => !/[\u0000-\u001f\u007f]/.test(value)),
34
34
  source_event: z.string().min(1).max(256).optional(),
35
- harness: z.enum(["claude-code", "opencode", "pi"]).optional(),
35
+ harness: z.enum(["claude-code", "opencode", "pi", "omp"]).optional(),
36
36
  harness_version: z.string().min(1).max(128).optional(),
37
37
  native_id: z.string().min(1).max(256).optional(),
38
38
  }).strict();
@@ -0,0 +1,109 @@
1
+ import { childEnvironment, connectCairnPiBridge } from "./pi-mcp-bridge.js";
2
+ const STDERR_LIMIT_BYTES = 16 * 1024;
3
+ let stderrTail = "";
4
+ const stderrWrite = process.stderr.write.bind(process.stderr);
5
+ process.stderr.write = ((chunk, ...rest) => {
6
+ const text = typeof chunk === "string" ? chunk : String(chunk);
7
+ const next = stderrTail + text;
8
+ stderrTail = next.length <= STDERR_LIMIT_BYTES ? next : next.slice(next.length - STDERR_LIMIT_BYTES);
9
+ return stderrWrite(chunk, ...rest);
10
+ });
11
+ function send(message) {
12
+ process.stdout.write(`${JSON.stringify(message)}\n`);
13
+ }
14
+ function fatal(error) {
15
+ const message = error instanceof Error ? error.message : String(error);
16
+ process.stderr.write(`${JSON.stringify({ type: "error", error: message })}\n`);
17
+ process.exit(1);
18
+ }
19
+ process.on("uncaughtException", fatal);
20
+ process.on("unhandledRejection", (reason) => fatal(reason));
21
+ async function main() {
22
+ const cwd = process.argv[2] ?? process.cwd();
23
+ const command = process.env.CAIRN_PI_BRIDGE_COMMAND ?? "cairn";
24
+ const args = JSON.parse(process.env.CAIRN_PI_BRIDGE_ARGS ?? '["memory-server"]');
25
+ const bridge = await connectCairnPiBridge({ cwd, command, args, env: childEnvironment(process.env) });
26
+ const controllers = new Map();
27
+ let stdinBuffer = "";
28
+ let closing = false;
29
+ const close = async () => {
30
+ if (closing)
31
+ return;
32
+ closing = true;
33
+ await bridge.close().catch(() => undefined);
34
+ process.exit(0);
35
+ };
36
+ process.on("SIGTERM", () => void close());
37
+ process.on("SIGINT", () => void close());
38
+ process.stdin.on("end", () => void close());
39
+ async function handle(request) {
40
+ try {
41
+ switch (request.type) {
42
+ case "list": {
43
+ send({ type: "result", id: request.id, ok: true, tools: await bridge.listAllTools() });
44
+ break;
45
+ }
46
+ case "call": {
47
+ const controller = new AbortController();
48
+ controllers.set(request.id, controller);
49
+ try {
50
+ const result = await bridge.call(request.tool, request.args ?? {}, { signal: controller.signal });
51
+ send({ type: "result", id: request.id, ok: true, result });
52
+ }
53
+ catch (error) {
54
+ send({
55
+ type: "result",
56
+ id: request.id,
57
+ ok: false,
58
+ error: error instanceof Error ? error.message : String(error),
59
+ stderr: stderrTail,
60
+ });
61
+ }
62
+ finally {
63
+ controllers.delete(request.id);
64
+ }
65
+ break;
66
+ }
67
+ case "cancel": {
68
+ controllers.get(request.id)?.abort(new Error("cancelled"));
69
+ break;
70
+ }
71
+ case "close": {
72
+ await close();
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ catch (error) {
78
+ const id = typeof request.id === "number" ? request.id : -1;
79
+ send({
80
+ type: "result",
81
+ id,
82
+ ok: false,
83
+ error: error instanceof Error ? error.message : String(error),
84
+ stderr: stderrTail,
85
+ });
86
+ }
87
+ }
88
+ process.stdin.on("data", (chunk) => {
89
+ stdinBuffer += chunk.toString("utf8");
90
+ let newline = stdinBuffer.indexOf("\n");
91
+ while (newline >= 0) {
92
+ const line = stdinBuffer.slice(0, newline);
93
+ stdinBuffer = stdinBuffer.slice(newline + 1);
94
+ newline = stdinBuffer.indexOf("\n");
95
+ if (!line.trim())
96
+ continue;
97
+ let request;
98
+ try {
99
+ request = JSON.parse(line);
100
+ }
101
+ catch {
102
+ continue;
103
+ }
104
+ void handle(request);
105
+ }
106
+ });
107
+ send({ type: "ready" });
108
+ }
109
+ main().catch(fatal);
@@ -11,11 +11,23 @@ function positiveInteger(value, fallback, name) {
11
11
  throw new Error(`${name} must be a positive integer.`);
12
12
  return selected;
13
13
  }
14
- function childEnvironment(source) {
14
+ // Bun-hosted agents (pi, omp) prepend a /tmp/bun-node-* dir whose `node` is
15
+ // Bun itself; grandchildren like `cairn memory-server` spawn real node
16
+ // subprocesses, so those shim dirs must not shadow it.
17
+ const BUN_NODE_SHIM = /\/tmp\/bun-node-[^/:]+$/;
18
+ export function childEnvironment(source) {
15
19
  const env = {};
16
20
  for (const [name, value] of Object.entries(source)) {
17
- if (value !== undefined && name !== "MCP_HTTP_PORT")
18
- env[name] = value;
21
+ if (value === undefined || name === "MCP_HTTP_PORT")
22
+ continue;
23
+ if (name === "PATH") {
24
+ env[name] = value
25
+ .split(":")
26
+ .filter((entry) => !BUN_NODE_SHIM.test(entry))
27
+ .join(":");
28
+ continue;
29
+ }
30
+ env[name] = value;
19
31
  }
20
32
  return env;
21
33
  }
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export const WORK_EVIDENCE_SCHEMA_VERSION = 1;
3
- export const WORK_EVIDENCE_HARNESSES = ["claude", "opencode", "pi", "kimi", "qwen", "codex"];
3
+ export const WORK_EVIDENCE_HARNESSES = ["claude", "opencode", "pi", "omp", "kimi", "qwen", "codex"];
4
4
  export const WORK_EVIDENCE_DEFAULT_RETENTION_DAYS = 30;
5
5
  export const WORK_EVIDENCE_DEFAULT_STORE_MAX_BYTES = 64 * 1024 * 1024;
6
6
  export const WORK_EVIDENCE_DEFAULT_MAX_TOUCHED_PATHS = 4096;
@@ -292,7 +292,7 @@ export async function finishWorkEvidence(projectRoot, evidenceId, exitStatus, op
292
292
  provenance: {
293
293
  producer: "cairn-work-evidence",
294
294
  source_event: "launcher-exit",
295
- harness: start.harness === "claude" ? "claude-code" : ["opencode", "pi"].includes(start.harness) ? start.harness : undefined,
295
+ harness: start.harness === "claude" ? "claude-code" : ["opencode", "pi", "omp"].includes(start.harness) ? start.harness : undefined,
296
296
  },
297
297
  content: { text: patchCapture.text },
298
298
  }, { ...artifactLimits, artifactMaxBytes: Math.min(artifactLimits.artifactMaxBytes, limits.patchMaxBytes) });
@@ -2,7 +2,7 @@
2
2
  "name": "@cairnkeep/memory-server",
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
- "description": "Durable, harness-agnostic memory MCP server for coding agents — the core of Cairnkeep.",
5
+ "description": "Durable, harness-agnostic memory MCP server for coding agents \u2014 the core of Cairnkeep.",
6
6
  "license": "Apache-2.0",
7
7
  "type": "module",
8
8
  "engines": {
@@ -61,10 +61,12 @@
61
61
  "check:playbook": "node scripts/smoke-playbook.mjs",
62
62
  "check:notes": "npm run build && npm run check:note-signatures && npm run check:note-distillation && npm run check:note-enrichment",
63
63
  "test": "npm run test:smoke",
64
- "test:smoke": "npm run build && npm run check:embeddings && npm run check:extract && npm run check:scope-guard && npm run check:http-guard && npm run check:remote-context && npm run check:explore-guard && npm run check:explore-cache && npm run check:explore-crossref && npm run check:route-guard && npm run check:reviewed-memory && npm run check:memory-proposals && npm run check:trajectory-roundtrip && npm run check:trajectory-redaction && npm run check:trajectory-retention && npm run check:note-signatures && npm run check:note-distillation && npm run check:note-enrichment && npm run check:node-compat && npm run check:typed-nodes && npm run check:memory-import && npm run check:note-mcp && npm run check:node-doctor && npm run check:artifact-store && npm run check:artifact-mcp && npm run check:compaction-capture && npm run check:capability-contract && npm run check:capability-logging && npm run check:capability-harness && npm run check:capability-mcp && npm run check:eval-schema && npm run check:eval-process && npm run check:eval-statistics && npm run check:skill-lifecycle && npm run check:graph-cli && npm run check:mcp-trust && npm run check:pi-mcp-bridge && npm run check:context-pack && npm run check:context-pack-retrieval && npm run check:context-pack-v216-compat && npm run check:context-usage && npm run check:domain-retrieval && npm run check:retrieval-benchmark && npm run check:work-evidence && npm run check:okf && npm run check:playbook",
64
+ "test:smoke": "npm run build && npm run check:embeddings && npm run check:extract && npm run check:scope-guard && npm run check:http-guard && npm run check:remote-context && npm run check:explore-guard && npm run check:explore-cache && npm run check:explore-crossref && npm run check:route-guard && npm run check:reviewed-memory && npm run check:memory-proposals && npm run check:trajectory-roundtrip && npm run check:trajectory-redaction && npm run check:trajectory-retention && npm run check:note-signatures && npm run check:note-distillation && npm run check:note-enrichment && npm run check:node-compat && npm run check:typed-nodes && npm run check:memory-import && npm run check:note-mcp && npm run check:node-doctor && npm run check:artifact-store && npm run check:artifact-mcp && npm run check:compaction-capture && npm run check:capability-contract && npm run check:capability-logging && npm run check:capability-harness && npm run check:capability-mcp && npm run check:eval-schema && npm run check:eval-process && npm run check:eval-statistics && npm run check:skill-lifecycle && npm run check:graph-cli && npm run check:mcp-trust && npm run check:pi-mcp-bridge && npm run check:pi-bridge-env && npm run check:pi-bridge-child && npm run check:context-pack && npm run check:context-pack-retrieval && npm run check:context-pack-v216-compat && npm run check:context-usage && npm run check:domain-retrieval && npm run check:retrieval-benchmark && npm run check:work-evidence && npm run check:okf && npm run check:playbook",
65
65
  "test:search": "npm run build && npm run check:search",
66
66
  "test:memory": "npm run build && npm run check:embeddings && npm run check:extract && npm run check:search",
67
- "test:all": "npm run test:memory"
67
+ "test:all": "npm run test:memory",
68
+ "check:pi-bridge-env": "node scripts/smoke-pi-bridge-env.mjs",
69
+ "check:pi-bridge-child": "node scripts/smoke-pi-bridge-child.mjs"
68
70
  },
69
71
  "dependencies": {
70
72
  "@modelcontextprotocol/sdk": "^1.30.0",