@cairnkeep/cli 2.4.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 +27 -1
- package/README.md +21 -3
- package/docs/building-an-overlay.md +4 -3
- package/docs/harness-compatibility.md +195 -0
- package/docs/learning/CURRICULUM-MAP.md +91 -0
- package/docs/learning/FEATURE-GUIDE.md +86 -0
- package/docs/learning/PRODUCTION-PLAN.md +45 -14
- package/docs/learning/README.md +20 -1
- package/docs/learning/instructor-guide.md +6 -0
- package/docs/learning/lessons/L00-why-cairnkeep.md +20 -8
- package/docs/learning/lessons/L01-safe-trial.md +3 -3
- package/docs/learning/lessons/L02-installation.md +31 -5
- package/docs/learning/lessons/L03-first-project.md +7 -2
- package/docs/learning/lessons/L04-memory-fundamentals.md +4 -0
- package/docs/learning/lessons/L05-daily-workflow.md +4 -0
- package/docs/learning/lessons/L07-privacy-and-storage.md +3 -0
- package/docs/learning/lessons/L10-context-exploration.md +4 -2
- package/docs/learning/lessons/L12-managed-overlays.md +2 -0
- package/docs/learning/lessons/L13-session-evidence.md +71 -0
- package/docs/learning/lessons/L14-typed-memory.md +51 -0
- package/docs/learning/lessons/L15-capability-governance.md +56 -0
- package/docs/learning/lessons/L16-evaluation.md +67 -0
- package/docs/learning/lessons/L17-agent-boundary.md +55 -0
- package/docs/learning/templates/lesson-template.md +4 -1
- package/docs/learning/tracks/evidence-and-evaluation.md +20 -0
- package/docs/learning/tracks/operator.md +8 -2
- package/docs/learning/tracks/practitioner.md +6 -1
- package/docs/learning/tracks/quickstart.md +3 -0
- package/docs/learning/video-scripts/L00-why-cairnkeep.md +21 -17
- package/docs/learning/video-scripts/L02-installation.md +9 -2
- package/docs/learning/video-scripts/L03-first-project.md +3 -0
- package/docs/operating.md +70 -5
- package/examples/eval/bundled-fake.json +1 -1
- package/package.json +3 -2
- package/scripts/bootstrap.sh +4 -0
- package/scripts/test-bootstrap-untracked.sh +3 -1
- package/scripts/test-launcher-hooks.sh +57 -1
- package/scripts/test-learning-docs.sh +20 -4
- package/scripts/test-package-install.sh +6 -0
- package/scripts/uninstall.sh +2 -0
- package/templates/start-kimi.sh.template +39 -0
- package/templates/start-qwen.sh.template +32 -0
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
# Operator Track
|
|
2
2
|
|
|
3
3
|
**Audience:** advanced users and platform maintainers
|
|
4
|
-
**Prerequisite:** Practitioner track
|
|
5
|
-
**Total time:** about
|
|
4
|
+
**Prerequisite:** Practitioner track; L13 before operating captured evidence
|
|
5
|
+
**Total time:** about 4 hours
|
|
6
6
|
|
|
7
7
|
1. [L09 - Domain knowledge with RAG](../lessons/L09-domain-knowledge.md)
|
|
8
8
|
2. [L10 - Faster context exploration](../lessons/L10-context-exploration.md)
|
|
9
9
|
3. [L11 - Containers and isolation](../lessons/L11-containers.md)
|
|
10
10
|
4. [L12 - Managed overlays](../lessons/L12-managed-overlays.md)
|
|
11
|
+
5. [L15 - Capability governance](../lessons/L15-capability-governance.md)
|
|
12
|
+
6. [L16 - Evaluation and ablation](../lessons/L16-evaluation.md)
|
|
11
13
|
|
|
12
14
|
All modules are optional. The track is complete when the operator can add and
|
|
13
15
|
remove each integration without breaking the standalone local workflow and can
|
|
14
16
|
explain its storage, network, credential, and rollback boundaries.
|
|
17
|
+
|
|
18
|
+
Hands-on spine: `course-04-operation`, `course-06-governance`, and
|
|
19
|
+
`course-07-evaluation` in the public
|
|
20
|
+
[course labs](https://github.com/cairnkeep/cairnkeep-course-labs).
|
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
**Audience:** developers adopting Cairnkeep in daily work
|
|
4
4
|
**Prerequisite:** Quickstart track
|
|
5
|
-
**Total time:** about
|
|
5
|
+
**Total time:** about 4 hours
|
|
6
6
|
|
|
7
7
|
1. [L04 - Memory fundamentals](../lessons/L04-memory-fundamentals.md)
|
|
8
8
|
2. [L05 - The daily workflow](../lessons/L05-daily-workflow.md)
|
|
9
9
|
3. [L06 - Repository review and security](../lessons/L06-repository-quality.md)
|
|
10
10
|
4. [L07 - Privacy and storage](../lessons/L07-privacy-and-storage.md)
|
|
11
11
|
5. [L08 - Multiple machines](../lessons/L08-multiple-machines.md)
|
|
12
|
+
6. [L13 - Session evidence and hindsight](../lessons/L13-session-evidence.md)
|
|
12
13
|
|
|
13
14
|
The track is complete when the learner can decide what should become memory,
|
|
14
15
|
review derived knowledge, run governed repository checks, locate the store, and
|
|
15
16
|
perform a reversible backup or migration.
|
|
17
|
+
|
|
18
|
+
Hands-on spine: `course-02-memory`, `course-03-quality`, and
|
|
19
|
+
`course-05-evidence` in the public
|
|
20
|
+
[course labs](https://github.com/cairnkeep/cairnkeep-course-labs).
|
|
@@ -12,3 +12,6 @@
|
|
|
12
12
|
The track is complete when a learner can start a new harness session, retrieve
|
|
13
13
|
a previously accepted fact, and explain that default stdio memory is stored on
|
|
14
14
|
the local machine rather than a discovered remote service.
|
|
15
|
+
|
|
16
|
+
Hands-on spine: `course-00-app` through `course-01-bootstrap` in the public
|
|
17
|
+
[course labs](https://github.com/cairnkeep/cairnkeep-course-labs).
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
## Recording setup
|
|
7
7
|
|
|
8
|
-
- Show only the
|
|
8
|
+
- Show only the trust-ladder table from the lesson.
|
|
9
9
|
- Prepare one slide containing the question: “What should survive this session?”
|
|
10
10
|
- No terminal or private project is required.
|
|
11
11
|
|
|
@@ -24,12 +24,14 @@ remember, and what must remain in the repository or another canonical system.”
|
|
|
24
24
|
|
|
25
25
|
**Show:** The lesson outcome.
|
|
26
26
|
|
|
27
|
-
## 01:00 -
|
|
27
|
+
## 01:00 - Trust ladder
|
|
28
28
|
|
|
29
|
-
**Say:** “
|
|
30
|
-
context.
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
**Say:** “Follow information through a trust ladder. The current conversation is
|
|
30
|
+
working context. Optional captured evidence and hindsight notes preserve bounded
|
|
31
|
+
local observations, but they are not automatically trusted memory. Cairnkeep
|
|
32
|
+
memory holds concise operational facts. The project wiki is derived, cited
|
|
33
|
+
knowledge. Code, tests, specifications, policies, and issue trackers remain
|
|
34
|
+
canonical.”
|
|
33
35
|
|
|
34
36
|
**Show:** Reveal one table row at a time.
|
|
35
37
|
|
|
@@ -38,10 +40,11 @@ agent find and apply knowledge; it does not redefine truth.”
|
|
|
38
40
|
|
|
39
41
|
## 02:40 - Memory versus RAG
|
|
40
42
|
|
|
41
|
-
**Say:** “Document RAG
|
|
42
|
-
|
|
43
|
-
it does not require
|
|
44
|
-
memory. The complete migration policy remains a
|
|
43
|
+
**Say:** “Document RAG and codebase exploration answer a different question:
|
|
44
|
+
which source material is relevant right now? Cairnkeep can integrate with those
|
|
45
|
+
retrieval paths, but it does not require them. A decision such as ‘use
|
|
46
|
+
transactional migrations’ is a memory. The complete migration policy remains a
|
|
47
|
+
document.”
|
|
45
48
|
|
|
46
49
|
**Show:** Memory on the left, document retrieval on the right.
|
|
47
50
|
|
|
@@ -57,20 +60,21 @@ until confirmed. A verified operational prohibition is a durable constraint.”
|
|
|
57
60
|
## 05:10 - Boundary
|
|
58
61
|
|
|
59
62
|
**Say:** “Cairnkeep does not store every sentence from a session. The default
|
|
60
|
-
stdio setup stores memory on this computer.
|
|
61
|
-
|
|
63
|
+
stdio setup stores memory on this computer. Structured capture, notes,
|
|
64
|
+
artifacts, evaluation, remote storage, model extraction, embeddings, and
|
|
65
|
+
document RAG are separate explicit choices.”
|
|
62
66
|
|
|
63
67
|
**Show:** “Local by default. Optional means opt-in.”
|
|
64
68
|
|
|
65
69
|
## 06:10 - Recap
|
|
66
70
|
|
|
67
|
-
**Say:** “Remember three things: durable memory is selective,
|
|
68
|
-
|
|
69
|
-
In L01 we will inspect the published container without
|
|
70
|
-
workflow.”
|
|
71
|
+
**Say:** “Remember three things: durable memory is selective, evidence is not
|
|
72
|
+
automatically trusted memory, and canonical sources still win. Optional layers
|
|
73
|
+
are not prerequisites. In L01 we will inspect the published container without
|
|
74
|
+
installing the complete workflow.”
|
|
71
75
|
|
|
72
76
|
## Editing notes
|
|
73
77
|
|
|
74
|
-
- Chapters: Problem,
|
|
78
|
+
- Chapters: Problem, Trust ladder, Memory vs retrieval, Exercise, Boundary.
|
|
75
79
|
- Link L00 and L01 in the description.
|
|
76
80
|
- Re-record the version-independent slide only if the conceptual model changes.
|
|
@@ -71,13 +71,20 @@ the harness after applying assets.”
|
|
|
71
71
|
|
|
72
72
|
**Show:** The two verification commands together.
|
|
73
73
|
|
|
74
|
-
## 09:
|
|
74
|
+
## 09:30 - Optional shell completion
|
|
75
|
+
|
|
76
|
+
**Do:** Run `source <(cairn completion bash)` and complete `cairn tra`.
|
|
77
|
+
|
|
78
|
+
**Say:** “Completion is optional convenience. It does not start another server
|
|
79
|
+
or enable any feature.”
|
|
80
|
+
|
|
81
|
+
## 10:00 - Boundary
|
|
75
82
|
|
|
76
83
|
**Say:** “This default server is local. We did not configure embeddings,
|
|
77
84
|
document RAG, or remote HTTP memory. Those choices have separate lessons
|
|
78
85
|
because they change data flow.”
|
|
79
86
|
|
|
80
|
-
##
|
|
87
|
+
## 11:00 - Recap
|
|
81
88
|
|
|
82
89
|
**Say:** “The machine setup has three pieces: CLI, MCP registration, and the
|
|
83
90
|
operating layer. In L03 we add the fourth piece, a bootstrapped project, and
|
|
@@ -43,6 +43,9 @@ does not reinstall the machine-level MCP server or operating assets.”
|
|
|
43
43
|
**Say:** “Optional unconfigured integrations may be skipped. A configured but
|
|
44
44
|
unreachable dependency is a failure and should be fixed before relying on it.”
|
|
45
45
|
|
|
46
|
+
**Point out:** Session capture, notes, compaction, artifacts, typed memory,
|
|
47
|
+
capability governance, and evaluation remain off for the core-memory proof.
|
|
48
|
+
|
|
46
49
|
## 05:00 - Launch and remember
|
|
47
50
|
|
|
48
51
|
**Do:** Start `./.ai/start-claude.sh`.
|
package/docs/operating.md
CHANGED
|
@@ -16,8 +16,10 @@ installs. This guide covers all three in order.
|
|
|
16
16
|
|
|
17
17
|
## Prerequisites
|
|
18
18
|
|
|
19
|
-
- Node.js 22 or newer (for the memory server) and a supported harness
|
|
20
|
-
Code
|
|
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 and Qwen Code
|
|
21
|
+
receive the memory MCP and launcher. Pi receives its native trajectory
|
|
22
|
+
adapter.
|
|
21
23
|
- Optional: the `sqlite3` CLI for `cairn memory export`. Runtime memory and
|
|
22
24
|
`cairn memory import` do not require it.
|
|
23
25
|
- Optional: an OpenAI-compatible LLM endpoint for memory extraction and
|
|
@@ -157,6 +159,68 @@ Model selection stays operator-env-driven through the existing
|
|
|
157
159
|
variables (see "Configuration" below) — the harness commits no default model
|
|
158
160
|
and carries no known-good allowlist.
|
|
159
161
|
|
|
162
|
+
## Setup order (Kimi Code)
|
|
163
|
+
|
|
164
|
+
Kimi Code can use the Cairnkeep memory MCP and the generated project launcher.
|
|
165
|
+
It does not yet receive Cairnkeep-specific skills, commands, or hooks.
|
|
166
|
+
|
|
167
|
+
For local stdio memory, create `.kimi-code/mcp.json` in the project:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"mcpServers": {
|
|
172
|
+
"cairn-memory": {
|
|
173
|
+
"command": "cairn",
|
|
174
|
+
"args": ["memory-server"]
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Then launch from the project root with `./.ai/start-kimi.sh`. The launcher
|
|
181
|
+
loads `.ai/.env`, runs the optional pre-launch and post-exit hooks, and forwards
|
|
182
|
+
all arguments to `kimi`.
|
|
183
|
+
|
|
184
|
+
Remote HTTP configuration needs one extra precaution: Kimi validates `url` as
|
|
185
|
+
a literal URL and does not expand `${CAIRN_MEMORY_REMOTE_URL}` there. Put the
|
|
186
|
+
resolved URL in a private `.kimi-code/mcp.json` and use
|
|
187
|
+
`bearerTokenEnvVar: "CAIRN_MEMORY_HTTP_TOKEN"` so the token value remains in
|
|
188
|
+
the environment. A repository-root `.mcp.json` must also be valid because Kimi
|
|
189
|
+
parses it before applying its private override. See
|
|
190
|
+
[Harness compatibility](harness-compatibility.md#kimi-code) for the complete
|
|
191
|
+
configuration and trust-boundary guidance.
|
|
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
|
+
|
|
160
224
|
## Setup order (Pi)
|
|
161
225
|
|
|
162
226
|
Pi trajectory capture uses the same project scaffold and store, but its source
|
|
@@ -630,13 +694,14 @@ maintain a running install — without forking the core. All are opt-in.
|
|
|
630
694
|
|
|
631
695
|
### Launcher seams
|
|
632
696
|
|
|
633
|
-
The generic launchers (`.ai/start-claude.sh`, `.ai/start-opencode.sh
|
|
634
|
-
|
|
697
|
+
The generic launchers (`.ai/start-claude.sh`, `.ai/start-opencode.sh`,
|
|
698
|
+
`.ai/start-kimi.sh`, `.ai/start-qwen.sh`, and `.ai/start-pi.sh`) run optional hooks around the
|
|
699
|
+
harness, each a no-op when absent:
|
|
635
700
|
|
|
636
701
|
| Seam | When | Purpose |
|
|
637
702
|
|---|---|---|
|
|
638
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 |
|
|
639
|
-
| `CAIRN_EXTRA_SETTINGS` | read just before launch | path to a settings file layered on
|
|
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 |
|
|
640
705
|
| `.ai/post-exit.sh` | sourced after the harness exits | teardown; `CAIRN_EXIT_STATUS` holds the exit code |
|
|
641
706
|
|
|
642
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
|
@@ -56,6 +56,8 @@ install_file() {
|
|
|
56
56
|
install_file "$TPL/start-claude.sh.template" "$target/.ai/start-claude.sh" 0755
|
|
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
|
+
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
|
|
59
61
|
install_file "$TPL/env.example.template" "$target/.ai/env.example" 0644
|
|
60
62
|
install_file "$TPL/trajectory-redaction.json.template" "$target/.ai/trajectory-redaction.json" 0644
|
|
61
63
|
install_file "$TPL/capabilities.json.template" "$target/.ai/capabilities.json" 0600
|
|
@@ -105,3 +107,5 @@ echo " 3. Install the operating layer (commands/agents/hooks): cairn sync --app
|
|
|
105
107
|
echo " For Pi trajectory capture, also run: cairn sync-pi --apply"
|
|
106
108
|
echo " From a source clone, use bin/cairn in place of cairn."
|
|
107
109
|
echo " 4. Launch: $target/.ai/start-claude.sh"
|
|
110
|
+
echo " Kimi memory-client launch: $target/.ai/start-kimi.sh"
|
|
111
|
+
echo " Qwen memory-client launch: $target/.ai/start-qwen.sh"
|
|
@@ -53,6 +53,8 @@ mkdir "$tmp/repo"
|
|
|
53
53
|
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
|
+
[[ -x "$tmp/repo/.ai/start-kimi.sh" ]] || fail "Kimi launcher missing"
|
|
57
|
+
[[ -x "$tmp/repo/.ai/start-qwen.sh" ]] || fail "Qwen launcher missing"
|
|
56
58
|
[[ -f "$tmp/repo/.planning/config.json" ]] || fail "planning layer missing"
|
|
57
59
|
[[ -f "$tmp/repo/.agentfs/.gitignore" ]] || fail "project-memory ignore guard missing"
|
|
58
60
|
[[ -z "$(git -C "$tmp/repo" status --porcelain)" ]] || fail "scaffold visible to git"
|
|
@@ -66,7 +68,7 @@ grep -qxF "/.agentfs/" "$tmp/repo/.git/info/exclude" || fail "missing /.agentfs/
|
|
|
66
68
|
printf '%s\n' '{"schema_version":1,"capabilities":{"wiki":false},"logging":{"callbacks":true}}' >"$tmp/repo/.ai/capabilities.json"
|
|
67
69
|
chmod 600 "$tmp/repo/.ai/capabilities.json"
|
|
68
70
|
printf '%s\n' '# operator-owned environment' >"$tmp/repo/.ai/env.example"
|
|
69
|
-
asset_paths='.ai/start-claude.sh .ai/start-opencode.sh .ai/start-pi.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'
|
|
70
72
|
mkdir -p "$tmp/assets-before"
|
|
71
73
|
for path in $asset_paths; do
|
|
72
74
|
cp "$tmp/repo/$path" "$tmp/assets-before/${path//\//__}"
|
|
@@ -423,6 +423,10 @@ launcher="$repo/.ai/start-claude.sh"
|
|
|
423
423
|
[[ -x "$launcher" ]] || fail "launcher not scaffolded"
|
|
424
424
|
pi_launcher="$repo/.ai/start-pi.sh"
|
|
425
425
|
[[ -x "$pi_launcher" ]] || fail "Pi launcher not scaffolded"
|
|
426
|
+
kimi_launcher="$repo/.ai/start-kimi.sh"
|
|
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"
|
|
426
430
|
|
|
427
431
|
# OpenCode's run mode ends a turn after content-only output. Commands that need
|
|
428
432
|
# owner I/O must therefore make their first response action a tool call rather
|
|
@@ -464,11 +468,23 @@ cat > "$tmp/bin/opencode" <<'FAKE'
|
|
|
464
468
|
} > "$OPENCODE_LOG"
|
|
465
469
|
exit "${FAKE_EXIT:-0}"
|
|
466
470
|
FAKE
|
|
467
|
-
|
|
471
|
+
cat > "$tmp/bin/kimi" <<'FAKE'
|
|
472
|
+
#!/usr/bin/env bash
|
|
473
|
+
{ echo "args:$*"; echo "prelaunch:${PRELAUNCH_RAN:-0}"; echo "extra:${CAIRN_EXTRA_SETTINGS:-}"; } > "$KIMI_LOG"
|
|
474
|
+
exit "${FAKE_EXIT:-0}"
|
|
475
|
+
FAKE
|
|
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"
|
|
468
482
|
ln -s "$ROOT/bin/cairn" "$tmp/bin/cairn"
|
|
469
483
|
export PATH="$tmp/bin:$PATH"
|
|
470
484
|
export CLAUDE_LOG="$tmp/claude.log"
|
|
471
485
|
export OPENCODE_LOG="$tmp/opencode.log"
|
|
486
|
+
export KIMI_LOG="$tmp/kimi.log"
|
|
487
|
+
export QWEN_LOG="$tmp/qwen.log"
|
|
472
488
|
|
|
473
489
|
# Claude sync has three exact installation states. Normal sync and an explicit
|
|
474
490
|
# overlay request with the master off must contain no capability hook bytes or
|
|
@@ -528,6 +544,14 @@ grep -qx "args:--foo bar" "$OPENCODE_LOG" || fail "OpenCode baseline did not pas
|
|
|
528
544
|
grep -qx "config:" "$OPENCODE_LOG" || fail "OpenCode baseline selected a config root"
|
|
529
545
|
grep -qx "capability-registration:0" "$OPENCODE_LOG" || fail "OpenCode baseline registered a capability plugin"
|
|
530
546
|
|
|
547
|
+
"$kimi_launcher" --foo bar >/dev/null 2>&1 || fail "Kimi baseline launch failed"
|
|
548
|
+
grep -qx "args:--foo bar" "$KIMI_LOG" || fail "Kimi baseline did not pass args through"
|
|
549
|
+
grep -qx "prelaunch:0" "$KIMI_LOG" || fail "Kimi prelaunch marker leaked without a hook"
|
|
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
|
+
|
|
531
555
|
# Invalid/off master values stay on the legacy direct-exec path: one harness
|
|
532
556
|
# process, unchanged argv/config environment, and no isolated assets or store.
|
|
533
557
|
legacy_claude="$tmp/legacy-claude"
|
|
@@ -618,6 +642,18 @@ grep -qx "prelaunch:1" "$OPENCODE_LOG" || fail "OpenCode pre-launch env not visi
|
|
|
618
642
|
grep -qx "args:--settings-probe" "$OPENCODE_LOG" || fail "OpenCode extra config changed harness argv"
|
|
619
643
|
grep -qx "explicit-config:$tmp/settings.json" "$OPENCODE_LOG" || fail "CAIRN_EXTRA_SETTINGS not exported as OPENCODE_CONFIG"
|
|
620
644
|
|
|
645
|
+
rm -f "$KIMI_LOG"
|
|
646
|
+
"$kimi_launcher" --plan >/dev/null 2>&1 || fail "Kimi launch with pre-launch failed"
|
|
647
|
+
grep -qx "args:--plan" "$KIMI_LOG" || fail "Kimi pre-launch changed harness argv"
|
|
648
|
+
grep -qx "prelaunch:1" "$KIMI_LOG" || fail "Kimi pre-launch env not visible to harness"
|
|
649
|
+
grep -qx "extra:$tmp/settings.json" "$KIMI_LOG" || fail "Kimi pre-launch environment was not preserved"
|
|
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
|
+
|
|
621
657
|
# 3. pre-launch.sh non-zero aborts the launch before the harness runs.
|
|
622
658
|
rm -f "$CLAUDE_LOG"
|
|
623
659
|
cat > "$repo/.ai/pre-launch.sh" <<'EOF'
|
|
@@ -626,6 +662,12 @@ return 1
|
|
|
626
662
|
EOF
|
|
627
663
|
if "$launcher" >/dev/null 2>&1; then fail "non-zero pre-launch should abort the launch"; fi
|
|
628
664
|
[[ ! -f "$CLAUDE_LOG" ]] || fail "harness ran despite pre-launch abort"
|
|
665
|
+
rm -f "$KIMI_LOG"
|
|
666
|
+
if "$kimi_launcher" >/dev/null 2>&1; then fail "non-zero pre-launch should abort Kimi"; fi
|
|
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"
|
|
629
671
|
rm -f "$repo/.ai/pre-launch.sh"
|
|
630
672
|
|
|
631
673
|
# 4. post-exit.sh runs after the harness with $CAIRN_EXIT_STATUS.
|
|
@@ -638,6 +680,20 @@ status=$?
|
|
|
638
680
|
[[ "$status" -eq 7 ]] || fail "expected exit 7 from launcher, got $status"
|
|
639
681
|
grep -qx "post:7" "$tmp/post.log" || fail "post-exit hook did not see CAIRN_EXIT_STATUS"
|
|
640
682
|
|
|
683
|
+
rm -f "$tmp/post.log" "$KIMI_LOG"
|
|
684
|
+
FAKE_EXIT=8 "$kimi_launcher" --auto >/dev/null 2>&1 && fail "Kimi launcher should propagate harness exit code"
|
|
685
|
+
status=$?
|
|
686
|
+
[[ "$status" -eq 8 ]] || fail "expected exit 8 from Kimi launcher, got $status"
|
|
687
|
+
grep -qx "args:--auto" "$KIMI_LOG" || fail "Kimi launcher changed arguments"
|
|
688
|
+
grep -qx "post:8" "$tmp/post.log" || fail "Kimi launcher post-exit status missing"
|
|
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
|
+
|
|
641
697
|
# 5. Pi launcher preserves the same env/pre/post seams and passes arguments
|
|
642
698
|
# unchanged; Pi has no generic settings-file flag so CAIRN_EXTRA_SETTINGS is ignored.
|
|
643
699
|
rm -f "$repo/.ai/pre-launch.sh" "$repo/.ai/post-exit.sh"
|
|
@@ -7,13 +7,22 @@ cd "$ROOT"
|
|
|
7
7
|
version=$(node -p "require('./package.json').version")
|
|
8
8
|
landing=docs/learning/README.md
|
|
9
9
|
production=docs/learning/PRODUCTION-PLAN.md
|
|
10
|
+
coverage=docs/learning/CURRICULUM-MAP.md
|
|
11
|
+
feature_guide=docs/learning/FEATURE-GUIDE.md
|
|
10
12
|
|
|
11
|
-
[[ -f "$landing" && -f "$production" ]]
|
|
13
|
+
[[ -f "$landing" && -f "$production" && -f "$coverage" && -f "$feature_guide" ]]
|
|
12
14
|
grep -qF 'docs/learning/README.md' README.md
|
|
15
|
+
grep -qF "**Baseline:** Cairnkeep $version" "$coverage"
|
|
16
|
+
grep -qF "**Baseline:** Cairnkeep $version" "$feature_guide"
|
|
17
|
+
grep -qF 'https://github.com/cairnkeep/cairnkeep-course-labs' "$landing"
|
|
18
|
+
for checkpoint in course-00-app course-01-bootstrap course-02-memory course-03-quality \
|
|
19
|
+
course-04-operation course-05-evidence course-06-governance course-07-evaluation; do
|
|
20
|
+
grep -qF "\`$checkpoint\`" "$coverage"
|
|
21
|
+
done
|
|
13
22
|
|
|
14
23
|
ready=0
|
|
15
24
|
brief=0
|
|
16
|
-
for number in $(seq -w 0
|
|
25
|
+
for number in $(seq -w 0 17); do
|
|
17
26
|
matches=(docs/learning/lessons/L"$number"-*.md)
|
|
18
27
|
[[ ${#matches[@]} -eq 1 && -f ${matches[0]} ]] || {
|
|
19
28
|
echo "learning path must contain exactly one L$number lesson" >&2
|
|
@@ -41,17 +50,24 @@ for number in $(seq -w 0 12); do
|
|
|
41
50
|
fi
|
|
42
51
|
done
|
|
43
52
|
|
|
44
|
-
[[ $ready -eq 4 && $brief -eq
|
|
53
|
+
[[ $ready -eq 4 && $brief -eq 14 ]] || {
|
|
45
54
|
echo "unexpected learning status totals: ready=$ready brief=$brief" >&2
|
|
46
55
|
exit 1
|
|
47
56
|
}
|
|
48
57
|
|
|
49
|
-
for track in quickstart practitioner operator; do
|
|
58
|
+
for track in quickstart practitioner evidence-and-evaluation operator; do
|
|
50
59
|
file=docs/learning/tracks/$track.md
|
|
51
60
|
[[ -f "$file" ]]
|
|
52
61
|
grep -q '^# ' "$file"
|
|
53
62
|
done
|
|
54
63
|
|
|
64
|
+
while read -r command; do
|
|
65
|
+
grep -qF "\`cairn $command\`" "$coverage" || {
|
|
66
|
+
echo "top-level command has no curriculum owner: cairn $command" >&2
|
|
67
|
+
exit 1
|
|
68
|
+
}
|
|
69
|
+
done < <(bin/cairn help | sed -n 's/^ cairn \([a-z-]*\).*/\1/p' | sort -u)
|
|
70
|
+
|
|
55
71
|
node <<'NODE'
|
|
56
72
|
const { existsSync, readdirSync, readFileSync } = require("node:fs");
|
|
57
73
|
const { dirname, resolve } = require("node:path");
|
|
@@ -43,6 +43,8 @@ bootstrap_output=$(cairn bootstrap "$tmp/project")
|
|
|
43
43
|
[[ "$bootstrap_output" == *"cairn sync --apply"* ]] || fail "bootstrap printed invalid operating-layer setup instructions"
|
|
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
|
+
[[ -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"
|
|
46
48
|
[[ -f "$tmp/project/.planning/config.json" ]] || fail "bootstrap did not install the planning scaffold"
|
|
47
49
|
|
|
48
50
|
(cd "$tmp/project" && cairn doctor) >/dev/null || fail "installed package failed cairn doctor"
|
|
@@ -220,6 +222,10 @@ NODE
|
|
|
220
222
|
fail "npm tarball omitted the Pi sync command"
|
|
221
223
|
[[ -f "$installed_root/templates/start-pi.sh.template" ]] || \
|
|
222
224
|
fail "npm tarball omitted the Pi launcher template"
|
|
225
|
+
[[ -f "$installed_root/templates/start-kimi.sh.template" ]] || \
|
|
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"
|
|
223
229
|
[[ -f "$installed_root/schemas/note.schema.json" ]] || \
|
|
224
230
|
fail "npm tarball omitted the note schema"
|
|
225
231
|
[[ -f "$installed_root/schemas/memory-node.schema.json" ]] || \
|
package/scripts/uninstall.sh
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Cairnkeep launcher for Kimi Code. Loads this repo's .ai/.env (if present),
|
|
3
|
+
# then launches Kimi from the repo root. Kimi reads a valid project .mcp.json
|
|
4
|
+
# and an optional .kimi-code/mcp.json override; it does not expand environment
|
|
5
|
+
# references in an HTTP URL, so remote URLs must be materialized by private
|
|
6
|
+
# machine configuration rather than committed to a shared project file.
|
|
7
|
+
#
|
|
8
|
+
# Wrapper seams (both optional, both no-ops when absent):
|
|
9
|
+
# .ai/pre-launch.sh sourced after .env, before launch. May export env
|
|
10
|
+
# or abort the launch by returning/exiting non-zero.
|
|
11
|
+
# .ai/post-exit.sh sourced after Kimi exits, with
|
|
12
|
+
# $CAIRN_EXIT_STATUS set to the exit code.
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
|
15
|
+
|
|
16
|
+
if [[ -f "$ROOT_DIR/.ai/.env" ]]; then
|
|
17
|
+
set -a
|
|
18
|
+
# shellcheck disable=SC1091
|
|
19
|
+
. "$ROOT_DIR/.ai/.env"
|
|
20
|
+
set +a
|
|
21
|
+
fi
|
|
22
|
+
if [[ -f "$ROOT_DIR/.ai/pre-launch.sh" ]]; then
|
|
23
|
+
# shellcheck disable=SC1091
|
|
24
|
+
. "$ROOT_DIR/.ai/pre-launch.sh"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
cd "$ROOT_DIR"
|
|
28
|
+
|
|
29
|
+
if [[ -f "$ROOT_DIR/.ai/post-exit.sh" ]]; then
|
|
30
|
+
set +e
|
|
31
|
+
kimi "$@"
|
|
32
|
+
CAIRN_EXIT_STATUS=$?
|
|
33
|
+
set -e
|
|
34
|
+
export CAIRN_EXIT_STATUS
|
|
35
|
+
# shellcheck disable=SC1091
|
|
36
|
+
. "$ROOT_DIR/.ai/post-exit.sh" || true
|
|
37
|
+
exit "$CAIRN_EXIT_STATUS"
|
|
38
|
+
fi
|
|
39
|
+
exec kimi "$@"
|
|
@@ -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 "$@"
|