kadence:让团队与 AI 智能体共享同一份仓库内上下文
bogutskiandriy/kadence
kadence 是一个把团队任务与 AI 智能体上下文存进代码仓库的工具,通过 `npm install -g kadence` 和 `kadence init` 安装,无需服务器、账号或网络。
kadence
Your team and your AI agents work from the same context — it lives in your repo and remembers what the code cannot.
npm install -g kadence kadence init
No server. No account. No network. Tasks, their whole history and the time they took are files next to your code, and they move with your branches.
The context your code cannot hold
Your code says what exists. git log says when it changed. Neither says
what was tried and abandoned, why a task is blocked, or what the team agreed on
Tuesday.
That gap costs a human a few minutes. It costs an AI agent the entire session: every new one starts from scratch, re-reads the same files and asks the same questions you answered yesterday.
kadence keeps that missing layer as an append-only journal — one file per event, committed with the code:
$ kadence task show KAD-1 --json
{
"schema": "kadence/v1",
"label": "KAD-1",
"title": "Fix login",
"status": "in_review",
"loggedHours": 4.5,
"blockedBy": ["KAD-7"],
"comments": [
{ "at": "2026-09-02T09:14:00Z", "by": "ana",
"text": "Session cookie is fine — the redirect drops it." }
],
"history": [
{ "at": "2026-09-01T10:02:00Z", "by": "ana", "type": "task.created" },
{ "at": "2026-09-01T14:40:00Z", "by": "ana", "type": "task.moved", "to": "in_progress" },
{ "at": "2026-09-02T09:20:00Z", "by": "agent","type": "task.blocked_by_added" }
]
}That is the whole state of a piece of work, in one call, with no server to ask
and no context to rebuild. A human reads it in kadence task show. An AI agent
reads the same thing as JSON.
And it stays one call. That answer stays under a kilobyte whether the project holds ten tasks or a thousand — while the journal behind it grows from 5 KB to 528 KB. The cost of asking does not grow with the history that makes the answer worth having. Measured at 948 bytes in 0.2; 982 bytes at 0.4, after claims and acceptance criteria joined every record.
Why events and not files
Every other tool that keeps work in a repository keeps state: a task file, a row in a database, the current spec. State has three failure modes, and all three are why kadence stores events instead.
It drifts. A spec written on Monday and edited by an agent on Thursday no longer says what actually happened. An event cannot drift — it records that something occurred, not what is currently true.
It conflicts. Two people editing one task on two branches is a merge conflict in every file-based tracker. Here it is not, by construction: the journal is append-only, one file per event.
It forgets. Rewriting a task file destroys the previous version. The journal keeps every step, so «how did we get here» has an answer.
State is still there when you want it — it is folded from the journal on read, which is why the board cannot drift from the journal. No one maintains a column by hand, so no column can be stale in the way a task file can.
What that does not buy you. A journal records what was written to it. If a
piece of work stops being touched, the board stays perfectly accurate and
perfectly uninformative about it — the same way git log is honest about a
branch nobody pushed to. kadence removes the drift between what is shown and
what was recorded. It cannot remove the drift between what was recorded and
what is actually happening; that still takes someone looking.
Why the merge claim holds
We measured it before building on it.
Across 8,396 merge commits in 130 public repositories using file-based
trackers, conflicts in task files hit 15% of repositories — and 89% are
CONFLICT (content), the exact type an append-only journal removes.
Then the other direction: three people editing one task on three branches, merged in every order. Zero conflicts, every author preserved, identical final state. That is an integration test, not a claim.
The measurement itself is a working paper and is not published (see
.gitignore); the mechanism it measures is proved here by
test/integration/merge.test.ts.
And for agents running side by side, which is where neighbouring tools lose
work: eight processes writing 200 tasks into one working tree at once, and
three worktrees writing 240 more and merged in one octopus merge — no
conflict, no task lost; two worktrees claiming the same task come out of the
merge with one claim and the other reported as contested, not silently
dropped. Every agent writes its own file, so there is nothing to overwrite.
The proof is test/parallel-agents.test.ts —
it runs the real binary in separate processes, and fails (182 of 200) when the
store is made to share file names.
In practice
The first ten minutes, for the person who owns CLAUDE.md:
kadence init # .kadence/, a short section in AGENTS.md and CLAUDE.md, and two # Claude Code hooks: prime at session start, a journal search per prompt kadence task add "Fix login" --type bug --priority high kadence decision add "Keep sessions in Redis" \ --why "Revocation must be instant" --rejected "JWT: cannot revoke before expiry"
Run in a terminal, kadence init is a guided setup: Coda says what it found
— the agents in use, an ADR folder — asks one question with a recommended
answer, offers the ADRs as decisions, and shows what a teammate's agent will
see when someone proposes what you ruled out. Nothing is written until you say
so, and running it again is a checkup. An agent, a script or any flag gets no
question at all, and the output tells an agent what to do next.
On Codex, Cursor or Copilot, kadence init --hooks-for codex,cursor,copilot
adds their hooks too; init writes them unasked only where the agent's own
directory is already in the repository.
Open a new agent session. The hook runs kadence prime, and the agent starts
knowing what is open, what is ready and DEC-1 with its reason — ask it how
sessions should be stored and it answers from the journal, not from a guess.
git add .kadence AGENTS.md CLAUDE.md .claude/settings.json .gitignore
git commit -m "Keep the team's work next to the code"kadence never commits for you. Once that commit is pushed, the journal is the team's, not yours.
If the repository is public, add the topic kadence-journal to it
(the gear next to About on GitHub, or
gh repo edit --add-topic kadence-journal). kadence sends nothing anywhere,
so a topic you choose to show is the only way anyone, us included, can tell
it is in use.
Adding a teammate
- They install it:
npm install -g kadence(Node 20 or newer). Nothing is configured per person. - They pull. Their agent reads the same section in
CLAUDE.mdorAGENTS.mdand, through the hook, runskadence primein its first session. On a machine where kadence is not installed yet, the hook prints one line asking for the install instead of failing. - One identity per person. Authorship is
git config user.email. The same person on two machines with two addresses reads as two people — set the same address everywhere. - Agents say so. Put
KADENCE_SOURCE=agentin the agent's environment; its writes then carry[agent]next to the same email, so a person and their agent stay distinguishable.
What you should see afterwards: kadence task show KAD-1 lists their comment,
note or move with their address. That second author is the moment the journal
starts doing its job.
When several people — or several agents — work the same board:
kadence ready # open, unblocked, nobody else's kadence task claim # take the top of that list, in one step kadence note "Redirect drops the cookie, not the session" --task KAD-1 kadence task release KAD-1
There is no lock, and the message says so. Two machines can each claim before
either pushes; the merge keeps both claims and the task reads contested with
both names. Refusing the second one would make the owner depend on which branch
merged first, and that is the property the whole design rests on.
The board, when you want to look at it:
$ kadence ui
kadence 6 open · 2 ready · 1 decision in force
+- backlog (2) -------++- in_progress (1) --++- in_review (1) ----++- done (3) ---------+
| ^# KAD-1 Auth epic || . KAD-4 Tokens @dev||!! KAD-7 Crash [] || v KAD-2 Export |
| * KAD-3 Login form || || || v KAD-5 Docs |
+---------------------++--------------------++--------------------++--------------------+
arrows move enter details m status a assign e edit s sprint R ready b branch q quit
Keyboard, mouse, drag between columns, every field editable in place. It calls the same commands the CLI does, so the two can never disagree.
And what the branch you are on is actually about:
kadence task list --branch
Nothing is stored for that: which tasks belong to a branch lives in git's history and is read when you ask. It narrows the answer between three and twenty times, measured on real board sizes.
Also in the box
Sprints (sprint create/close, with points and hours derived from moves),
milestones, acceptance criteria and a definition of done, templates, custom
columns, reports folded from the same journal (report flow, cfd,
attention; burndown, velocity and workload are in the repository and not yet
on npm), a self-contained HTML or Markdown export, compact for long journals,
doctor to rebuild the cache and check every event reads, and shell
completion. None of it is required, and none of it is the point —
it is what the journal happens to know. --help on each command is the
reference, and kadence doc list is what the journal knows about itself.
Removing kadence
Everything init touched, so you can undo it by hand:
| What | Where |
|---|---|
| The journal | .kadence/ — yours to keep or delete; kadence never deletes it |
| The agent section | between <!-- kadence:begin --> and <!-- kadence:end --> in AGENTS.md and CLAUDE.md |
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 |
| The cache entry | the .kadence/state.json line in .gitignore |
Then npm uninstall -g kadence. Nothing lives outside the repository and your
global node_modules.
For agents
Files first. Every command speaks --json, every response carries
schema: "kadence/v1", stdout is JSON and nothing else, warnings go to stderr.
Start a session with one command:
kadence prime # active sprint, your work, what is ready, decisions in force, recent notes kadence ready --json # seven fields per task, not the whole record
prime is held to forty lines and three kilobytes by a test, because it is paid
for on every turn that follows. kadence init adds it as a SessionStart hook,
and adds a UserPromptSubmit hook that searches the journal for each prompt
and puts up to three records next to it. Both are on by default because agents
do not reach for search on their own (1 in 10 measured); --no-hooks leaves
.claude/settings.json alone. The journal is searched in the words it is
written in: a prompt in another language finds nothing.
kadence board --json
kadence task show KAD-1 --json # full history and comments
KADENCE_SOURCE=agent kadence task move KAD-1 in_progressinit writes that guide into both AGENTS.md and CLAUDE.md — the first is the
cross-tool convention, the second is what Claude Code actually reads. Whatever a
human wrote in either is left alone. No MCP server to run, no token to issue, no
network call to make.
The contract is not a promise you have to take on trust:
kadence schema --json # every command, every field, every error codeA failure carries error.code and, where the valid set is knowable, allowed —
which matters most for statuses, because they are configured per project and no
documentation can tell an agent what yours are.
There is no MCP wrapper, and one gets built only as an optional package, when someone who cannot run a CLI asks for it: it costs about 700 tokens a session over the CLI path — we measured it, and it is not the saving the industry benchmarks suggest — it would be a second way to say the same thing, and it would not work for agents that have no MCP client at all.
Ask for only what you need — a board of a thousand tasks is 855 KB in full
with --history, 275 KB by default, which leaves out the history and comments
that grow with the work, and 104 KB with the three fields an agent actually
reads:
kadence board --json kadence board --json --fields label,status,assignee
And the part the code cannot hold — why:
kadence decision add "Use ULIDs" --why "Clocks disagree between machines" \ --rejected "Auto-increment: collides across branches" --task KAD-1
When a decision stops being true you supersede it rather than edit it, and that
is one event — the backward link is derived, so the two directions cannot
fall out of step. In a file-based tool it is two edits, and teams reliably make
one; that is how a reversed decision keeps looking authoritative.
decision list returns what is still in force, --all adds the history, and
task show --json carries the decisions made about that task.
Something learned that was never a choice is a note, not a decision — no --why,
no number, and prime shows the latest:
kadence note "The staging clock runs 40 s behind" --task KAD-1Documentation lives in the journal too. How something works now, revised as
it changes — an entity, DOC-N, not a filename an agent has to guess:
kadence doc add "How auth works" --file notes/auth.md --task KAD-1
kadence doc show DOC-1 --jsonA revision names the revisions it was written on top of, so two people editing
the same version leave a conflict that is reported and settled by writing text,
never a silent overwrite. Agents are handed it without searching: task show
carries documentation[] and prime names the documentation of the work you
hold — both without bodies, so the body arrives only when asked for.
A markdown file that already exists is still linked, not swallowed:
kadence task doc add KAD-1 docs/design.md records the link, which is the part
git cannot express.
Bulk works everywhere and is all or nothing: kadence task move KAD-1,KAD-2 done
either moves both or changes nothing. A typo does not leave half a board.
What it costs you
| Install | 135 KB packed — 405 KB of kadence, plus 1.8 MB of blessed |
| Startup | 78 ms (--version, 0.9.0, one laptop) |
| 10,000 events | 21 ms cold with a compacted archive, 12 ms warm — 199 ms cold if every event is still a separate file |
| Journal on disk | under 5 MB |
| One task, as an agent reads it | 982 bytes, or 304 with --summary — the same however long the task has been worked on |
These are tests. They fail the build on regression, which is why they are still true.
Honest status
Verified. The merge thesis, on real git branches. Performance and size, by tests that fail if they regress. That the conflict problem exists in the wild — measured, not assumed. 1,477 tests in the repository today, including an end-to-end run through the installed binary.
Not verified. That teams and their AI agents actually lose enough context to want
this. The bet rests on reasoning and on the industry naming the problem out
loud — not on our own users. That research, Probe B, is
designed and not yet run: as of
2026-09-30, zero conversations and no external users. What happens next, and
on which dates, is recorded in this repository's own journal — kadence decision list and kadence note list.
Not built, on purpose. An MCP package — only if someone who cannot run a CLI asks for it, not as an inevitability.
kadence context <task> was dropped: we measured what task show --json already
returns and it is the whole history of one piece of work, under a kilobyte,
constant.
The only thing left to add was a different format, and nobody has asked for one.
Known limits. Conflicts are real but rare: roughly one merge in two hundred.
Terminal interaction is covered by manual testing; only the key router is
unit-tested. Deleting several tasks by KAD-N in one loop removes the wrong
ones, because labels are derived and renumber as earlier tasks go — delete by
ULID, or one at a time. There is no task ac remove, so a board-wide Definition
of Done lands on every new task unless it is added with --no-dod.
How it works
.kadence/
|- state.json derived cache - gitignored, safe to delete
`- events/
|- archive/ compacted history, one file per month
`- 2026-09/ recent events, one file each
Every command appends one event. State is folded from the journal on read, so the board cannot drift from the journal — nothing is maintained by hand. Two branches writing at once produce two different files, and git merges them without a conflict by construction.
Design decisions, each recording what was measured and what would make us
revisit it, are in the journal that ships with this repository — kadence decision list, or kadence decision show DEC-3 for one in full. The longer
write-ups behind them are working papers and are kept out of git on purpose;
the decision, its reason and the alternatives that lost are in the events.
Your journal outlives the version that wrote it. Inside kadence/v1 the
format and the --json contract only grow: nothing is renamed or removed, an
upgrade never rewrites an event, and a journal written by any released version
reads the same in every later one — tested on real journals from every minor
version since 0.1 (test/compatibility.test.ts). The full policy, deprecation
included: kadence search "compatibility policy" or kadence doc show DOC-65.
Contributing
npm install npm test # 1,477 tests; builds dist/cli.js first npm run typecheck npm run build # dist/cli.js 149 KB, blessed kept external (82 KB at 0.4.1)
CLAUDE.md documents the invariants, the boundaries, and the decisions that
look arbitrary without their reasoning. Read it before changing the core.
Licence
MIT
来源:GitHub · github.com