@misterhuydo/cairn-mcp 1.18.0 → 1.20.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/README.md +84 -3
- package/dist/cairn-cli.js +74 -73
- package/dist/index.js +55 -55
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,10 +50,11 @@ server load.
|
|
|
50
50
|
| Hook | Trigger | Effect |
|
|
51
51
|
|---|---|---|
|
|
52
52
|
| `PreToolUse[Read]` | Every file read | Source files compressed ~68% before Claude sees them; large files show structural outline with **line numbers** to save tokens |
|
|
53
|
-
| `PreToolUse[Edit]` | Every file edit | Blocks Edit if Claude only saw compressed content — requires a full re-read first |
|
|
53
|
+
| `PreToolUse[Edit]` | Every file edit | Blocks Edit if Claude only saw compressed content — requires a full re-read first. Reported as a permission decision with a one-line reason, **not** as a red hook error: being sent back to re-read a file is a normal step, and the full source rides along out of sight so it does not fill the screen |
|
|
54
54
|
| `PostToolUse[ExitPlanMode]` | A plan is approved | The plan is parsed into `### Phase N` entries in `.cairn/roadmap.md`, synced, and the cursor activated |
|
|
55
55
|
| `PostToolUse[TodoWrite]` | The todo list changes | Todos mirror onto the roadmap as sub-tasks under the current phase (or seed root phases if none exist) |
|
|
56
|
-
| `Stop` | End of every response | Session auto-saved to `.cairn/session.json`, Claude auto-memory backed up to `.cairn/memory/`, the roadmap re-surfaced,
|
|
56
|
+
| `Stop` | End of every response | Session auto-saved to `.cairn/session.json`, Claude auto-memory backed up to `.cairn/memory/`, the roadmap re-surfaced, any git-detected completed phases surfaced for you to confirm, and — once the session is genuinely large — a prompt asking whether you want to `/clear` or `/compact`, with a recommendation and the reason. All in one line |
|
|
57
|
+
| `SessionStart[clear]`<br>`SessionStart[compact]` | Right after you `/clear` or `/compact` | The checkpoint is re-injected into the fresh session automatically, so it opens already knowing the open thread and what the last session would have lost. You do not have to type "resume" |
|
|
57
58
|
| `UserPromptSubmit` | First message of a new session | Fresh project: Claude prompted to run `cairn_maintain`. Returning session: Claude prompted to run `cairn_resume`. Memory restored from `.cairn/memory/` if the Claude store is empty (new machine / fresh clone) |
|
|
58
59
|
|
|
59
60
|
---
|
|
@@ -83,7 +84,7 @@ No manual steps. The index lives in `.cairn/index.db` inside your project — li
|
|
|
83
84
|
| `cairn_todos` | Scan codebase for TODO/FIXME/HACK comments, add manual items, resolve and list them |
|
|
84
85
|
| `cairn_roadmap` | The active project plan: phases authored in `.cairn/roadmap.md`, with a cursor, dependencies, and auto-pruning of shipped phases into `.cairn/roadmap_completed.md` |
|
|
85
86
|
| `cairn_bundle` | Minified source snapshot (auto-handled by hooks) |
|
|
86
|
-
| `cairn_checkpoint` | Save session state (auto-handled by hooks) |
|
|
87
|
+
| `cairn_checkpoint` | Save session state (auto-handled by hooks). At a stopping point, answer `would_be_lost` — the one part that git and the index cannot recover |
|
|
87
88
|
| `cairn_minify` | Minify a single file on demand (fallback when hooks are not installed) |
|
|
88
89
|
| `cairn_switch` | Switch active project root mid-session (use for maintenance on a sibling service) |
|
|
89
90
|
| `cairn_memo` | Save a preference, decision, or discovery to the project's persistent memory |
|
|
@@ -236,6 +237,86 @@ before calling `set_status … done`, so a stray keyword can't silently prune yo
|
|
|
236
237
|
|
|
237
238
|
---
|
|
238
239
|
|
|
240
|
+
## Stopping points: what clearing would cost
|
|
241
|
+
|
|
242
|
+
Before `/clear` or `/compact`, the question that actually matters is not *how full
|
|
243
|
+
is the window*. Fullness tells you **when**; it never tells you **which**. What
|
|
244
|
+
decides it is whether the saved state is sufficient — "the slice is three-quarters
|
|
245
|
+
built and the fact that long-press selection has never run on a real handset is
|
|
246
|
+
written down nowhere" is a judgement about the handoff, not about a percentage.
|
|
247
|
+
|
|
248
|
+
Cairn cannot make that judgement for you. It cannot audit for absence: the gap
|
|
249
|
+
worth reporting is by definition the thing nobody wrote down, and a lazy
|
|
250
|
+
checkpoint looks exactly like a thorough one from the outside. A tool that
|
|
251
|
+
computed this would print "nothing outstanding" on precisely the sessions where
|
|
252
|
+
the most was outstanding. So cairn does the part it can do honestly — it **demands
|
|
253
|
+
the judgement on the way in and carries it across the gap**:
|
|
254
|
+
|
|
255
|
+
1. **`cairn_checkpoint` asks.** A `would_be_lost` field whose description is the
|
|
256
|
+
literal question: what would a fresh session not know? Unverified work, a
|
|
257
|
+
thread you are mid-way through, a decision whose reason never made it into the
|
|
258
|
+
commit message. A checkpoint that skips it says so in its result rather than
|
|
259
|
+
passing silently.
|
|
260
|
+
2. **`cairn_resume` carries it back**, near the top of the payload and first in
|
|
261
|
+
the summary, because everything else resume returns is recoverable from git and
|
|
262
|
+
the index and this is the only part that is not. It also lands on the first
|
|
263
|
+
prompt of the next session, since a session picked up after `/clear` rarely
|
|
264
|
+
opens with the word "resume".
|
|
265
|
+
3. **It ages.** The end-of-turn hook checkpoints every turn, so `session.json`
|
|
266
|
+
always *looks* fresh while its contents may be hours and several slices stale.
|
|
267
|
+
The handoff is stamped only when it is actually written, never by the
|
|
268
|
+
heartbeat that copies it forward, and anything written before commits that
|
|
269
|
+
have since landed is reported as possibly stale.
|
|
270
|
+
4. **Then, and only then, it asks.** When the session crosses the threshold **and**
|
|
271
|
+
something is actually at risk, the Stop hook asks you to choose, with a
|
|
272
|
+
recommendation and the reason:
|
|
273
|
+
|
|
274
|
+
> **Checkpoint + /clear (Recommended)** — I write the handoff now, then you type `/clear`
|
|
275
|
+
> **Checkpoint + /compact** — I write the handoff now, then you type `/compact`
|
|
276
|
+
> **Keep going** — decline
|
|
277
|
+
|
|
278
|
+
Which one is recommended follows from the handoff, not from fullness. A
|
|
279
|
+
*current* handoff means the thread survives a hard reset, so `/clear` wins and
|
|
280
|
+
you get the full window back. A *missing or stale* one means something unwritten
|
|
281
|
+
is at risk, so `/compact` wins and keeps it reachable. Either choice writes the
|
|
282
|
+
checkpoint first — including `/clear`, which needs it most, not least.
|
|
283
|
+
|
|
284
|
+
5. **And it is there afterwards.** `SessionStart[clear|compact]` re-injects the
|
|
285
|
+
checkpoint into the fresh session, so it opens already knowing where it is. You
|
|
286
|
+
never have to remember to type "resume", which is exactly the manual step that
|
|
287
|
+
gets skipped on the sessions where skipping it costs the most.
|
|
288
|
+
|
|
289
|
+
**Cairn cannot type the command.** No hook output and no tool can trigger a slash
|
|
290
|
+
command, so the agent does the half it can do (the checkpoint, immediately) and you
|
|
291
|
+
type the six characters. Anything that claimed otherwise would leave you waiting for
|
|
292
|
+
something that never happens.
|
|
293
|
+
|
|
294
|
+
### How the size is measured
|
|
295
|
+
|
|
296
|
+
Not from file size. No hook input carries token counts, but every hook receives
|
|
297
|
+
`transcript_path`, and the transcript's assistant records carry the usage the API
|
|
298
|
+
actually reported — so cairn tail-reads the last 256 KB and sums the real window
|
|
299
|
+
(input + cache reads + cache creation + output). Measured cost: 6 lines parsed,
|
|
300
|
+
0.5 ms.
|
|
301
|
+
|
|
302
|
+
v1.19.0 used transcript bytes as the proxy and it was wrong in the one place that
|
|
303
|
+
mattered. Measured on cairn's own session: **3.40 MB of transcript holding 72,285
|
|
304
|
+
tokens of context.** Bytes keep accumulating across a `/compact` while the window
|
|
305
|
+
resets, so a byte threshold is loudest immediately *after* a compaction, when there
|
|
306
|
+
is least reason to speak. Bytes survive now only as a fallback for when no usage
|
|
307
|
+
record is reachable, and when that happens the line says so instead of dressing a
|
|
308
|
+
file size up as a token count.
|
|
309
|
+
|
|
310
|
+
Deliberately not built: no percentage (the context-window size is not observable
|
|
311
|
+
from a hook, so the denominator would be invented — the absolute count is reported
|
|
312
|
+
instead), no full transcript walk (the tail only; a full walk in this hot path once
|
|
313
|
+
froze every terminal in the cockpit for 4.3 seconds), no counting subagent spend as
|
|
314
|
+
main-thread context, no repeating the prompt when nothing changed, and no
|
|
315
|
+
auto-clearing, auto-compacting, or filling the field in on your behalf. Same shape
|
|
316
|
+
as completed-phase detection: detect, surface, confirm with the user, never apply.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
239
320
|
## Supported languages
|
|
240
321
|
|
|
241
322
|
| Language | What Cairn extracts |
|