@misterhuydo/cairn-mcp 1.19.0 → 1.21.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 CHANGED
@@ -53,7 +53,8 @@ server load.
53
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, any git-detected completed phases surfaced for you to confirm, and on a long session one line naming what clearing would cost — all in one line |
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
  ---
@@ -174,14 +175,26 @@ the **`roadmap/1`** slot format so any cockpit or tool can read it without writi
174
175
  parser per provider. One file carries both halves — two files drift, and the drift is
175
176
  invisible:
176
177
 
177
- - **A markdown half for humans:** checkboxes, per-item status, a one-line summary per
178
- phase, and a `← current` marker on the cursor phase.
179
- - **One `roadmap-json` block for consumers**, at the end of the file. It carries stable
178
+ - **A markdown half for readers:** checkboxes, per-item status, a progress bar, one
179
+ plain sentence per phase, and a `← current` marker on the cursor phase. Written for
180
+ somebody who has never heard of cairn and is reading the file on GitHub: they should
181
+ be able to say what the project is working on and what is next. That means no
182
+ authoring syntax survives into the prose — `[[wikilinks]]` are unwrapped or dropped
183
+ (they are filenames a reader cannot open) and nothing points at `.cairn/`, which is
184
+ gitignored and therefore not there for them. `.cairn/roadmap.md` remains the
185
+ authoring source and stays as detailed as you like; this half is the summary.
186
+ - **One `roadmap-json` block for consumers**, collapsed inside a `<details>` at the end
187
+ of the file so a reader never scrolls through it, and never removed — a cockpit's
188
+ per-phase view is rendered from it, and without it that view degrades silently to
189
+ flat markdown. Collapsing costs nothing: the fence keeps blank lines around it, so it
190
+ stays a valid CommonMark code block and both line-anchored and AST consumers still
191
+ find it. It carries stable
180
192
  phase `id`s, `number`, `title`, `status`, `goal`, `blocked_by`, `slices`, the full
181
- per-phase `detail` (the body you wrote in `.cairn/roadmap.md`), and `links` — the
182
- `[[wikilinks]]` in that body resolved to the memory files behind each phase, so the
183
- reasoning is one tap away instead of "go and find it". A link that cannot be resolved
184
- is dropped rather than emitted dead.
193
+ per-phase `detail` (the body you wrote in `.cairn/roadmap.md`, verbatim and in full —
194
+ thinning the prose never thins this), and `links` — the `[[wikilinks]]` in that body
195
+ resolved to the memory files behind each phase, so the reasoning is one tap away
196
+ instead of "go and find it". A link that cannot be resolved is dropped rather than
197
+ emitted dead.
185
198
 
186
199
  The first line is the marker that says who generated the file and when
187
200
  (`<!-- slot:roadmap format=roadmap/1 provider=cairn generated=… -->`). cairn declares
@@ -266,19 +279,53 @@ the judgement on the way in and carries it across the gap**:
266
279
  The handoff is stamped only when it is actually written, never by the
267
280
  heartbeat that copies it forward, and anything written before commits that
268
281
  have since landed is reported as possibly stale.
269
- 4. **Then, and only then, one line.** When the session transcript crosses a coarse
270
- size threshold **and** something is actually at risk, the Stop hook adds a line
271
- naming the loss: *"Clearing now would lose: … — last written before the 3
272
- commits since."* When the handoff is current it says what clearing costs
273
- instead, which is the more useful message and the one that lets you actually
274
- clear.
275
-
276
- Deliberately not built: no percentage (the transcript keeps growing across a
277
- compaction while the window resets, so a precise number would claim an accuracy
278
- it does not have), no transcript parsing (`statSync` only — this runs on every
279
- single turn), no repeating the line when nothing changed, and no auto-clearing,
280
- auto-compacting, or filling the field in on your behalf. Same shape as completed-phase
281
- detection: detect, surface, confirm with the user, never apply.
282
+ 4. **Then, and only then, it asks.** When the session crosses the threshold **and**
283
+ something is actually at risk, the Stop hook asks you to choose, with a
284
+ recommendation and the reason:
285
+
286
+ > **Checkpoint + /clear (Recommended)** — I write the handoff now, then you type `/clear`
287
+ > **Checkpoint + /compact** — I write the handoff now, then you type `/compact`
288
+ > **Keep going** — decline
289
+
290
+ Which one is recommended follows from the handoff, not from fullness. A
291
+ *current* handoff means the thread survives a hard reset, so `/clear` wins and
292
+ you get the full window back. A *missing or stale* one means something unwritten
293
+ is at risk, so `/compact` wins and keeps it reachable. Either choice writes the
294
+ checkpoint first — including `/clear`, which needs it most, not least.
295
+
296
+ 5. **And it is there afterwards.** `SessionStart[clear|compact]` re-injects the
297
+ checkpoint into the fresh session, so it opens already knowing where it is. You
298
+ never have to remember to type "resume", which is exactly the manual step that
299
+ gets skipped on the sessions where skipping it costs the most.
300
+
301
+ **Cairn cannot type the command.** No hook output and no tool can trigger a slash
302
+ command, so the agent does the half it can do (the checkpoint, immediately) and you
303
+ type the six characters. Anything that claimed otherwise would leave you waiting for
304
+ something that never happens.
305
+
306
+ ### How the size is measured
307
+
308
+ Not from file size. No hook input carries token counts, but every hook receives
309
+ `transcript_path`, and the transcript's assistant records carry the usage the API
310
+ actually reported — so cairn tail-reads the last 256 KB and sums the real window
311
+ (input + cache reads + cache creation + output). Measured cost: 6 lines parsed,
312
+ 0.5 ms.
313
+
314
+ v1.19.0 used transcript bytes as the proxy and it was wrong in the one place that
315
+ mattered. Measured on cairn's own session: **3.40 MB of transcript holding 72,285
316
+ tokens of context.** Bytes keep accumulating across a `/compact` while the window
317
+ resets, so a byte threshold is loudest immediately *after* a compaction, when there
318
+ is least reason to speak. Bytes survive now only as a fallback for when no usage
319
+ record is reachable, and when that happens the line says so instead of dressing a
320
+ file size up as a token count.
321
+
322
+ Deliberately not built: no percentage (the context-window size is not observable
323
+ from a hook, so the denominator would be invented — the absolute count is reported
324
+ instead), no full transcript walk (the tail only; a full walk in this hot path once
325
+ froze every terminal in the cockpit for 4.3 seconds), no counting subagent spend as
326
+ main-thread context, no repeating the prompt when nothing changed, and no
327
+ auto-clearing, auto-compacting, or filling the field in on your behalf. Same shape
328
+ as completed-phase detection: detect, surface, confirm with the user, never apply.
282
329
 
283
330
  ---
284
331