@cairnkeep/cli 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -1
- package/README.md +11 -4
- package/docs/building-an-overlay.md +2 -2
- package/docs/harness-compatibility.md +85 -7
- package/docs/learning/CURRICULUM-MAP.md +1 -1
- package/docs/learning/FEATURE-GUIDE.md +1 -1
- package/docs/learning/lessons/L00-why-cairnkeep.md +1 -1
- package/docs/learning/lessons/L01-safe-trial.md +3 -3
- package/docs/learning/lessons/L02-installation.md +11 -3
- package/docs/learning/lessons/L03-first-project.md +1 -1
- package/docs/operating.md +36 -4
- package/examples/eval/bundled-fake.json +1 -1
- package/package.json +3 -2
- package/scripts/bootstrap.sh +2 -0
- package/scripts/test-bootstrap-untracked.sh +2 -1
- package/scripts/test-launcher-hooks.sh +29 -1
- package/scripts/test-package-install.sh +3 -0
- package/scripts/uninstall.sh +1 -0
- package/templates/start-qwen.sh.template +32 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ All notable user-facing changes are documented here. This project follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [2.6.0] - 2026-07-29
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add Qwen Code as a supported memory client with a generated project launcher,
|
|
13
|
+
local stdio guidance, and tested authenticated remote HTTP configuration.
|
|
14
|
+
- Expand the harness comparison to cover current native plugin and MCP clients,
|
|
15
|
+
while keeping memory-only support separate from the full operating layer.
|
|
16
|
+
|
|
8
17
|
## [2.5.0] - 2026-07-29
|
|
9
18
|
|
|
10
19
|
### Added
|
|
@@ -211,7 +220,8 @@ stored memories.
|
|
|
211
220
|
- Preserve executable permissions and Bash 3.2 portability on macOS.
|
|
212
221
|
- Add backup-first uninstall and SQLite-safe memory export/import guidance.
|
|
213
222
|
|
|
214
|
-
[Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.
|
|
223
|
+
[Unreleased]: https://github.com/cairnkeep/cairnkeep/compare/v2.6.0...HEAD
|
|
224
|
+
[2.6.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.5.0...v2.6.0
|
|
215
225
|
[2.5.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.4.0...v2.5.0
|
|
216
226
|
[2.4.0]: https://github.com/cairnkeep/cairnkeep/compare/v2.3.1...v2.4.0
|
|
217
227
|
[2.3.1]: https://github.com/cairnkeep/cairnkeep/compare/v2.3.0...v2.3.1
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ A *cairn* is a stack of stones left as a trail marker for whoever follows; a
|
|
|
10
10
|
*keep* is where you store what matters. **Cairnkeep** is where coding agents
|
|
11
11
|
stack durable memory — decisions, pitfalls, patterns — and follow the trail
|
|
12
12
|
across sessions, projects, and harnesses (Claude Code, OpenCode, Kimi Code,
|
|
13
|
-
Pi, and other MCP clients).
|
|
13
|
+
Qwen Code, Pi, and other MCP clients).
|
|
14
14
|
|
|
15
15
|
## Status
|
|
16
16
|
|
|
@@ -38,6 +38,7 @@ and 20 are end-of-life upstream.
|
|
|
38
38
|
| Claude Code on Linux/macOS | Memory server plus commands, agents, hooks, and launchers |
|
|
39
39
|
| OpenCode on Linux/macOS | Memory server plus commands, plugins, hooks, and launchers |
|
|
40
40
|
| Kimi Code on Linux/macOS | Memory MCP server plus project launcher; no Cairnkeep operating-layer assets yet |
|
|
41
|
+
| Qwen Code on Linux/macOS | Memory MCP server plus project launcher; no Cairnkeep operating-layer assets yet |
|
|
41
42
|
| Pi on Linux/macOS | Native opt-in trajectory extension and launcher; no bundled MCP bridge |
|
|
42
43
|
| Codex CLI | Memory MCP server; no Cairnkeep operating-layer assets |
|
|
43
44
|
| Other MCP clients | Memory and optional domain-knowledge MCP tools |
|
|
@@ -47,7 +48,7 @@ Linux, macOS, Bash 3.2 portability, and clean Node 22/24/26 runtime checks
|
|
|
47
48
|
are exercised in CI.
|
|
48
49
|
|
|
49
50
|
See [Harness compatibility](docs/harness-compatibility.md) for exact support
|
|
50
|
-
levels, Kimi configuration, and candidates that are not yet runtime-tested.
|
|
51
|
+
levels, Kimi and Qwen configuration, and candidates that are not yet runtime-tested.
|
|
51
52
|
|
|
52
53
|
## Try with Podman
|
|
53
54
|
|
|
@@ -159,6 +160,12 @@ configuration requires a literal URL and supports a token reference through
|
|
|
159
160
|
`bearerTokenEnvVar`; it does not expand `${VAR}` in the URL. See
|
|
160
161
|
[Harness compatibility](docs/harness-compatibility.md#kimi-code).
|
|
161
162
|
|
|
163
|
+
For Qwen Code, use project `.qwen/settings.json`: local stdio launches
|
|
164
|
+
`cairn memory-server`, while remote HTTP uses `httpUrl` and environment-expanded
|
|
165
|
+
headers. Review and approve project MCP configuration with
|
|
166
|
+
`qwen mcp approve cairn-memory`, then launch with `./.ai/start-qwen.sh`. See
|
|
167
|
+
[Harness compatibility](docs/harness-compatibility.md#qwen-code).
|
|
168
|
+
|
|
162
169
|
For Pi, install the local trajectory adapter and use the scaffolded launcher:
|
|
163
170
|
|
|
164
171
|
```bash
|
|
@@ -208,8 +215,8 @@ unless a wrapper opts in:
|
|
|
208
215
|
export env (e.g. a provider base URL) or abort the launch by returning
|
|
209
216
|
non-zero. This is where credential refresh / connectivity setup lives.
|
|
210
217
|
- **`CAIRN_EXTRA_SETTINGS`** — path to a settings file layered onto the harness
|
|
211
|
-
(`--settings` for Claude Code, `OPENCODE_CONFIG` for OpenCode).
|
|
212
|
-
|
|
218
|
+
(`--settings` for Claude Code, `OPENCODE_CONFIG` for OpenCode). Kimi, Qwen,
|
|
219
|
+
and Pi do not interpret this variable in their generic launchers.
|
|
213
220
|
Process env still wins, so an inline value beats the profile.
|
|
214
221
|
- **`.ai/post-exit.sh`** — sourced after the harness exits, with
|
|
215
222
|
`CAIRN_EXIT_STATUS` set to its exit code.
|
|
@@ -28,13 +28,13 @@ manifest, profile-lock, private-registry, and rollback contract.
|
|
|
28
28
|
## The launcher seams
|
|
29
29
|
|
|
30
30
|
The generic launchers (`.ai/start-claude.sh`, `.ai/start-opencode.sh`,
|
|
31
|
-
`.ai/start-kimi.sh`, and `.ai/start-pi.sh`, scaffolded by `cairn bootstrap`) run
|
|
31
|
+
`.ai/start-kimi.sh`, `.ai/start-qwen.sh`, and `.ai/start-pi.sh`, scaffolded by `cairn bootstrap`) run
|
|
32
32
|
optional hooks, each a no-op when absent:
|
|
33
33
|
|
|
34
34
|
| Seam | When | Use it for |
|
|
35
35
|
|---|---|---|
|
|
36
36
|
| `.ai/pre-launch.sh` | sourced after `.env`, before launch | export a provider base URL / credentials, refresh a token, run a connectivity check, or **abort** the launch by returning non-zero |
|
|
37
|
-
| `CAIRN_EXTRA_SETTINGS` | read just before launch | path to a settings file layered onto Claude Code (`--settings`) or OpenCode (`OPENCODE_CONFIG`); Kimi and Pi leave it available to hooks but do not interpret it |
|
|
37
|
+
| `CAIRN_EXTRA_SETTINGS` | read just before launch | path to a settings file layered onto Claude Code (`--settings`) or OpenCode (`OPENCODE_CONFIG`); Kimi, Qwen, and Pi leave it available to hooks but do not interpret it |
|
|
38
38
|
| `.ai/post-exit.sh` | sourced after the harness exits | teardown; `CAIRN_EXIT_STATUS` holds the exit code |
|
|
39
39
|
|
|
40
40
|
**Typical overlay launcher** — a corporate wrapper needs a non-default provider
|
|
@@ -11,14 +11,15 @@ commands, hooks, plugins, or trajectory adapters.
|
|
|
11
11
|
| Claude Code | Memory MCP, commands, agents, hooks, launcher | Exercised by Cairnkeep tests |
|
|
12
12
|
| OpenCode | Memory MCP, commands, workflows, plugins, launcher | Exercised by Cairnkeep tests |
|
|
13
13
|
| Kimi Code | Memory MCP, `AGENTS.md`, launcher | Launcher tested; remote MCP tested with Kimi Code 0.30.0 |
|
|
14
|
+
| Qwen Code | Memory MCP, launcher | Launcher tested; stdio and remote MCP tested with Qwen Code 0.21.1 |
|
|
14
15
|
| Pi | Native opt-in trajectory extension and launcher | Exercised by Cairnkeep tests; no bundled MCP bridge |
|
|
15
16
|
| Codex CLI | Memory MCP | Configuration supported; no Cairnkeep operating-layer assets or launcher |
|
|
16
17
|
| Other MCP clients | Memory and optional domain-knowledge tools | Protocol-compatible; not automatically runtime-tested |
|
|
17
18
|
|
|
18
19
|
Only Claude Code and OpenCode currently receive the complete operating layer.
|
|
19
|
-
Kimi skills and hooks require harness-specific adaptation and
|
|
20
|
-
they can be presented as equivalent. In
|
|
21
|
-
ordinary prompts until that work is complete.
|
|
20
|
+
Kimi and Qwen skills and hooks require harness-specific adaptation and
|
|
21
|
+
validation before they can be presented as equivalent. In either client, call
|
|
22
|
+
MCP tools directly or use ordinary prompts until that work is complete.
|
|
22
23
|
|
|
23
24
|
## Kimi Code
|
|
24
25
|
|
|
@@ -91,6 +92,72 @@ token value in either file.
|
|
|
91
92
|
Kimi MCP configuration is documented at
|
|
92
93
|
[Kimi Code MCP](https://www.kimi.com/code/docs/en/kimi-code-cli/customization/mcp.html).
|
|
93
94
|
|
|
95
|
+
## Qwen Code
|
|
96
|
+
|
|
97
|
+
Qwen Code can read MCP definitions from user settings, project
|
|
98
|
+
`.qwen/settings.json`, and compatible repository `.mcp.json` files. Use the
|
|
99
|
+
Qwen-specific project settings file for remote HTTP so its `httpUrl` transport
|
|
100
|
+
and environment expansion are explicit.
|
|
101
|
+
|
|
102
|
+
### Local stdio
|
|
103
|
+
|
|
104
|
+
Create `.qwen/settings.json` in a trusted project:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"mcpServers": {
|
|
109
|
+
"cairn-memory": {
|
|
110
|
+
"command": "cairn",
|
|
111
|
+
"args": ["memory-server"]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Project MCP definitions are approval-gated. Review the file, then run:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
qwen mcp approve cairn-memory
|
|
121
|
+
./.ai/start-qwen.sh
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The server is a local child process. Its storage stays on this computer unless
|
|
125
|
+
the operator deliberately replaces this stdio definition with a remote one.
|
|
126
|
+
|
|
127
|
+
### Remote HTTP
|
|
128
|
+
|
|
129
|
+
Qwen Code 0.21.1 was exercised with environment expansion in project settings:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"mcpServers": {
|
|
134
|
+
"cairn-memory": {
|
|
135
|
+
"httpUrl": "${CAIRN_MEMORY_REMOTE_URL}",
|
|
136
|
+
"headers": {
|
|
137
|
+
"Authorization": "Bearer ${CAIRN_MEMORY_HTTP_TOKEN}",
|
|
138
|
+
"X-Cairn-Project": "example-project",
|
|
139
|
+
"X-Cairn-Scopes": "identity,personal,project",
|
|
140
|
+
"X-Cairn-AnythingLLM-Workspaces": "example-workspace"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Keep the endpoint and token in `.ai/.env` or a machine secret store. The
|
|
148
|
+
generated launcher exports `.ai/.env` before Qwen reads the settings. Re-run
|
|
149
|
+
`qwen mcp approve cairn-memory` after changing the project definition because
|
|
150
|
+
the approval is bound to the configuration digest.
|
|
151
|
+
|
|
152
|
+
The authenticated recipe above is validated for `.qwen/settings.json`.
|
|
153
|
+
Cairnkeep does not assume that a one-shot `--mcp-config` input performs the same
|
|
154
|
+
environment expansion. A private overlay should write the project settings
|
|
155
|
+
backup-first, preserve unrelated keys, exclude private routing metadata from
|
|
156
|
+
Git, and leave secret values as environment references.
|
|
157
|
+
|
|
158
|
+
Qwen MCP configuration is documented at
|
|
159
|
+
[Qwen Code MCP](https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/).
|
|
160
|
+
|
|
94
161
|
## Candidate memory clients
|
|
95
162
|
|
|
96
163
|
The following clients have documented MCP support and are reasonable adapter
|
|
@@ -99,17 +166,28 @@ writers, operating assets, or runtime CI:
|
|
|
99
166
|
|
|
100
167
|
| Client | Documented MCP surface | Cairnkeep status |
|
|
101
168
|
|---|---|---|
|
|
102
|
-
|
|
|
169
|
+
| Antigravity CLI | Workspace `.agents/mcp_config.json` and plugins | Current successor candidate for memory plus native operating assets |
|
|
170
|
+
| Cursor | Project `.cursor/mcp.json`, plugins, and Agent CLI | Candidate for memory plus native operating assets |
|
|
103
171
|
| GitHub Copilot CLI | `copilot mcp` and `.mcp.json` | Candidate for memory plus shared skills |
|
|
104
|
-
|
|
|
172
|
+
| Factory Droid | Native plugin marketplace | Candidate for reusing a compatible operating-layer package |
|
|
105
173
|
| goose | MCP extensions and CLI session extension loading | Candidate for memory and recipe integration |
|
|
174
|
+
| Gemini CLI | `mcpServers` in `settings.json` | Legacy candidate for enterprise or API-key users only |
|
|
106
175
|
|
|
107
176
|
Primary references:
|
|
108
177
|
|
|
109
|
-
- [
|
|
178
|
+
- [Antigravity MCP](https://antigravity.google/docs/mcp)
|
|
179
|
+
- [Cursor MCP](https://docs.cursor.com/context/model-context-protocol)
|
|
110
180
|
- [GitHub Copilot CLI MCP](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers)
|
|
111
|
-
- [Qwen Code MCP](https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/)
|
|
112
181
|
- [goose](https://github.com/aaif-goose/goose)
|
|
182
|
+
- [Gemini CLI transition announcement](https://github.com/google-gemini/gemini-cli/discussions/28017)
|
|
183
|
+
- [Superpowers harness integrations](https://github.com/obra/superpowers)
|
|
184
|
+
|
|
185
|
+
Superpowers is a useful comparison because it keeps shared behavior in one
|
|
186
|
+
source tree and ships thin native adapters through each harness's supported
|
|
187
|
+
plugin, extension, hook, or context mechanism. Cairnkeep follows the same
|
|
188
|
+
principle for future operating-layer ports: reuse common content, map real tool
|
|
189
|
+
names and lifecycle events per harness, and document degraded capabilities
|
|
190
|
+
instead of copying one harness's files into another.
|
|
113
191
|
|
|
114
192
|
Support should be added one client at a time with a clean install, a local
|
|
115
193
|
stdio handshake, an authenticated HTTP handshake, a real write/recall canary,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Quickstart
|
|
5
5
|
**Time:** 15 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.
|
|
6
|
+
**Tested with:** Cairnkeep 2.6.0
|
|
7
7
|
|
|
8
8
|
## Outcome
|
|
9
9
|
|
|
@@ -26,7 +26,7 @@ ephemeral; the named course volume is persistent.
|
|
|
26
26
|
1. Pull the public image:
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
podman pull ghcr.io/cairnkeep/cairnkeep:2.
|
|
29
|
+
podman pull ghcr.io/cairnkeep/cairnkeep:2.6.0
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
2. Start the stdio server with a read-only root filesystem and no Linux
|
|
@@ -38,7 +38,7 @@ ephemeral; the named course volume is persistent.
|
|
|
38
38
|
--read-only --cap-drop=all --security-opt=no-new-privileges \
|
|
39
39
|
--tmpfs=/tmp:rw,noexec,nosuid,size=64m,mode=1777 \
|
|
40
40
|
--volume cairnkeep-course-data:/data:Z,U \
|
|
41
|
-
ghcr.io/cairnkeep/cairnkeep:2.
|
|
41
|
+
ghcr.io/cairnkeep/cairnkeep:2.6.0 stdio
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
3. The process waits quietly for MCP input. Press `Ctrl-C` after confirming it
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Status:** Ready
|
|
4
4
|
**Track:** Quickstart
|
|
5
5
|
**Time:** 25 minutes
|
|
6
|
-
**Tested with:** Cairnkeep 2.
|
|
6
|
+
**Tested with:** Cairnkeep 2.6.0 and Node.js 22 or newer
|
|
7
7
|
|
|
8
8
|
## Outcome
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ layer, and distinguish a complete installation from a partial one.
|
|
|
13
13
|
## Prerequisites
|
|
14
14
|
|
|
15
15
|
- Node.js 22 or newer and npm.
|
|
16
|
-
- Claude Code installed for the commands below. OpenCode and
|
|
16
|
+
- Claude Code installed for the commands below. OpenCode, Kimi Code, and Qwen Code users
|
|
17
17
|
should follow the equivalent setup in
|
|
18
18
|
[the operating guide](../../operating.md).
|
|
19
19
|
- Permission to install an npm package globally for your user.
|
|
@@ -41,7 +41,7 @@ machine-level steps.
|
|
|
41
41
|
2. Install Cairnkeep:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
npm install --global @cairnkeep/cli@2.
|
|
44
|
+
npm install --global @cairnkeep/cli@2.6.0
|
|
45
45
|
cairn --version
|
|
46
46
|
```
|
|
47
47
|
|
|
@@ -108,6 +108,14 @@ URL rather than `${CAIRN_MEMORY_REMOTE_URL}`. Keep the resolved URL in a private
|
|
|
108
108
|
`.kimi-code/mcp.json` and keep the bearer token in the environment. See
|
|
109
109
|
[Harness compatibility](../../harness-compatibility.md#kimi-code).
|
|
110
110
|
|
|
111
|
+
Qwen Code can use the generated `.ai/start-qwen.sh` launcher. Its project
|
|
112
|
+
`.qwen/settings.json` supports environment references for both the remote URL
|
|
113
|
+
and authorization header, so the file can contain names such as
|
|
114
|
+
`${CAIRN_MEMORY_REMOTE_URL}` and `${CAIRN_MEMORY_HTTP_TOKEN}` instead of secret
|
|
115
|
+
values. Keep this project settings file untracked and approve the generated MCP
|
|
116
|
+
entry with `qwen mcp approve cairn-memory`. See
|
|
117
|
+
[Harness compatibility](../../harness-compatibility.md#qwen-code).
|
|
118
|
+
|
|
111
119
|
## Clean up if you stop the evaluation
|
|
112
120
|
|
|
113
121
|
Continue directly to L03 if you are completing the quickstart. If you stop here,
|
package/docs/operating.md
CHANGED
|
@@ -17,8 +17,9 @@ installs. This guide covers all three in order.
|
|
|
17
17
|
## Prerequisites
|
|
18
18
|
|
|
19
19
|
- Node.js 22 or newer (for the memory server) and a supported harness. Claude
|
|
20
|
-
Code and OpenCode receive the full operating layer. Kimi Code
|
|
21
|
-
memory MCP and launcher. Pi receives its native trajectory
|
|
20
|
+
Code and OpenCode receive the full operating layer. Kimi Code and Qwen Code
|
|
21
|
+
receive the memory MCP and launcher. Pi receives its native trajectory
|
|
22
|
+
adapter.
|
|
22
23
|
- Optional: the `sqlite3` CLI for `cairn memory export`. Runtime memory and
|
|
23
24
|
`cairn memory import` do not require it.
|
|
24
25
|
- Optional: an OpenAI-compatible LLM endpoint for memory extraction and
|
|
@@ -189,6 +190,37 @@ parses it before applying its private override. See
|
|
|
189
190
|
[Harness compatibility](harness-compatibility.md#kimi-code) for the complete
|
|
190
191
|
configuration and trust-boundary guidance.
|
|
191
192
|
|
|
193
|
+
## Setup order (Qwen Code)
|
|
194
|
+
|
|
195
|
+
Qwen Code can use the Cairnkeep memory MCP and the generated project launcher.
|
|
196
|
+
It does not yet receive Cairnkeep-specific skills, commands, or hooks.
|
|
197
|
+
|
|
198
|
+
For local stdio memory, create `.qwen/settings.json` in the project:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"mcpServers": {
|
|
203
|
+
"cairn-memory": {
|
|
204
|
+
"command": "cairn",
|
|
205
|
+
"args": ["memory-server"]
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Review and approve the project server, then launch it:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
qwen mcp approve cairn-memory
|
|
215
|
+
./.ai/start-qwen.sh
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
For authenticated remote HTTP, use `httpUrl` plus environment-expanded headers
|
|
219
|
+
in `.qwen/settings.json`. Keep the endpoint and bearer token in `.ai/.env` or a
|
|
220
|
+
machine secret store, not in the JSON file. See
|
|
221
|
+
[Harness compatibility](harness-compatibility.md#qwen-code) for the tested
|
|
222
|
+
configuration, approval behavior, and overlay guidance.
|
|
223
|
+
|
|
192
224
|
## Setup order (Pi)
|
|
193
225
|
|
|
194
226
|
Pi trajectory capture uses the same project scaffold and store, but its source
|
|
@@ -663,13 +695,13 @@ maintain a running install — without forking the core. All are opt-in.
|
|
|
663
695
|
### Launcher seams
|
|
664
696
|
|
|
665
697
|
The generic launchers (`.ai/start-claude.sh`, `.ai/start-opencode.sh`,
|
|
666
|
-
`.ai/start-kimi.sh`, and `.ai/start-pi.sh`) run optional hooks around the
|
|
698
|
+
`.ai/start-kimi.sh`, `.ai/start-qwen.sh`, and `.ai/start-pi.sh`) run optional hooks around the
|
|
667
699
|
harness, each a no-op when absent:
|
|
668
700
|
|
|
669
701
|
| Seam | When | Purpose |
|
|
670
702
|
|---|---|---|
|
|
671
703
|
| `.ai/pre-launch.sh` | sourced after `.env`, before launch | export env (e.g. a provider base URL / auth), refresh credentials, or abort by returning non-zero |
|
|
672
|
-
| `CAIRN_EXTRA_SETTINGS` | read just before launch | path to a settings file layered on Claude Code (`--settings`) or OpenCode (`OPENCODE_CONFIG`); Kimi and Pi leave the variable available to hooks but do not interpret it |
|
|
704
|
+
| `CAIRN_EXTRA_SETTINGS` | read just before launch | path to a settings file layered on Claude Code (`--settings`) or OpenCode (`OPENCODE_CONFIG`); Kimi, Qwen, and Pi leave the variable available to hooks but do not interpret it |
|
|
673
705
|
| `.ai/post-exit.sh` | sourced after the harness exits | teardown; `CAIRN_EXIT_STATUS` holds the exit code |
|
|
674
706
|
|
|
675
707
|
A wrapper that needs a non-default provider drops a `pre-launch.sh` that renders
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"identifier":"cairn-offline-fake-v1","package_version":"2.
|
|
1
|
+
{"identifier":"cairn-offline-fake-v1","package_version":"2.6.0","schema_version":1,"task_set_digest":"13e95379f35839593047ec34521a65a8fa3ab92bd3993bca9dc8bf5c4a9ff36f"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cairnkeep/cli",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "A durable, harness-agnostic memory + context layer for coding agents
|
|
3
|
+
"version": "2.6.0",
|
|
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",
|
|
7
7
|
"publishConfig": {
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"agent",
|
|
64
64
|
"claude-code",
|
|
65
65
|
"opencode",
|
|
66
|
+
"qwen-code",
|
|
66
67
|
"pi-coding-agent",
|
|
67
68
|
"context",
|
|
68
69
|
"rag"
|
package/scripts/bootstrap.sh
CHANGED
|
@@ -57,6 +57,7 @@ install_file "$TPL/start-claude.sh.template" "$target/.ai/start-claude.sh" 0
|
|
|
57
57
|
install_file "$TPL/start-opencode.sh.template" "$target/.ai/start-opencode.sh" 0755
|
|
58
58
|
install_file "$TPL/start-pi.sh.template" "$target/.ai/start-pi.sh" 0755
|
|
59
59
|
install_file "$TPL/start-kimi.sh.template" "$target/.ai/start-kimi.sh" 0755
|
|
60
|
+
install_file "$TPL/start-qwen.sh.template" "$target/.ai/start-qwen.sh" 0755
|
|
60
61
|
install_file "$TPL/env.example.template" "$target/.ai/env.example" 0644
|
|
61
62
|
install_file "$TPL/trajectory-redaction.json.template" "$target/.ai/trajectory-redaction.json" 0644
|
|
62
63
|
install_file "$TPL/capabilities.json.template" "$target/.ai/capabilities.json" 0600
|
|
@@ -107,3 +108,4 @@ echo " For Pi trajectory capture, also run: cairn sync-pi --apply"
|
|
|
107
108
|
echo " From a source clone, use bin/cairn in place of cairn."
|
|
108
109
|
echo " 4. Launch: $target/.ai/start-claude.sh"
|
|
109
110
|
echo " Kimi memory-client launch: $target/.ai/start-kimi.sh"
|
|
111
|
+
echo " Qwen memory-client launch: $target/.ai/start-qwen.sh"
|
|
@@ -54,6 +54,7 @@ git -C "$tmp/repo" init -q
|
|
|
54
54
|
"$ROOT/scripts/bootstrap.sh" --untracked "$tmp/repo" >/dev/null
|
|
55
55
|
[[ -f "$tmp/repo/.ai/start-claude.sh" ]] || fail "scaffold missing"
|
|
56
56
|
[[ -x "$tmp/repo/.ai/start-kimi.sh" ]] || fail "Kimi launcher missing"
|
|
57
|
+
[[ -x "$tmp/repo/.ai/start-qwen.sh" ]] || fail "Qwen launcher missing"
|
|
57
58
|
[[ -f "$tmp/repo/.planning/config.json" ]] || fail "planning layer missing"
|
|
58
59
|
[[ -f "$tmp/repo/.agentfs/.gitignore" ]] || fail "project-memory ignore guard missing"
|
|
59
60
|
[[ -z "$(git -C "$tmp/repo" status --porcelain)" ]] || fail "scaffold visible to git"
|
|
@@ -67,7 +68,7 @@ grep -qxF "/.agentfs/" "$tmp/repo/.git/info/exclude" || fail "missing /.agentfs/
|
|
|
67
68
|
printf '%s\n' '{"schema_version":1,"capabilities":{"wiki":false},"logging":{"callbacks":true}}' >"$tmp/repo/.ai/capabilities.json"
|
|
68
69
|
chmod 600 "$tmp/repo/.ai/capabilities.json"
|
|
69
70
|
printf '%s\n' '# operator-owned environment' >"$tmp/repo/.ai/env.example"
|
|
70
|
-
asset_paths='.ai/start-claude.sh .ai/start-opencode.sh .ai/start-pi.sh .ai/start-kimi.sh .ai/env.example .ai/trajectory-redaction.json .ai/capabilities.json .agentfs/.gitignore .planning/config.json .planning/wiki/index.md .planning/wiki/policy.md .planning/wiki/CONTRADICTIONS.md .planning/wiki/LOG.md .planning/alignment/policy.md .planning/alignment/gap-register.yaml .planning/graphs/policy.md .planning/graphs/.gitignore .planning/security/policy.md'
|
|
71
|
+
asset_paths='.ai/start-claude.sh .ai/start-opencode.sh .ai/start-pi.sh .ai/start-kimi.sh .ai/start-qwen.sh .ai/env.example .ai/trajectory-redaction.json .ai/capabilities.json .agentfs/.gitignore .planning/config.json .planning/wiki/index.md .planning/wiki/policy.md .planning/wiki/CONTRADICTIONS.md .planning/wiki/LOG.md .planning/alignment/policy.md .planning/alignment/gap-register.yaml .planning/graphs/policy.md .planning/graphs/.gitignore .planning/security/policy.md'
|
|
71
72
|
mkdir -p "$tmp/assets-before"
|
|
72
73
|
for path in $asset_paths; do
|
|
73
74
|
cp "$tmp/repo/$path" "$tmp/assets-before/${path//\//__}"
|
|
@@ -425,6 +425,8 @@ pi_launcher="$repo/.ai/start-pi.sh"
|
|
|
425
425
|
[[ -x "$pi_launcher" ]] || fail "Pi launcher not scaffolded"
|
|
426
426
|
kimi_launcher="$repo/.ai/start-kimi.sh"
|
|
427
427
|
[[ -x "$kimi_launcher" ]] || fail "Kimi launcher not scaffolded"
|
|
428
|
+
qwen_launcher="$repo/.ai/start-qwen.sh"
|
|
429
|
+
[[ -x "$qwen_launcher" ]] || fail "Qwen launcher not scaffolded"
|
|
428
430
|
|
|
429
431
|
# OpenCode's run mode ends a turn after content-only output. Commands that need
|
|
430
432
|
# owner I/O must therefore make their first response action a tool call rather
|
|
@@ -471,12 +473,18 @@ cat > "$tmp/bin/kimi" <<'FAKE'
|
|
|
471
473
|
{ echo "args:$*"; echo "prelaunch:${PRELAUNCH_RAN:-0}"; echo "extra:${CAIRN_EXTRA_SETTINGS:-}"; } > "$KIMI_LOG"
|
|
472
474
|
exit "${FAKE_EXIT:-0}"
|
|
473
475
|
FAKE
|
|
474
|
-
|
|
476
|
+
cat > "$tmp/bin/qwen" <<'FAKE'
|
|
477
|
+
#!/usr/bin/env bash
|
|
478
|
+
{ echo "args:$*"; echo "prelaunch:${PRELAUNCH_RAN:-0}"; echo "extra:${CAIRN_EXTRA_SETTINGS:-}"; } > "$QWEN_LOG"
|
|
479
|
+
exit "${FAKE_EXIT:-0}"
|
|
480
|
+
FAKE
|
|
481
|
+
chmod +x "$tmp/bin/claude" "$tmp/bin/opencode" "$tmp/bin/kimi" "$tmp/bin/qwen"
|
|
475
482
|
ln -s "$ROOT/bin/cairn" "$tmp/bin/cairn"
|
|
476
483
|
export PATH="$tmp/bin:$PATH"
|
|
477
484
|
export CLAUDE_LOG="$tmp/claude.log"
|
|
478
485
|
export OPENCODE_LOG="$tmp/opencode.log"
|
|
479
486
|
export KIMI_LOG="$tmp/kimi.log"
|
|
487
|
+
export QWEN_LOG="$tmp/qwen.log"
|
|
480
488
|
|
|
481
489
|
# Claude sync has three exact installation states. Normal sync and an explicit
|
|
482
490
|
# overlay request with the master off must contain no capability hook bytes or
|
|
@@ -540,6 +548,10 @@ grep -qx "capability-registration:0" "$OPENCODE_LOG" || fail "OpenCode baseline
|
|
|
540
548
|
grep -qx "args:--foo bar" "$KIMI_LOG" || fail "Kimi baseline did not pass args through"
|
|
541
549
|
grep -qx "prelaunch:0" "$KIMI_LOG" || fail "Kimi prelaunch marker leaked without a hook"
|
|
542
550
|
|
|
551
|
+
"$qwen_launcher" --foo bar >/dev/null 2>&1 || fail "Qwen baseline launch failed"
|
|
552
|
+
grep -qx "args:--foo bar" "$QWEN_LOG" || fail "Qwen baseline did not pass args through"
|
|
553
|
+
grep -qx "prelaunch:0" "$QWEN_LOG" || fail "Qwen prelaunch marker leaked without a hook"
|
|
554
|
+
|
|
543
555
|
# Invalid/off master values stay on the legacy direct-exec path: one harness
|
|
544
556
|
# process, unchanged argv/config environment, and no isolated assets or store.
|
|
545
557
|
legacy_claude="$tmp/legacy-claude"
|
|
@@ -636,6 +648,12 @@ grep -qx "args:--plan" "$KIMI_LOG" || fail "Kimi pre-launch changed harness argv
|
|
|
636
648
|
grep -qx "prelaunch:1" "$KIMI_LOG" || fail "Kimi pre-launch env not visible to harness"
|
|
637
649
|
grep -qx "extra:$tmp/settings.json" "$KIMI_LOG" || fail "Kimi pre-launch environment was not preserved"
|
|
638
650
|
|
|
651
|
+
rm -f "$QWEN_LOG"
|
|
652
|
+
"$qwen_launcher" --approval-mode plan >/dev/null 2>&1 || fail "Qwen launch with pre-launch failed"
|
|
653
|
+
grep -qx "args:--approval-mode plan" "$QWEN_LOG" || fail "Qwen pre-launch changed harness argv"
|
|
654
|
+
grep -qx "prelaunch:1" "$QWEN_LOG" || fail "Qwen pre-launch env not visible to harness"
|
|
655
|
+
grep -qx "extra:$tmp/settings.json" "$QWEN_LOG" || fail "Qwen pre-launch environment was not preserved"
|
|
656
|
+
|
|
639
657
|
# 3. pre-launch.sh non-zero aborts the launch before the harness runs.
|
|
640
658
|
rm -f "$CLAUDE_LOG"
|
|
641
659
|
cat > "$repo/.ai/pre-launch.sh" <<'EOF'
|
|
@@ -647,6 +665,9 @@ if "$launcher" >/dev/null 2>&1; then fail "non-zero pre-launch should abort the
|
|
|
647
665
|
rm -f "$KIMI_LOG"
|
|
648
666
|
if "$kimi_launcher" >/dev/null 2>&1; then fail "non-zero pre-launch should abort Kimi"; fi
|
|
649
667
|
[[ ! -f "$KIMI_LOG" ]] || fail "Kimi ran despite pre-launch abort"
|
|
668
|
+
rm -f "$QWEN_LOG"
|
|
669
|
+
if "$qwen_launcher" >/dev/null 2>&1; then fail "non-zero pre-launch should abort Qwen"; fi
|
|
670
|
+
[[ ! -f "$QWEN_LOG" ]] || fail "Qwen ran despite pre-launch abort"
|
|
650
671
|
rm -f "$repo/.ai/pre-launch.sh"
|
|
651
672
|
|
|
652
673
|
# 4. post-exit.sh runs after the harness with $CAIRN_EXIT_STATUS.
|
|
@@ -666,6 +687,13 @@ status=$?
|
|
|
666
687
|
grep -qx "args:--auto" "$KIMI_LOG" || fail "Kimi launcher changed arguments"
|
|
667
688
|
grep -qx "post:8" "$tmp/post.log" || fail "Kimi launcher post-exit status missing"
|
|
668
689
|
|
|
690
|
+
rm -f "$tmp/post.log" "$QWEN_LOG"
|
|
691
|
+
FAKE_EXIT=10 "$qwen_launcher" --output-format json >/dev/null 2>&1 && fail "Qwen launcher should propagate harness exit code"
|
|
692
|
+
status=$?
|
|
693
|
+
[[ "$status" -eq 10 ]] || fail "expected exit 10 from Qwen launcher, got $status"
|
|
694
|
+
grep -qx "args:--output-format json" "$QWEN_LOG" || fail "Qwen launcher changed arguments"
|
|
695
|
+
grep -qx "post:10" "$tmp/post.log" || fail "Qwen launcher post-exit status missing"
|
|
696
|
+
|
|
669
697
|
# 5. Pi launcher preserves the same env/pre/post seams and passes arguments
|
|
670
698
|
# unchanged; Pi has no generic settings-file flag so CAIRN_EXTRA_SETTINGS is ignored.
|
|
671
699
|
rm -f "$repo/.ai/pre-launch.sh" "$repo/.ai/post-exit.sh"
|
|
@@ -44,6 +44,7 @@ bootstrap_output=$(cairn bootstrap "$tmp/project")
|
|
|
44
44
|
[[ -x "$tmp/project/.ai/start-claude.sh" ]] || fail "bootstrap did not install an executable Claude launcher"
|
|
45
45
|
[[ -x "$tmp/project/.ai/start-pi.sh" ]] || fail "bootstrap did not install an executable Pi launcher"
|
|
46
46
|
[[ -x "$tmp/project/.ai/start-kimi.sh" ]] || fail "bootstrap did not install an executable Kimi launcher"
|
|
47
|
+
[[ -x "$tmp/project/.ai/start-qwen.sh" ]] || fail "bootstrap did not install an executable Qwen launcher"
|
|
47
48
|
[[ -f "$tmp/project/.planning/config.json" ]] || fail "bootstrap did not install the planning scaffold"
|
|
48
49
|
|
|
49
50
|
(cd "$tmp/project" && cairn doctor) >/dev/null || fail "installed package failed cairn doctor"
|
|
@@ -223,6 +224,8 @@ NODE
|
|
|
223
224
|
fail "npm tarball omitted the Pi launcher template"
|
|
224
225
|
[[ -f "$installed_root/templates/start-kimi.sh.template" ]] || \
|
|
225
226
|
fail "npm tarball omitted the Kimi launcher template"
|
|
227
|
+
[[ -f "$installed_root/templates/start-qwen.sh.template" ]] || \
|
|
228
|
+
fail "npm tarball omitted the Qwen launcher template"
|
|
226
229
|
[[ -f "$installed_root/schemas/note.schema.json" ]] || \
|
|
227
230
|
fail "npm tarball omitted the note schema"
|
|
228
231
|
[[ -f "$installed_root/schemas/memory-node.schema.json" ]] || \
|
package/scripts/uninstall.sh
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Cairnkeep launcher for Qwen Code. Loads this repo's private .ai/.env, runs
|
|
3
|
+
# the optional pre/post seams, and launches Qwen from the project root. Qwen
|
|
4
|
+
# reads user ~/.qwen/settings.json plus project .qwen/settings.json and
|
|
5
|
+
# .mcp.json configuration.
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
|
8
|
+
|
|
9
|
+
if [[ -f "$ROOT_DIR/.ai/.env" ]]; then
|
|
10
|
+
set -a
|
|
11
|
+
# shellcheck disable=SC1091
|
|
12
|
+
. "$ROOT_DIR/.ai/.env"
|
|
13
|
+
set +a
|
|
14
|
+
fi
|
|
15
|
+
if [[ -f "$ROOT_DIR/.ai/pre-launch.sh" ]]; then
|
|
16
|
+
# shellcheck disable=SC1091
|
|
17
|
+
. "$ROOT_DIR/.ai/pre-launch.sh"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
cd "$ROOT_DIR"
|
|
21
|
+
|
|
22
|
+
if [[ -f "$ROOT_DIR/.ai/post-exit.sh" ]]; then
|
|
23
|
+
set +e
|
|
24
|
+
qwen "$@"
|
|
25
|
+
CAIRN_EXIT_STATUS=$?
|
|
26
|
+
set -e
|
|
27
|
+
export CAIRN_EXIT_STATUS
|
|
28
|
+
# shellcheck disable=SC1091
|
|
29
|
+
. "$ROOT_DIR/.ai/post-exit.sh" || true
|
|
30
|
+
exit "$CAIRN_EXIT_STATUS"
|
|
31
|
+
fi
|
|
32
|
+
exec qwen "$@"
|