@misterhuydo/cairn-mcp 1.33.1 → 1.36.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 +101 -1
- package/dist/cairn-cli.js +63 -60
- package/dist/index.js +68 -68
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ No manual steps. The index lives in `.cairn/index.db` inside your project — li
|
|
|
84
84
|
| `cairn_todos` | Scan codebase for TODO/FIXME/HACK comments, add manual items, resolve and list them |
|
|
85
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` |
|
|
86
86
|
| `cairn_bundle` | Minified source snapshot (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
|
+
| `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. Also takes `context_window`, the one thing cairn cannot measure for itself |
|
|
88
88
|
| `cairn_minify` | Minify a single file on demand (fallback when hooks are not installed) |
|
|
89
89
|
| `cairn_switch` | Switch active project root mid-session (use for maintenance on a sibling service) |
|
|
90
90
|
| `cairn_memo` | Save a preference, decision, or discovery to the project's persistent memory. `action: "reindex"` repairs an index that has lost entries (see below) |
|
|
@@ -389,6 +389,7 @@ and the model id is no help either: a `claude-opus-5[1m]` session writes the bas
|
|
|
389
389
|
| v1.20.0 | fixed 120k tokens | 60% of a 200k window but 12% of a 1M one, so it fired a tenth of the way into a 1M session |
|
|
390
390
|
| v1.31.0 | infer the smallest window that fits the measurement | sound as a lower bound only, so below 196k it assumed 200k — reported **96%** where `/context` said **19%** |
|
|
391
391
|
| v1.32.0 | never guess downward; `CAIRN_CONTEXT_WINDOW` states the truth | nothing could ever set it. `install-hooks` cannot know the window either, so there was no correct value to write — unwritable by construction, and the feature went silently dead |
|
|
392
|
+
| v1.33.0 | report the bare count, let the agent judge | right about *who* decides. But a reader handed a number with no denominator supplies one, and supplies the familiar 200k: an agent at **253,500 of a 1M window** called for a clear, twice, with 74% free |
|
|
392
393
|
|
|
393
394
|
v1.31.0's false-alarm band could never have been tuned away: any firing point for a
|
|
394
395
|
200k window is a point a 1M session also passes through, so no number serves both.
|
|
@@ -400,11 +401,110 @@ rules for acting on it, and never issues the verdict itself. It is the same divi
|
|
|
400
401
|
of labour as the handoff: cairn demands the judgement and carries it, never computes
|
|
401
402
|
it.
|
|
402
403
|
|
|
404
|
+
**Since v1.34.0 the agent also declares the denominator.** Pass `context_window` to
|
|
405
|
+
`cairn_resume` or `cairn_checkpoint` once per project (optionally with
|
|
406
|
+
`context_window_model`), and every reading from then on is scaled:
|
|
407
|
+
|
|
408
|
+
```
|
|
409
|
+
[cairn] Context: 253,500 of 1,000,000 tokens (25%, declared for claude-opus-5[1m]).
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Until you do, the line carries the raw count and says the window is undeclared, which
|
|
413
|
+
is the honest state — cairn still never invents a denominator. The declared window is
|
|
414
|
+
stored beside the handoff in `session.json` and carried forward by checkpoints that do
|
|
415
|
+
not restate it, so the every-turn heartbeat cannot drop it.
|
|
416
|
+
|
|
417
|
+
This is not `CAIRN_CONTEXT_WINDOW` coming back. That died on *who could ever set it*,
|
|
418
|
+
and the answer turned out to be: the one party that can read it off its own system
|
|
419
|
+
prompt. A declaration can still be wrong — carried into a narrower model's session, say
|
|
420
|
+
— but it is wrong *on screen*, next to the model it claims to be for, and a reading over
|
|
421
|
+
100% is called out as an impossible one rather than an emergency. A stated assumption
|
|
422
|
+
gets corrected; the unstated one that replaced it in v1.33.0 could not be.
|
|
423
|
+
|
|
403
424
|
That also removes the rate-limiting. The old block was a *verdict*, so repeating it
|
|
404
425
|
was nagging and it had to be shown once per situation; this is a *measurement*, and a
|
|
405
426
|
budget you are only shown once it is nearly spent cannot inform the decision to start
|
|
406
427
|
something. It rides every prompt.
|
|
407
428
|
|
|
429
|
+
**Since v1.35.0 the line also says which reset to use.** Every reading carries a
|
|
430
|
+
second line naming `/clear` or `/compact` and why:
|
|
431
|
+
|
|
432
|
+
```
|
|
433
|
+
[cairn] Context: 90,000 of 1,000,000 tokens (9%, declared for claude-opus-5[1m]).
|
|
434
|
+
Handoff is STALE, written before the 1 commit(s) since: the retry path is untested…
|
|
435
|
+
→ If you reset: /compact — the handoff predates the 1 commit(s) since, so it no
|
|
436
|
+
longer describes the work in flight.
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Cairn had been computing that recommendation since v1.29.0 and printing none of it:
|
|
440
|
+
`recommendedAction()` decided between the two on every prompt, and the hook built its
|
|
441
|
+
output from the measurement and the protocol alone, so the advice reached the screen
|
|
442
|
+
only if the agent chose to raise it. That routed the whole path through the one
|
|
443
|
+
component with a demonstrated failure record — the same judgement that read 253,500 of
|
|
444
|
+
1M as an emergency, twice.
|
|
445
|
+
|
|
446
|
+
The advice turns on **what is saved, never on how full the window is**. A current
|
|
447
|
+
handoff means the thread survives a hard reset, so `/clear` is the better trade; a
|
|
448
|
+
missing or stale one means something unwritten is still at risk, so `/compact` keeps it
|
|
449
|
+
reachable. That is why it can print at 9% as readily as at 94%, and why the wording is
|
|
450
|
+
strictly conditional. *If* you reset, use this one. It never says to reset — that
|
|
451
|
+
judgement is still the agent's, and still yours to act on, since cairn cannot type
|
|
452
|
+
either command. A fact about your saved state does not become false or urgent by being
|
|
453
|
+
displayed; the verdict it replaced did, which is why that one had to be rationed.
|
|
454
|
+
|
|
455
|
+
**Since v1.36.0 there is exactly one threshold again: the 90% gate.** At 90% of the
|
|
456
|
+
*declared* window, cairn asks the agent for one specific thing:
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
⚠ [cairn] 94% of the declared window (940,000 of 1,000,000 tokens, 60,000 left) and
|
|
460
|
+
nothing has been written down about what this session would lose. Call cairn_checkpoint
|
|
461
|
+
with would_be_lost: the every-turn auto-checkpoint carries that field forward but never
|
|
462
|
+
writes it, so nothing else will. This is not a verdict on whether your next task fits —
|
|
463
|
+
that judgement is still yours.
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
A threshold is defensible now for a reason that did not exist before v1.34.0: **the
|
|
467
|
+
window is declared, not guessed.** The gate fires only when an agent has stated its
|
|
468
|
+
denominator and never otherwise, so a project that has declared nothing gets no trigger
|
|
469
|
+
and no false alarm — by construction, not by tuning. That is the property the fixed
|
|
470
|
+
120k, the inferred-smallest and the unwritable env var could never have had.
|
|
471
|
+
|
|
472
|
+
It also asks for something none of them asked for. It does not say stop, and it does not
|
|
473
|
+
rule on whether the work fits. It demands the one field an automatic save must never
|
|
474
|
+
invent: the Stop hook checkpoints every turn, but `would_be_lost` is deliberately carried
|
|
475
|
+
forward untouched rather than fabricated (`checkpoint.js:68`), which makes it precisely
|
|
476
|
+
the field still missing when the window runs out.
|
|
477
|
+
|
|
478
|
+
90% rather than 95% because the cost is asymmetric — firing early costs about 1k tokens
|
|
479
|
+
for a handoff worth writing anyway, firing late costs the session's whole unwritten
|
|
480
|
+
reasoning — and because usage does not climb smoothly. A single image read or large test
|
|
481
|
+
dump can take 10k in one turn, which is the entire margin 95% leaves on a 200k window.
|
|
482
|
+
|
|
483
|
+
**It also names who picks `/clear` vs `/compact`, and on what basis.** Cairn's own
|
|
484
|
+
recommendation is about *what is saved* — but that is a precondition, not the decision.
|
|
485
|
+
The decision is whether the work ahead needs the context already loaded: a new,
|
|
486
|
+
unrelated phase gains nothing from this conversation, so `/clear` is the better trade,
|
|
487
|
+
while a phase continuing this one would force a re-read of everything, so `/compact` is.
|
|
488
|
+
|
|
489
|
+
Cairn cannot see which of those is coming, and does not try — that is the
|
|
490
|
+
window-inference mistake in a new costume. The *agent* can: it has the incoming
|
|
491
|
+
request, the roadmap cursor, and where the conversation was heading. So the gate demands
|
|
492
|
+
that judgement rather than leaving you a two-branch menu, and the user-facing half
|
|
493
|
+
explains what each command does so you can act on it or overrule it. Same division of
|
|
494
|
+
labour as everywhere else here: cairn measures, the agent judges, you act — because
|
|
495
|
+
cairn cannot type either command.
|
|
496
|
+
|
|
497
|
+
Once the handoff is written, neither option drops anything that was written down, so the
|
|
498
|
+
choice collapses to that single question about what comes next.
|
|
499
|
+
|
|
500
|
+
It needs no rate limit: it self-extinguishes. The moment the handoff is written the
|
|
501
|
+
demand returns null, and it speaks again only if later commits make that answer stale.
|
|
502
|
+
Crossing is remembered in `.cairn/.handoff-gate` and forgotten when usage drops back
|
|
503
|
+
below the gate, so a `/clear` makes the next crossing a genuinely new event. The stored
|
|
504
|
+
crossing also closes a hole that `stale` alone cannot: staleness is counted in *commits*,
|
|
505
|
+
so a long research session that commits nothing would keep a handoff from its opening
|
|
506
|
+
minutes marked current all the way to the top of the window.
|
|
507
|
+
|
|
408
508
|
`CAIRN_CONTEXT_HINT_TOKENS` no longer gates anything, but if you set it, cairn tells
|
|
409
509
|
the agent when you have passed it rather than ignoring you.
|
|
410
510
|
|