kadence 0.6.0 → 0.8.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 +183 -11
- package/README.md +30 -26
- package/dist/chunks/{board-5SQP5RX6.js → board-2HUYLTND.js} +1 -1
- package/dist/chunks/chunk-E7WLBKNZ.js +286 -0
- package/dist/chunks/chunk-IP426V3B.js +16 -0
- package/dist/chunks/{ui-OTWFK76P.js → ui-PATAOGVA.js} +2 -2
- package/dist/cli.js +139 -129
- package/package.json +1 -1
- package/dist/chunks/chunk-CR5YON2J.js +0 -10
- package/dist/chunks/chunk-J7QEHKDW.js +0 -248
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,178 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.8.0] — 2026-09-30
|
|
6
|
+
|
|
7
|
+
**The journal is searched before the agent starts guessing.** Agents told to
|
|
8
|
+
use `kadence search` did not: in natural runs on this repository 1 in 10
|
|
9
|
+
reached for it, and 0 in 10 after the instruction files said "before grep".
|
|
10
|
+
Every one opened with grep over the whole tree. So `kadence init` now installs
|
|
11
|
+
a UserPromptSubmit hook that searches the journal for each prompt and puts up
|
|
12
|
+
to three records next to it — by default, next to the `prime` hook.
|
|
13
|
+
|
|
14
|
+
### ⚠️ `init` now writes `.claude/settings.json`
|
|
15
|
+
|
|
16
|
+
It used to only with `--hooks`. It now installs both hooks unless you pass
|
|
17
|
+
`--no-hooks`, creates the file when there is none, keeps every hook that was
|
|
18
|
+
already there, says what it added, and never rewrites a file it cannot parse.
|
|
19
|
+
`--hooks` is still accepted.
|
|
20
|
+
|
|
21
|
+
Measured on the same ten questions, same prompt, Sonnet agents:
|
|
22
|
+
|
|
23
|
+
| | without the hook | with it |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Used the journal | 1 / 10 | 9 / 10 (6 as the first step) |
|
|
26
|
+
| Right answer | 9 / 10 | 10 / 10 |
|
|
27
|
+
| Context added, median | ~10.9k tokens | ~7.9k tokens |
|
|
28
|
+
| Time, median | 44 s | 25 s |
|
|
29
|
+
| Answered from files a clone does not have | 1 | 0 |
|
|
30
|
+
|
|
31
|
+
One repository, ten questions, one model. The hook's output was placed in the
|
|
32
|
+
prompt by hand, because subagents do not fire hooks, so this measures what the
|
|
33
|
+
records do once they arrive, not the hook firing in a live session. A signal,
|
|
34
|
+
not a benchmark.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- `kadence hook prompt` — run by the hook, not by hand. Reads the
|
|
39
|
+
UserPromptSubmit payload on stdin and prints up to three records (1 KB at
|
|
40
|
+
most), or nothing. A passage is quoted only when its record holds the whole
|
|
41
|
+
question; a note is given whole, since there is no command to open one.
|
|
42
|
+
Always exits 0: exit 2 from this hook erases the prompt.
|
|
43
|
+
- A record is shown once per session: what a session has seen is kept in the
|
|
44
|
+
system temp directory, keyed by session and repository — never in
|
|
45
|
+
`.kadence/`. The lines are offered on a condition ("if this is about why or
|
|
46
|
+
how something was decided"), not as an order. On ten ordinary code tasks
|
|
47
|
+
the hook added ~180 tokens and sent no agent into the journal; same answers,
|
|
48
|
+
same time.
|
|
49
|
+
- `init` installs it next to the SessionStart hook. The command is
|
|
50
|
+
silent where kadence is missing and swallows an older kadence's exit 2, so a
|
|
51
|
+
teammate who has not upgraded does not lose every prompt they type.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- **`task list --search` runs on the search engine.** It was a substring over
|
|
56
|
+
title, description and comments — a second idea of what "matches" means.
|
|
57
|
+
Now it matches words the way `kadence search` does, reads acceptance
|
|
58
|
+
criteria too, returns every matching task rather than the top five, and
|
|
59
|
+
lists the most relevant first unless `--sort` is given. A fragment no longer
|
|
60
|
+
matches: `--search coo` does not find `cookie`. The flag and the `--json`
|
|
61
|
+
fields are unchanged. The TUI `/` filter stays a substring, since it filters
|
|
62
|
+
as a person types.
|
|
63
|
+
- The instruction section and `.kadence/README.md` list the ways to look
|
|
64
|
+
something up cheapest first, with what each costs in tokens — from the
|
|
65
|
+
prompt hook's ~90 to `board --json`'s ~51,000, with grep at ~11,000.
|
|
66
|
+
- `prime` names `kadence search` first under "Go deeper", with when to use it.
|
|
67
|
+
- The instruction section in `AGENTS.md` / `CLAUDE.md` and `.kadence/README.md`
|
|
68
|
+
say when to search — before grep or a list. On their own these changed
|
|
69
|
+
nothing measurable; they stay because they cost one line.
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- `search` missed the last word of every sentence. A full stop stayed inside
|
|
74
|
+
the token, so "release steps." was indexed as `steps.` and a search for
|
|
75
|
+
"steps" never found it. Golden-set recall@3 0.64 → 0.68.
|
|
76
|
+
|
|
77
|
+
## [0.7.0] — 2026-09-25
|
|
78
|
+
|
|
79
|
+
**One question over everything written down — and three fixes that had to come
|
|
80
|
+
first.** `kadence search` answers "what do we know about X" across tasks,
|
|
81
|
+
decisions, notes and documents at once. Getting there meant admitting that the
|
|
82
|
+
commands an agent already calls were returning answers it could not use: one
|
|
83
|
+
that could be forged by a note, one that read the whole journal twice on every
|
|
84
|
+
call, and one that returned four thousand tasks into a window that truncates at
|
|
85
|
+
twenty-five thousand tokens.
|
|
86
|
+
|
|
87
|
+
### ⚠️ Upgrading — three defaults changed
|
|
88
|
+
|
|
89
|
+
Nothing was renamed or removed from `kadence schema --json`, so `kadence/v1`
|
|
90
|
+
stands. What a caller gets **by default** changed in three places, and a script
|
|
91
|
+
that assumed otherwise needs one flag:
|
|
92
|
+
|
|
93
|
+
| Was | Is | To get the old answer |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `task list --json` carried `history` | it does not | `--fields id,label,history` |
|
|
96
|
+
| list commands returned everything | one page of 100 | `--limit 0` |
|
|
97
|
+
| `prime --json` carried full note text | capped at 2000 characters | `kadence note list --json` |
|
|
98
|
+
|
|
99
|
+
`history` was never promised there — the schema has always placed it in
|
|
100
|
+
`task show` — but it was emitted, and Hyrum's Law says somebody depended on it.
|
|
101
|
+
It is 61% of that response at 4000 tasks, which put the command past the point
|
|
102
|
+
where an agent's tool output is silently cut in half.
|
|
103
|
+
|
|
104
|
+
### Added — `kadence search`
|
|
105
|
+
|
|
106
|
+
- **One query, every kind of record.** Tasks with their descriptions,
|
|
107
|
+
acceptance criteria and comments; decisions with their reason and the
|
|
108
|
+
alternative they rejected; notes; documents cut at their headings. Most of
|
|
109
|
+
that was unreachable by any command before this: `task list --search` covered
|
|
110
|
+
24% of the journal's prose and only tasks.
|
|
111
|
+
- **Lexical, not semantic, and measured rather than assumed.** BM25,
|
|
112
|
+
hand-rolled, no dependency, over the folded projection — so labels exist
|
|
113
|
+
(I7), a superseded decision does not answer as though it were current, and
|
|
114
|
+
search cannot disagree with `task show`. An embedding model is 200 MB and
|
|
115
|
+
seconds of cold start against a 200 ms budget and a promise to work offline;
|
|
116
|
+
on a vocabulary of `ULID`, `KAD-N` and `FlowEvent` it is also the weaker
|
|
117
|
+
method. 26 ms a query over 829 units; 158 ms end to end (DEC-26).
|
|
118
|
+
- **A hit is something you can cite.** The ULID, never the derived label; the
|
|
119
|
+
lines a document section came from; and a quoted span whose offsets land on
|
|
120
|
+
the quoted text, so an agent quotes the journal instead of paraphrasing it.
|
|
121
|
+
- **`coverage` — how much of the question a record actually holds**, 0 to 1,
|
|
122
|
+
weighted by how rare each word is. Where the first hit is right this is 1.00
|
|
123
|
+
at the median; where it is wrong, 0.62. Below 0.7 the human output says the
|
|
124
|
+
passage answers part of the question. The obvious signal — the gap to the
|
|
125
|
+
second hit — was measured and does not work: 0.10 against 0.08 (DEC-30).
|
|
126
|
+
- **An empty answer, said plainly.** Below the coverage floor the result is
|
|
127
|
+
nothing, and the message says the journal has no answer. A model handed
|
|
128
|
+
passages that merely look relevant fabricates more than one handed none, so
|
|
129
|
+
this is a feature and not a cop-out. Nine of ten questions about things this
|
|
130
|
+
journal has never discussed get silence.
|
|
131
|
+
- **Quality is held by a test, not by hope.** `test/search-relevance.test.ts`
|
|
132
|
+
runs 25 real questions against the repository's own journal and fails below
|
|
133
|
+
recall@3 of 0.64. Three ranking ideas were measured this release and two were
|
|
134
|
+
removed for making it worse (DEC-27, DEC-28).
|
|
135
|
+
|
|
136
|
+
### Fixed — `prime` could be forged, and repainted your terminal
|
|
137
|
+
|
|
138
|
+
- **A note carrying newlines rendered as sections of its own**, and the
|
|
139
|
+
cheapest section to forge is the `Go deeper:` block `prime` ends with. The
|
|
140
|
+
length was capped; the shape was not. An escape sequence went further and
|
|
141
|
+
cleared the screen — `prime` runs from the `SessionStart` hook without being
|
|
142
|
+
asked.
|
|
143
|
+
- **`prime --json` was unbounded.** One 200 KB note made the session preamble
|
|
144
|
+
200,728 bytes. Free text is now capped at 2000 characters with `bytes`
|
|
145
|
+
alongside, the signal `documentation` already gave (DEC-21).
|
|
146
|
+
|
|
147
|
+
### Fixed — a warm command read the whole journal anyway
|
|
148
|
+
|
|
149
|
+
- **`loadState` called `readAll` on every command**, purely to count corrupted
|
|
150
|
+
and unknown events for a warning, after the snapshot had already answered.
|
|
151
|
+
A warm call read all 10,103 files; a cold one read every event twice.
|
|
152
|
+
345 ms to 201 ms end to end at 10k events; 204 ms to 5 ms in process.
|
|
153
|
+
- **The fingerprint counts bytes as well as names**, so a file rewritten in
|
|
154
|
+
place invalidates the cache. That also means `git checkout .kadence/` — the
|
|
155
|
+
remedy the corruption warning itself recommends — finally invalidates the
|
|
156
|
+
cache it needed to, which it never did (DEC-22).
|
|
157
|
+
- Every performance guardrail measured `loadOrBuild`; the CLI calls
|
|
158
|
+
`loadState`. The bug lived in the gap between them. Both are measured now.
|
|
159
|
+
|
|
160
|
+
### Fixed — list commands returned the whole board
|
|
161
|
+
|
|
162
|
+
- **One page of 100, with the real total and the offset beside it.**
|
|
163
|
+
`task list --json` was 1.3M tokens at 4000 tasks against the 25k at which an
|
|
164
|
+
agent's tool output is cut — silently, so the agent answers on a fraction
|
|
165
|
+
while believing it saw everything. Now 50 KB. `--limit 0` returns everything;
|
|
166
|
+
`--offset` walks (DEC-24).
|
|
167
|
+
- 100 rather than 200 because this repository's own tasks run 1100 bytes each,
|
|
168
|
+
where the ceiling is 93.
|
|
169
|
+
|
|
170
|
+
### Changed
|
|
171
|
+
|
|
172
|
+
- Documentation moved into the journal: 65 documents, `DOC-2` through `DOC-66`,
|
|
173
|
+
as `doc.written` events. `docs/` stays on disk as the working draft and links
|
|
174
|
+
are rewritten to `DOC-N` on publication (DEC-25). The npm package is
|
|
175
|
+
unaffected — `.kadence/` is not in `files`.
|
|
176
|
+
|
|
5
177
|
## [0.6.0] — 2026-09-23
|
|
6
178
|
|
|
7
179
|
**Documentation in the journal, and an honest answer when something goes
|
|
@@ -318,7 +490,7 @@ command was renamed, and `--json` responses gain keys rather than losing them.
|
|
|
318
490
|
- **`kadence task claim` / `task release`** — take a task, or give it back.
|
|
319
491
|
`claim` with no argument takes the top of `ready`, which is one step instead
|
|
320
492
|
of two. There is **no lock**, and the message says so: two machines can each
|
|
321
|
-
claim before either pushes. See
|
|
493
|
+
claim before either pushes. See ADR-011.
|
|
322
494
|
- **`kadence note "text" [--task KAD-1]`** and `note list` — something learned
|
|
323
495
|
that was never a choice. Deliberately not a decision: no `--why`, no
|
|
324
496
|
`supersedes`, no number. The help says when to reach for `decision add`
|
|
@@ -354,7 +526,7 @@ command was renamed, and `--json` responses gain keys rather than losing them.
|
|
|
354
526
|
events fold differently depending on where they were written. A detached HEAD
|
|
355
527
|
and an unknown base both fail by name rather than reporting no work.
|
|
356
528
|
The measurement that justified the flag, including what would make it wrong,
|
|
357
|
-
is in
|
|
529
|
+
is in branch-context-2026-09.md.
|
|
358
530
|
- **Acceptance criteria** — `task ac add|check|uncheck|list`. The number is a
|
|
359
531
|
position in the folded list, assigned like `KAD-N` and never stored, so two
|
|
360
532
|
branches can each add a criterion and merge without renumbering. Moving a task
|
|
@@ -395,7 +567,7 @@ command was renamed, and `--json` responses gain keys rather than losing them.
|
|
|
395
567
|
|
|
396
568
|
What the neighbours call reports is, here, a fold over timestamps the journal
|
|
397
569
|
already carries. The reasoning, the sources and the verdict per report are in
|
|
398
|
-
|
|
570
|
+
reports-discovery-2026-09.md.
|
|
399
571
|
Velocity and cycle time stay out of the headline; they are a consequence, served
|
|
400
572
|
to the person who asks.
|
|
401
573
|
|
|
@@ -426,7 +598,7 @@ to the person who asks.
|
|
|
426
598
|
|
|
427
599
|
Each of these was a standing "no". Each is now tried in the shape that survives
|
|
428
600
|
the three constraints, and each has a kill condition written before the code, in
|
|
429
|
-
|
|
601
|
+
feature-adoption-2026-09.md.
|
|
430
602
|
|
|
431
603
|
- **`kadence board export --html`** — the board, the sprint, the burndown,
|
|
432
604
|
milestones and decisions in force, as **one self-contained file**. No script
|
|
@@ -444,7 +616,7 @@ the three constraints, and each has a kill condition written before the code, in
|
|
|
444
616
|
trusts. A marker in the issue body makes a second publish an edit rather than
|
|
445
617
|
a duplicate, and the issue itself says that edits made there are overwritten.
|
|
446
618
|
Nothing is ever read back. See
|
|
447
|
-
|
|
619
|
+
ADR-012, written before the
|
|
448
620
|
code. Every test runs against a recorded `gh`, never the real one.
|
|
449
621
|
- **`kadence task doc add KAD-1 docs/design.md`** — creates the file from a
|
|
450
622
|
four-line template and records the link in one call. It never overwrites: a
|
|
@@ -475,7 +647,7 @@ the three constraints, and each has a kill condition written before the code, in
|
|
|
475
647
|
adding different labels merged without a conflict and one label vanished with
|
|
476
648
|
no warning. Not a merge failure — a fold storing *state* in an event, the
|
|
477
649
|
exact mistake the product exists to avoid. Reasoning in
|
|
478
|
-
|
|
650
|
+
ADR-013.
|
|
479
651
|
- **`labels` in `ready --json`**, the seventh field, and in the guaranteed set.
|
|
480
652
|
|
|
481
653
|
Source for this slice: a tech lead's feedback of 2026-09-10 — drift comes not
|
|
@@ -662,7 +834,7 @@ is additive within `kadence/v1`, which the contract permits at any version.
|
|
|
662
834
|
The journal held what happened. It now holds **why** — and the reasoning cannot
|
|
663
835
|
quietly go stale, because superseding a decision is one event rather than two
|
|
664
836
|
edits somebody has to remember to make. Reasoning in
|
|
665
|
-
|
|
837
|
+
ADR-010.
|
|
666
838
|
|
|
667
839
|
### Added
|
|
668
840
|
|
|
@@ -687,7 +859,7 @@ edits somebody has to remember to make. Reasoning in
|
|
|
687
859
|
explains this task, and that is the only thing recorded. A missing file is a
|
|
688
860
|
warning, not a refusal — it may arrive in a later commit.
|
|
689
861
|
|
|
690
|
-
Measured before building (
|
|
862
|
+
Measured before building (Probe D):
|
|
691
863
|
across five real questions, grep finds the answering document every time and
|
|
692
864
|
buries it among 10–35 candidates. The link saves the sifting, not the search.
|
|
693
865
|
|
|
@@ -758,8 +930,8 @@ published package rather than the source.
|
|
|
758
930
|
The agent contract, made real. `schema: "kadence/v1"` used to be a version
|
|
759
931
|
string that nothing checked; now the contract is published, the failures are
|
|
760
932
|
machine-readable, and the responses can be narrowed to what an agent actually
|
|
761
|
-
reads. Reasoning in
|
|
762
|
-
measurements in
|
|
933
|
+
reads. Reasoning in ADR-009,
|
|
934
|
+
measurements in Probe C.
|
|
763
935
|
|
|
764
936
|
### Added
|
|
765
937
|
|
|
@@ -830,7 +1002,7 @@ asked for.
|
|
|
830
1002
|
- Developer tooling (`.claude/`, `.serena/`) is no longer committed: 381 files
|
|
831
1003
|
and 3.8 MB of it, against 94 files of actual product. What belongs in git and
|
|
832
1004
|
what does not is written down in
|
|
833
|
-
|
|
1005
|
+
ADR-007, and `.gitignore` now
|
|
834
1006
|
also covers `.env`, coverage output and editor leftovers.
|
|
835
1007
|
|
|
836
1008
|
## [0.1.3] — 2026-09-03
|
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ reads the same thing as JSON.
|
|
|
56
56
|
**And it stays one call.** That answer stays under a kilobyte whether the project
|
|
57
57
|
holds ten tasks or a thousand — while the journal behind it grows from 5 KB to
|
|
58
58
|
528 KB. The cost of asking does not grow with the history that makes the answer
|
|
59
|
-
worth having.
|
|
59
|
+
worth having. Measured at 948 bytes in
|
|
60
60
|
0.2; 982 bytes at 0.4, after claims and acceptance criteria joined every record.
|
|
61
61
|
|
|
62
62
|
## Why events and not files
|
|
@@ -102,7 +102,9 @@ merged in every order. Zero conflicts, every author preserved, identical final
|
|
|
102
102
|
state. That is an [integration test](test/integration/merge.test.ts), not a
|
|
103
103
|
claim.
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
The measurement itself is a working paper and is not published (see
|
|
106
|
+
`.gitignore`); the mechanism it measures is proved here by
|
|
107
|
+
`test/integration/merge.test.ts`.
|
|
106
108
|
|
|
107
109
|
---
|
|
108
110
|
|
|
@@ -111,8 +113,8 @@ Full data: [probe-a-results.md](docs/research/probe-a-results.md).
|
|
|
111
113
|
**The first ten minutes, for the person who owns `CLAUDE.md`:**
|
|
112
114
|
|
|
113
115
|
```bash
|
|
114
|
-
kadence init
|
|
115
|
-
#
|
|
116
|
+
kadence init # .kadence/, a short section in AGENTS.md and CLAUDE.md, and two
|
|
117
|
+
# Claude Code hooks: prime at session start, a journal search per prompt
|
|
116
118
|
kadence task add "Fix login" --type bug --priority high
|
|
117
119
|
kadence decision add "Keep sessions in Redis" \
|
|
118
120
|
--why "Revocation must be instant" --rejected "JWT: cannot revoke before expiry"
|
|
@@ -187,7 +189,7 @@ kadence task list --branch
|
|
|
187
189
|
|
|
188
190
|
Nothing is stored for that: which tasks belong to a branch lives in git's
|
|
189
191
|
history and is read when you ask. It narrows the answer between three and
|
|
190
|
-
twenty times,
|
|
192
|
+
twenty times, measured on real board
|
|
191
193
|
sizes.
|
|
192
194
|
|
|
193
195
|
### Also in the box
|
|
@@ -198,8 +200,8 @@ columns, reports folded from the same journal (`report flow`, `cfd`,
|
|
|
198
200
|
`attention`; burndown, velocity and workload are in the repository and not yet
|
|
199
201
|
on npm), a self-contained HTML or Markdown export, `compact` for long journals,
|
|
200
202
|
and shell completion. None of it is required, and none of it is the point —
|
|
201
|
-
it is what the journal happens to know.
|
|
202
|
-
|
|
203
|
+
it is what the journal happens to know. `--help` on each command is the
|
|
204
|
+
reference, and `kadence doc list` is what the journal knows about itself.
|
|
203
205
|
|
|
204
206
|
### Removing kadence
|
|
205
207
|
|
|
@@ -209,7 +211,7 @@ Everything `init` touched, so you can undo it by hand:
|
|
|
209
211
|
|---|---|
|
|
210
212
|
| The journal | `.kadence/` — yours to keep or delete; kadence never deletes it |
|
|
211
213
|
| The agent section | between `<!-- kadence:begin -->` and `<!-- kadence:end -->` in `AGENTS.md` and `CLAUDE.md` |
|
|
212
|
-
| The
|
|
214
|
+
| The hooks (unless `--no-hooks`) | the `SessionStart` entry that runs `kadence prime` and the `UserPromptSubmit` entry that runs `kadence hook prompt`, in `.claude/settings.json` |
|
|
213
215
|
| The cache entry | the `.kadence/state.json` line in `.gitignore` |
|
|
214
216
|
|
|
215
217
|
Then `npm uninstall -g kadence`. Nothing lives outside the repository and your
|
|
@@ -230,9 +232,12 @@ kadence ready --json # seven fields per task, not the whole record
|
|
|
230
232
|
```
|
|
231
233
|
|
|
232
234
|
`prime` is held to forty lines and three kilobytes by a test, because it is paid
|
|
233
|
-
for on every turn that follows. `kadence init
|
|
234
|
-
`
|
|
235
|
-
|
|
235
|
+
for on every turn that follows. `kadence init` adds it as a `SessionStart` hook,
|
|
236
|
+
and adds a `UserPromptSubmit` hook that searches the journal for each prompt
|
|
237
|
+
and puts up to three records next to it. Both are on by default because agents
|
|
238
|
+
do not reach for search on their own (1 in 10 measured); `--no-hooks` leaves
|
|
239
|
+
`.claude/settings.json` alone. The journal is searched in the words it is
|
|
240
|
+
written in: a prompt in another language finds nothing.
|
|
236
241
|
|
|
237
242
|
```bash
|
|
238
243
|
kadence board --json
|
|
@@ -257,7 +262,7 @@ documentation can tell an agent what yours are.
|
|
|
257
262
|
|
|
258
263
|
There is no MCP wrapper, and one gets built only as an **optional package**, when
|
|
259
264
|
someone who cannot run a CLI asks for it: it costs about 700 tokens a session
|
|
260
|
-
over the CLI path —
|
|
265
|
+
over the CLI path — we measured it, and it
|
|
261
266
|
is not the saving the industry benchmarks suggest — it would be a second way to
|
|
262
267
|
say the same thing, and it would not work for agents that have no MCP client at
|
|
263
268
|
all.
|
|
@@ -319,8 +324,8 @@ either moves both or changes nothing. A typo does not leave half a board.
|
|
|
319
324
|
|
|
320
325
|
| | |
|
|
321
326
|
|---|---|
|
|
322
|
-
| Install |
|
|
323
|
-
| Startup |
|
|
327
|
+
| Install | 114 KB packed — 344 KB of kadence, plus 1.8 MB of blessed |
|
|
328
|
+
| Startup | 70 ms (`--version`, 0.8.0, one laptop) |
|
|
324
329
|
| 10,000 events | 21 ms cold with a compacted archive, 12 ms warm — 199 ms cold if every event is still a separate file |
|
|
325
330
|
| Journal on disk | under 5 MB |
|
|
326
331
|
| One task, as an agent reads it | 982 bytes, or 304 with `--summary` — the same however long the task has been worked on |
|
|
@@ -334,24 +339,20 @@ true.
|
|
|
334
339
|
|
|
335
340
|
**Verified.** The merge thesis, on real git branches. Performance and size, by
|
|
336
341
|
tests that fail if they regress. That the conflict problem exists in the wild —
|
|
337
|
-
measured, not assumed.
|
|
342
|
+
measured, not assumed. 1,188 tests in the repository today, including an
|
|
338
343
|
end-to-end run through the installed binary.
|
|
339
344
|
|
|
340
345
|
**Not verified.** That teams and their AI agents actually lose enough context to want
|
|
341
346
|
this. The bet rests on reasoning and on the industry naming the problem out
|
|
342
347
|
loud — not on our own users. That research, Probe B, is
|
|
343
|
-
|
|
344
|
-
2026-09-
|
|
345
|
-
|
|
346
|
-
and
|
|
348
|
+
designed and not yet run: as of
|
|
349
|
+
2026-09-30, zero conversations and no external users. What happens next, and
|
|
350
|
+
on which dates, is recorded in this repository's own journal — `kadence
|
|
351
|
+
decision list` and `kadence note list`.
|
|
347
352
|
|
|
348
353
|
**Not built, on purpose.** An MCP package — only if someone who cannot run a CLI
|
|
349
354
|
asks for it, not as an inevitability.
|
|
350
355
|
|
|
351
|
-
**In the repository, not yet released.** `report burndown`, `report velocity`,
|
|
352
|
-
`report workload`, `report --list` and `report <name> --html`. `npm install`
|
|
353
|
-
gives you 0.4.1 without them.
|
|
354
|
-
|
|
355
356
|
`kadence context <task>` was dropped: we measured what `task show --json` already
|
|
356
357
|
returns and it is the whole history of one piece of work, under a kilobyte,
|
|
357
358
|
constant.
|
|
@@ -382,15 +383,18 @@ branches writing at once produce two different files, and git merges them
|
|
|
382
383
|
without a conflict by construction.
|
|
383
384
|
|
|
384
385
|
Design decisions, each recording what was measured and what would make us
|
|
385
|
-
revisit it
|
|
386
|
+
revisit it, are in the journal that ships with this repository — `kadence
|
|
387
|
+
decision list`, or `kadence decision show DEC-3` for one in full. The longer
|
|
388
|
+
write-ups behind them are working papers and are kept out of git on purpose;
|
|
389
|
+
the decision, its reason and the alternatives that lost are in the events.
|
|
386
390
|
|
|
387
391
|
## Contributing
|
|
388
392
|
|
|
389
393
|
```bash
|
|
390
394
|
npm install
|
|
391
|
-
npm test #
|
|
395
|
+
npm test # 1,188 tests; builds dist/cli.js first
|
|
392
396
|
npm run typecheck
|
|
393
|
-
npm run build #
|
|
397
|
+
npm run build # dist/cli.js 135 KB, blessed kept external (82 KB at 0.4.1)
|
|
394
398
|
```
|
|
395
399
|
|
|
396
400
|
`CLAUDE.md` documents the invariants, the boundaries, and the decisions that
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
2
|
+
import{s as G}from"./chunk-IP426V3B.js";import S from"blessed";var c={border:"gray",borderFocus:"cyan",headerFg:"white",headerBg:"blue",selectedFg:"black",selectedBg:"cyan",dim:"gray",hint:"gray",warn:"yellow",danger:"red"},he={backlog:"gray",todo:"white",in_progress:"blue",doing:"blue",blocked:"red",in_review:"magenta",review:"magenta",done:"green",shipped:"green"};function ne(n){return he[n]??"white"}var pe={urgent:"\u203C",high:"\u2191",normal:" ",low:"\u2193"},me={urgent:"red",high:"yellow",normal:"white",low:"gray"},ye={bug:"\u2716",story:"\u25C6",epic:"\u2B22",task:"\xB7"};function k(n,s){return`{${s}-fg}${n}{/}`}function W(n,s){let d=k(pe[n.priority],me[n.priority]),p=k(ye[n.type]??"\xB7","gray"),h=k(n.label,"cyan"),g=[];n.blockedBy.length>0&&g.push(k("\u2298","red")),n.contestedBy.length>0?g.push(k("\u2691","magenta")):n.claimedBy!==null&&g.push(k("\u2713","green"));let E=n.criteria.filter(O=>!O.checked).length;if(E>0?g.push(k(`${n.criteria.length-E}/${n.criteria.length}`,"yellow")):n.criteria.length>0&&g.push(k("\u2611","green")),n.comments.length>0&&g.push(k("\u{1F4AC}","gray")),n.due!==null){let O=n.due<new Date().toISOString().slice(0,10);g.push(k(O?"\u23F0":"\u{1F4C5}",O?"red":"gray"))}let C=[n.assignee!==null?k(`@${n.assignee.split("@")[0]}`,"gray"):"",n.estimate!==null?k(String(n.estimate),"yellow"):"",g.join("")].filter(O=>O.length>0).join(" "),m=`${Y(d)}${Y(p)} ${Y(h)} `,b=C.length>0?` ${Y(C)}`:"",T=Math.max(4,s-m.length-b.length),F=[...n.title],q=F.length>T?`${F.slice(0,T-1).join("")}\u2026`:n.title;return`${d}${p} ${h} ${q}${C.length>0?` ${C}`:""}`}function z(n,s){return s?`{cyan-bg}{black-fg}${Y(n)}{/}`:` ${n}`}function J(n,s,d,p=12){let h=`${n.padEnd(p)} ${s}`;return d?`{cyan-bg}{black-fg}\u25B8 ${h}{/}`:` ${h}`}function Y(n){return n.replace(/\{[^}]*\}/g,"")}var re=["\u2190\u2192\u2191\u2193 move","enter details","[ ] shift","m status","a assign","c comment","e edit","n new","s sprint","/ filter","R ready","b branch","M milestone","C claim","? help","q quit (Ctrl-C forces)"].join(" ");function se(n){let s=[],d=!1;function p(){d=!0,setImmediate(()=>{d=!1})}return{dispatch(h){if(d)return;let g=s[s.length-1];g!==void 0?g(h):n(h)},push(h){s.push(h),p();let g=!1;return()=>{if(g)return;g=!0;let E=s.lastIndexOf(h);E!==-1&&s.splice(E,1),p()}},isDialogOpen:()=>s.length>0,depth:()=>s.length}}function oe(n){if(n.ch==="")return!1;let s=n.ch.charCodeAt(0);return s<32||s===127}var be=["up","down","pageup","pagedown","home","end"],ie=["escape","q"];function Q(n){return be.includes(n.name)}function le(n){return ie.includes(n.name)||ie.includes(n.ch)}function _(n,s,d){return d===0?0:(n+s+d)%d}var ae="cancelled",we="done";function ve(n){let s=[`${n.open} open`,`${n.ready} ready`,`${n.decisions} ${n.decisions===1?"decision":"decisions"} in force`,...n.points===null?[]:[`${n.points} points`]];return`kadence ${n.sprint===null?"":`${n.sprint} `}${s.join(" \xB7 ")}${n.filterNote}`}function Ie(n){let s=S.screen({smartCSR:!0,title:"kadence",fullUnicode:!0,mouse:!0}),{state:d}=n.reload(),p=n.branchEventIds(),h="",g=!1,E=!1,C="",m=[],b=0,T=se(t=>ge(t));function F(t=0){try{s.destroy()}catch{}process.exit(t)}process.on("SIGINT",()=>F(0)),process.on("SIGTERM",()=>F(0)),s.program.on("keypress",(t,r)=>{let i={ch:t??"",name:r?.name??""};(i.name==="C-c"||i.ch==="")&&F(0),!(oe(i)&&i.name!=="enter"&&i.name!=="escape")&&T.dispatch(i)});let q=S.box({parent:s,top:0,height:1,width:"100%",tags:!0,style:{fg:c.headerFg,bg:c.headerBg}}),O=S.box({parent:s,bottom:0,height:1,width:"100%",tags:!0,content:` ${re}`,style:{fg:c.hint}}),V=S.box({parent:s,bottom:1,height:1,width:"100%",tags:!0,style:{fg:c.warn}});function w(t,r=c.warn){V.setContent(` ${t}`),V.style.fg=r,s.render()}function A(){let t=d.statuses.filter(i=>i!==ae),r=d.orphanStatuses.filter(i=>i!==ae);return[...t,...r]}function de(t){let r=h.toLowerCase(),i=g?new Set(G(d.tasks,{viewer:n.actor,statuses:d.statuses,started:d.started}).map(a=>a.id)):null,e=E&&!("reason"in p)?p:null,o=e===null?null:a=>e.ids.has(a.id)||a.history.some(l=>e.ids.has(l.id)),u=C===""?null:d.milestones.find(a=>a.label===C)?.id??null;return d.tasks.filter(a=>a.status===t&&(i===null||i.has(a.id))&&(o===null||o(a))&&(u===null||a.milestone===u)&&(r===""||a.title.toLowerCase().includes(r)||(a.assignee??"").toLowerCase().includes(r)||a.labels.some(l=>l.toLowerCase().includes(r))))}function X(){for(let i of m)i.box.destroy();m=[];let t=A(),r=Math.max(Math.floor(100/Math.max(t.length,1)),12);t.forEach((i,e)=>{let o=S.box({parent:s,top:1,left:`${e*r}%`,width:`${r}%`,bottom:2,label:` ${i} `,border:{type:"line"},style:{border:{fg:c.border},label:{fg:ne(i)}}}),u=S.list({parent:o,top:0,left:0,right:0,bottom:0,keys:!1,mouse:!1,interactive:!1,tags:!0,scrollable:!0,style:{selected:{fg:c.selectedFg,bg:c.selectedBg},item:{fg:"white"}}});m.push({status:i,box:o,list:u,tasks:[],cursor:0})})}function y(t=!1){t&&(d=n.reload().state,p=n.branchEventIds()),m.length!==A().length&&X();let r=0,i=0,e=!1;m.forEach((l,N)=>{l.tasks=de(l.status),l.status!==we&&(r+=l.tasks.length,i+=l.tasks.reduce((R,M)=>R+(M.estimate??0),0)),l.tasks.some(R=>R.estimate!==null)&&(e=!0);let U=l.box.width-4;l.cursor=Math.min(l.cursor,Math.max(0,l.tasks.length-1)),l.list.setItems(l.tasks.map((R,M)=>z(W(R,U),N===b&&M===l.cursor)));let L=l.tasks.reduce((R,M)=>R+(M.estimate??0),0);l.box.setLabel(` ${l.status} (${l.tasks.length}${L>0?`, ${L}`:""}) `),l.box.style.border.fg=N===b?c.borderFocus:c.border});let o=d.sprints.find(l=>l.status==="active"),u=(h===""?"":` filter: "${h}"`)+(g?" ready only":"")+(E&&!("reason"in p)?` branch: ${p.name}`:"")+(C===""?"":` milestone: ${C}`),a=G(d.tasks,{viewer:n.actor,statuses:d.statuses,started:d.started}).length;q.setContent(` ${ve({sprint:o===void 0?null:o.name,open:r,ready:a,decisions:d.decisions.filter(l=>l.supersededBy===null).length,points:e?i:null,filterNote:u})}`),d.cycles.length>0&&w(`${d.cycles.length} dependency cycle(s) \u2014 see kadence task list`,c.danger),s.render()}function I(){let t=m[b];return t?.tasks[t.cursor]}function Z(){m.forEach((t,r)=>{let i=t.box.width-4;t.list.setItems(t.tasks.map((e,o)=>z(W(e,i),r===b&&o===t.cursor))),t.box.style.border.fg=r===b?c.borderFocus:c.border}),s.render()}function x(t){t!==null?w(t,c.warn):w(""),y(!0)}function K(t,r,i){let e=T.push(()=>{}),o=S.prompt({parent:s,top:"center",left:"center",width:"60%",height:7,border:{type:"line"},style:{border:{fg:c.borderFocus}},keys:!0,mouse:!0});o.input(t,r,(u,a)=>{o.destroy(),e(),s.render(),typeof a=="string"&&i(a.trim())})}function ue(t){let r=S.box({parent:s,top:"center",left:"center",width:"75%",height:"80%",border:{type:"line"},label:` ${t.label} `,style:{border:{fg:c.borderFocus}},tags:!0,keys:!0,mouse:!0}),i=[{key:"title",label:"title",value:()=>t.title,hint:"Title:"},{key:"description",label:"description",value:()=>(t.description??"\u2014").split(`
|
|
3
3
|
`)[0]??"\u2014",hint:"Description (one line here, e for $EDITOR):"},{key:"status",label:"status",value:()=>t.status,hint:`Status (${A().join(", ")}):`},{key:"type",label:"type",value:()=>t.type,hint:"Type (task, bug, story, epic):"},{key:"priority",label:"priority",value:()=>t.priority,hint:"Priority (low, normal, high, urgent):"},{key:"assignee",label:"assignee",value:()=>t.assignee??"\u2014",hint:'Assignee (or "none"):'},{key:"estimate",label:"estimate",value:()=>t.estimate===null?"\u2014":String(t.estimate),hint:"Estimate in points:"},{key:"due",label:"due",value:()=>t.due??"\u2014",hint:"Due date YYYY-MM-DD (empty clears):"},{key:"labels",label:"labels",value:()=>t.labels.length>0?t.labels.join(", "):"\u2014",hint:"Labels, comma separated:"}],e=()=>[...i.map((v,f)=>({kind:"field",index:f})),...t.criteria.map(v=>({kind:"criterion",n:v.n}))],o=S.list({parent:r,top:0,left:1,right:1,height:i.length+t.criteria.length,keys:!1,mouse:!1,interactive:!1,tags:!0,style:{selected:{fg:c.selectedFg,bg:c.selectedBg}}}),u=0,a=S.box({parent:r,top:i.length+t.criteria.length+1,left:1,right:1,bottom:0,tags:!0,scrollable:!0});function l(){o.setItems(e().map((f,B)=>f.kind==="field"?J(i[f.index].label,i[f.index].value(),B===u):J(` ${f.n}.`,`[${t.criteria.find($=>$.n===f.n)?.checked===!0?"x":" "}] ${t.criteria.find($=>$.n===f.n)?.text??""}`,B===u)));let v=[t.blockedBy.length>0?`{red-fg}blocked by ${t.blockedBy.length} task(s){/}`:"",t.parent!==null?"{gray-fg}has a parent{/}":"",t.loggedHours>0?`{gray-fg}logged ${t.loggedHours.toFixed(1)}h{/}`:"","",t.description!==null&&t.description.includes(`
|
|
4
4
|
`)?`{gray-fg}${t.description.split(`
|
|
5
5
|
`).slice(1).join(`
|