k0-board 0.3.0 → 0.5.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/.claude/skills/k0-changelog/SKILL.md +2 -2
- package/.claude/skills/k0-discuss/SKILL.md +105 -0
- package/.claude/skills/k0-discuss/references/rounds.md +280 -0
- package/.claude/skills/k0-epic/SKILL.md +196 -0
- package/.claude/skills/k0-links/.claude-plugin/plugin.json +6 -0
- package/.claude/skills/k0-links/hooks/hooks.json +1 -0
- package/.claude/skills/k0-links/hooks/links.js +128 -0
- package/.claude/skills/k0-links/hooks/register.js +204 -0
- package/.claude/skills/k0-next/SKILL.md +82 -0
- package/.claude/skills/k0-order/SKILL.md +123 -0
- package/.claude/skills/k0-plan/SKILL.md +156 -0
- package/.claude/skills/k0-split/SKILL.md +169 -0
- package/.claude/skills/k0-story/SKILL.md +108 -0
- package/.claude/skills/k0-ultracode/SKILL.md +251 -0
- package/.claude/skills/k0-ultracode/references/agent-brief.md +71 -0
- package/.claude/skills/k0-ultracode/references/modes.md +49 -0
- package/.claude/skills/k0-verify/SKILL.md +219 -0
- package/.claude/skills/k0-whatsnew/SKILL.md +95 -0
- package/.claude/skills/k0-work/SKILL.md +212 -0
- package/CHANGELOG.md +426 -1
- package/README.md +1021 -119
- package/bin/k0-board.js +81 -11
- package/menubar/K0MenuBar.swift +35 -5
- package/package.json +13 -1
- package/platform/contract.js +37 -6
- package/platform/darwin/index.js +1 -0
- package/platform/darwin/shell.js +4 -1
- package/platform/darwin/terminal.js +230 -56
- package/platform/index.js +3 -1
- package/platform/linux/index.js +14 -0
- package/platform/linux/shell.js +10 -1
- package/platform/linux/tray.py +10 -10
- package/platform/shared/command.js +19 -3
- package/platform/shared/tmux.js +32 -14
- package/platform/win32/index.js +6 -2
- package/platform/win32/shell.js +4 -1
- package/platform/win32/terminal.js +24 -8
- package/platform/win32/tray.ps1 +13 -13
- package/server/backlog.js +618 -0
- package/server/changelog.js +13 -13
- package/server/db.js +1800 -146
- package/server/files.js +156 -26
- package/server/git.js +53 -14
- package/server/idle.js +15 -13
- package/server/index.js +1286 -189
- package/server/launcher.js +122 -14
- package/server/machine.js +10 -1
- package/server/mirror.js +1048 -0
- package/server/prices.js +59 -0
- package/server/projects.js +57 -12
- package/server/servers.js +22 -1
- package/server/sessions.js +5 -5
- package/server/settings.js +25 -2
- package/server/update.js +324 -0
- package/server/usage.js +642 -0
- package/server/watcher.js +67 -13
- package/server/worktree.js +600 -0
- package/server/writer.js +98 -26
- package/web/awake.js +62 -0
- package/web/base.css +4 -0
- package/web/board.css +404 -16
- package/web/board.js +1182 -152
- package/web/changelog.js +3 -3
- package/web/conf.js +118 -0
- package/web/files.css +206 -1
- package/web/files.html +10 -0
- package/web/files.js +533 -75
- package/web/fuzzy.js +73 -21
- package/web/index.html +109 -12
- package/web/json.js +145 -0
- package/web/list.css +536 -0
- package/web/list.js +1015 -0
- package/web/mentions.js +27 -9
- package/web/recency.js +10 -10
- package/web/units.js +1 -1
- package/web/usage.css +169 -0
- package/web/usage.html +78 -0
- package/web/usage.js +447 -0
- package/web/view.js +22 -3
- package/web/whatsnew.css +211 -0
- package/web/whatsnew.html +49 -0
- package/web/whatsnew.js +339 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# k0
|
|
2
2
|
|
|
3
3
|
**A board of sticky notes that drives your Claude Code sessions.** One column per project, one
|
|
4
|
-
|
|
4
|
+
story per piece of work. From a story you open a real terminal, and on the story you see at a
|
|
5
5
|
glance whether the session is working, has finished, is asking you something, or has a plan
|
|
6
6
|
waiting for your approval.
|
|
7
7
|
|
|
@@ -9,12 +9,15 @@ It exists because of one specific moment: four terminals open, and no way to tel
|
|
|
9
9
|
waiting for you without clicking through all four.
|
|
10
10
|
|
|
11
11
|
If you have used a kanban board, an infinite canvas like Miro, and a wall of paper sticky notes,
|
|
12
|
-
you have already seen the three pieces k0 is made of:
|
|
12
|
+
you have already seen the three pieces k0 is made of: stories standing in columns, a board that pans
|
|
13
13
|
and zooms instead of scrolling, and notes that sit at their own slightly crooked angle. What is
|
|
14
|
-
different is what those things are underneath. **A column is a repository, not a stage** —
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
different is what those things are underneath. **A column is a repository, not a stage** — the
|
|
15
|
+
stories reorder themselves by who is waiting for you, rather than being pushed along a pipeline.
|
|
16
|
+
(One switch in the top bar lays the same stories out as a list instead, for the days you are
|
|
17
|
+
planning rather than working.)
|
|
18
|
+
**A story drives real Claude Code sessions** — it opens a terminal, it knows what that session
|
|
19
|
+
is doing, and it goes on saying so while you are looking somewhere else. A story may have had
|
|
20
|
+
several over its life, one at a time, and it keeps all of them.
|
|
18
21
|
|
|
19
22
|

|
|
20
23
|
|
|
@@ -23,6 +26,7 @@ doing, and it goes on saying so while you are looking somewhere else.
|
|
|
23
26
|
[](LICENSE)
|
|
24
27
|
|
|
25
28
|
**Contents** · [Install](#install) · [How it is used](#how-it-is-used) ·
|
|
29
|
+
[The backlog](#the-backlog) · [The ChangeLog](#the-changelog) · [What's New](#whats-new) ·
|
|
26
30
|
[The files of a session](#the-files-of-a-session) · [What it costs](#what-it-costs) ·
|
|
27
31
|
[Filling the board with what you have already done](#filling-the-board-with-what-you-have-already-done) ·
|
|
28
32
|
[The statuses](#the-statuses) · [The four modes](#the-four-modes) ·
|
|
@@ -95,7 +99,7 @@ only browsers are obliged to know that `.localhost` means this computer — k0 o
|
|
|
95
99
|
- **Node 24 or newer.** k0 keeps the board in SQLite through `node:sqlite`, which is built into
|
|
96
100
|
Node — there is nothing to install and there are no npm dependencies at all.
|
|
97
101
|
- **Claude Code**, obviously.
|
|
98
|
-
- **git**, for the mark on each
|
|
102
|
+
- **git**, for the mark on each story that says whether your work is safe.
|
|
99
103
|
- **macOS**: Xcode Command Line Tools, to build the menu bar icon. Nothing else.
|
|
100
104
|
- **Linux**: tmux, which is how k0 drives terminals there. Optionally `xdotool` for window
|
|
101
105
|
placement, and `python3` with PyGObject for the tray icon.
|
|
@@ -108,6 +112,7 @@ only browsers are obliged to know that `.localhost` means this computer — k0 o
|
|
|
108
112
|
| Open a terminal and run Claude Code in it | ✅ | ✅ tmux | ✅ |
|
|
109
113
|
| Read the terminal to know when it is ready | ✅ | ✅ | ❌ waits a fixed moment instead |
|
|
110
114
|
| Leave your prompt in place, unsent | ✅ needs Accessibility | ✅ | ✅ |
|
|
115
|
+
| Rename a running session when its title changes | ✅ needs Accessibility | ❌ when it ends | ❌ when it ends |
|
|
111
116
|
| Place, resize and raise windows | ✅ | ✅ X11 only | ✅ |
|
|
112
117
|
| Large text in terminals for driving mode | ✅ | ❌ | ❌ |
|
|
113
118
|
| Keep the machine awake | ✅ | ✅ | ✅ |
|
|
@@ -138,12 +143,19 @@ Nothing on this list happens before you have seen it and said yes. Everything on
|
|
|
138
143
|
| **macOS only** — one administrator rule | `/etc/sudoers.d/k0-pmset` | to keep the Mac awake with the lid closed. Asks for your password once, and grants exactly two command lines |
|
|
139
144
|
| **macOS only** — one key binding | your Terminal profile (backed up first) | so Shift+Enter starts a new line |
|
|
140
145
|
| **macOS only** — Accessibility for `node` | you grant it by hand, in System Settings | so k0 can place a prompt without sending it |
|
|
146
|
+
| The commands, and the `k0-links` mod, if you want them | `~/.claude/skills/` | Claude Code looks there and in the repository you have open, and nowhere else. Asked once; installing again brings the copies up to date without asking |
|
|
141
147
|
|
|
142
148
|
That last one deserves a sentence of its own: a process with the Accessibility permission can
|
|
143
149
|
send keystrokes to any application, and here it is granted to your `node`, not to a signed k0
|
|
144
150
|
app. Skipping it breaks nothing — the prompt gets typed and the session starts by itself.
|
|
145
151
|
|
|
146
|
-
k0 makes **
|
|
152
|
+
k0 makes **exactly one network request**, and you can switch it off. Once a day it asks the public
|
|
153
|
+
npm registry what the newest version of `k0-board` is, so the board can mention that there is one.
|
|
154
|
+
The package name is in the address and nothing else is in the request: not the version you are
|
|
155
|
+
running, not your repositories, not your commits, not your board, not an identifier of any kind.
|
|
156
|
+
Nothing is downloaded and nothing is run — k0 cannot update itself. Set `"updateCheck": false` in `~/.k0/config.json` and and no
|
|
157
|
+
socket is opened, ever. Everything else stays as it was: no fonts fetched, no telemetry, no
|
|
158
|
+
`git fetch`.
|
|
147
159
|
|
|
148
160
|
---
|
|
149
161
|
|
|
@@ -152,9 +164,13 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
152
164
|
### The board
|
|
153
165
|
|
|
154
166
|
- **+** — at the left, next to k0, and next to every repository name on the board: that one opens
|
|
155
|
-
a
|
|
156
|
-
|
|
157
|
-
|
|
167
|
+
a story with the repository already chosen. Two fields and no more: the repository and a title.
|
|
168
|
+
Nothing is asked about what the story is for, because both ways out of the dialog open a terminal
|
|
169
|
+
and you say it there. (With a backlog behind the board the `+` at the left is a menu of two — a
|
|
170
|
+
story typed here, or an epic told to a terminal — the dialog gains a field for the story's epic,
|
|
171
|
+
and the two buttons are *Discuss* and *Quick Start*. Editing a story that exists adds a list of
|
|
172
|
+
**notes**, which sit on the post-it for you to read and are never sent to Claude Code. It is
|
|
173
|
+
written out [below](#the-two-views).)
|
|
158
174
|
|
|
159
175
|
The repository has to be **picked from the list** (searchable, most used at the top; arrow keys
|
|
160
176
|
to move, Enter takes the highlighted row): a name typed by hand does not count. On leaving the
|
|
@@ -168,19 +184,26 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
168
184
|
spaces, and the capitals you typed stay where you put them — `fix api` becomes `Fix-Api`, while
|
|
169
185
|
`Fix API` stays `Fix-API`. What you see in the field is exactly the name the session will have.
|
|
170
186
|
|
|
171
|
-
- **the pencil** (top right of a
|
|
172
|
-
itself does nothing. On a
|
|
187
|
+
- **the pencil** (top right of a story) — the only way to open the editor: clicking the story
|
|
188
|
+
itself does nothing. On a story that is already finished, where there is nothing left to edit,
|
|
173
189
|
the **bin** takes its place.
|
|
174
190
|
|
|
175
|
-
Changing the title — only the title; the prompt has nothing to do with it —
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
191
|
+
Changing the title — only the title; the prompt has nothing to do with it — renames the session
|
|
192
|
+
too, in three places at three moments. The window's title bar, **immediately**, session running
|
|
193
|
+
or not. The session itself, if it is still running, **the first time you look at it**: when that
|
|
194
|
+
window is the one in front of you and Claude Code is sitting idle with nothing under the cursor,
|
|
195
|
+
k0 types `/rename` with the new name into it and presses Enter — you will see the command go by.
|
|
196
|
+
It never brings the window up to do that: the keyboard is yours, and a terminal jumping up while
|
|
197
|
+
you type somewhere else would take your next words. And the list of sessions you can resume,
|
|
198
|
+
**when the session ends** — while the process is alive the transcript already has an owner, and
|
|
199
|
+
it would write the old name back over ours. On Linux and Windows the second of the three is
|
|
200
|
+
missing, and `k0-board doctor` says so: there the name catches up when the session ends. The
|
|
201
|
+
same happens when a skill changes the title through the API.
|
|
202
|
+
|
|
203
|
+
- **Start** — opens a new terminal window, runs `claude` in the right repository under the story's
|
|
181
204
|
name, and puts the prompt in it. You press Enter.
|
|
182
205
|
|
|
183
|
-
The session is **born in plan mode**, always. On the board the
|
|
206
|
+
The session is **born in plan mode**, always. On the board the story turns **Planning** as soon
|
|
184
207
|
as it gets to work, and amber **Needs approval** when the plan is ready. If you need something
|
|
185
208
|
else, shift+tab as usual. **Resume** forces nothing: that session already had a mode, and it
|
|
186
209
|
comes back as it was.
|
|
@@ -189,6 +212,11 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
189
212
|
never asking anything are two things Claude Code does not do together — the why is
|
|
190
213
|
[further down](#the-traps).
|
|
191
214
|
|
|
215
|
+
Every session, new or resumed, is also born **with Claude Code's task list switched on**. On a
|
|
216
|
+
newer model Claude Code leaves it off unless it is told otherwise, and the commands that plan,
|
|
217
|
+
work and check keep a task per step — so without it they would be asking for a tool that is not
|
|
218
|
+
there.
|
|
219
|
+
|
|
192
220
|
The window is born **centred on the screen you are using**, at 86% of the free space: the same
|
|
193
221
|
margin on all four sides, never under a menu bar or a dock. Open more than one and they stack
|
|
194
222
|
in the middle — double click brings the one underneath back.
|
|
@@ -201,12 +229,16 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
201
229
|
it. It is what stops you losing track of which window is which.
|
|
202
230
|
|
|
203
231
|
- **Resume** — appears once the terminal has been closed, by you or by k0 after a long silence: it
|
|
204
|
-
reopens the same conversation exactly where it was. The
|
|
232
|
+
reopens the same conversation exactly where it was. The story's prompt is **not** put back in —
|
|
205
233
|
that conversation answered it hours ago, and typing it in again would be at best something stale
|
|
206
234
|
in the way.
|
|
207
235
|
|
|
208
236
|
- **Done** — closes the work **and its terminal**, with no questions: undo it with **Reopen**, and
|
|
209
|
-
pick the conversation up again with **Resume**.
|
|
237
|
+
pick the conversation up again with **Resume**. On a story that has never been started there is
|
|
238
|
+
no terminal to close, and the button is there anyway as long as there is a backlog behind the
|
|
239
|
+
board — a story planned here and then worked on in a terminal you opened yourself has to be
|
|
240
|
+
closable, and `Done` is the only thing in k0 that closes one. With the backlog switched off it
|
|
241
|
+
is not drawn on those stories at all.
|
|
210
242
|
|
|
211
243
|
The session is stopped first and only then is the window closed. Closing a window with `claude`
|
|
212
244
|
still inside it makes macOS put up the "terminate running processes" dialog, and the window does
|
|
@@ -214,7 +246,7 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
214
246
|
|
|
215
247
|
- **Close** — a link at the end of the row, quieter than the buttons because it is the one you
|
|
216
248
|
reach for least: it closes the terminal and **not the work**. The session is stopped, its window
|
|
217
|
-
goes, and the machine gets the memory back; the
|
|
249
|
+
goes, and the machine gets the memory back; the story stays exactly where it is, with the colour
|
|
218
250
|
it had — the one asking you something stays red, the one holding a plan up stays amber, the one
|
|
219
251
|
at your turn stays yellow — and **Resume** takes it from there. It is what a dozen windows open
|
|
220
252
|
and a computer running out of air are answered with.
|
|
@@ -222,9 +254,9 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
222
254
|
It is **not there while the session is working**: stopping one mid-thought is not memory saved,
|
|
223
255
|
it is work lost. Wait for it to come back to you, and then close it.
|
|
224
256
|
|
|
225
|
-
The only thing that asks for confirmation is throwing a
|
|
257
|
+
The only thing that asks for confirmation is throwing a story away.
|
|
226
258
|
|
|
227
|
-
|
|
259
|
+
Stories reorder themselves inside a column: first the ones waiting for you, then the ones grinding
|
|
228
260
|
away, backlog at the bottom, and among equals the most recent first.
|
|
229
261
|
|
|
230
262
|
### Moving around
|
|
@@ -261,16 +293,16 @@ that is waiting for you is the opposite of what the board is for. A terminal sim
|
|
|
261
293
|
**Your turn** is not one of those: it is the resting state of every window you have not closed,
|
|
262
294
|
and a session you finished with three weeks ago would otherwise hold its column at full width for
|
|
263
295
|
ever. It folds like anything else — and folding closes nothing, so the terminal is still open and
|
|
264
|
-
the
|
|
296
|
+
the story is still exactly where you left it. And **nothing folds while you are looking at it**: within one visit the set of columns can only grow, and the board tidies itself
|
|
265
297
|
on the next reload, so a column never disappears out from under your hands.
|
|
266
298
|
|
|
267
299
|
**The last two columns on the right are `Old` and `Others`**, and they are the same list twice
|
|
268
300
|
over: a `+`, a name and the git mark, in alphabetical order. `Old` is the repositories that have
|
|
269
301
|
work on the board, just not lately; `Others` is the ones that have no column because they have no
|
|
270
|
-
|
|
302
|
+
stories at all. **Click a row in `Old` and the column comes back** at full width for the rest of the
|
|
271
303
|
visit — with everything that was in it, which is why the row itself says nothing about how much
|
|
272
304
|
that is or how long it has been there. Both columns are also there for the same two things:
|
|
273
|
-
getting into the files of a directory you are not working on, and giving birth to the first
|
|
305
|
+
getting into the files of a directory you are not working on, and giving birth to the first story
|
|
274
306
|
there with the `+`.
|
|
275
307
|
|
|
276
308
|
Next to a column's `+` there is one more button, which **puts that column away now** instead of
|
|
@@ -281,18 +313,18 @@ back to your turn every few seconds and it would spend the session blinking.
|
|
|
281
313
|
Unlike the automatic fold, this one is remembered across reloads, until you fetch the column back
|
|
282
314
|
or something in it wakes up. It **closes nothing**: no session is stopped and no terminal is
|
|
283
315
|
shut. It is the board that gets smaller, not the work — what closes a session is `Close` or `Done`
|
|
284
|
-
on a
|
|
316
|
+
on a story.
|
|
285
317
|
|
|
286
318
|
### The git mark
|
|
287
319
|
|
|
288
|
-
On every
|
|
320
|
+
On every story, next to the repository name, and next to every column name, one symbol says
|
|
289
321
|
whether the work is safe: a **dot** with how many files, if there is work that is nowhere yet; an
|
|
290
322
|
**up arrow** with how many commits, if it is committed but not pushed; a faded **tick**, if
|
|
291
323
|
everything is saved. Hover to read it in full — branch, files, commits, and how many of those
|
|
292
324
|
commits belong to that session. **Click it and the files open.**
|
|
293
325
|
|
|
294
|
-
A
|
|
295
|
-
its own. A
|
|
326
|
+
A story running in an **isolated worktree** has a working tree of its own, so the mark is really
|
|
327
|
+
its own. A story working in the base repository shares the working tree with everybody — there the
|
|
296
328
|
dot belongs to the repository, and the only thing that belongs to the session is the commits made
|
|
297
329
|
since it started, which k0 counts by remembering where `HEAD` was at that moment.
|
|
298
330
|
|
|
@@ -325,8 +357,9 @@ that asked for it, close every session, restart k0 itself — the server stays u
|
|
|
325
357
|
stays green. This is the whole reason it exists: a dev server started inside a session belongs to
|
|
326
358
|
that session, and dies with it.
|
|
327
359
|
|
|
328
|
-
**k0 never asks the server whether it is up.**
|
|
329
|
-
|
|
360
|
+
**k0 never asks the server whether it is up.** Nothing here opens a socket — the one request k0
|
|
361
|
+
makes goes to npm, and it is about versions, not about you. "Up" means the process is alive *and*
|
|
362
|
+
the operating system says it is holding a TCP port
|
|
330
363
|
open. That is stronger evidence than a reply would be, and it is where the port in the tooltip
|
|
331
364
|
comes from — k0 never guesses a port, it reads the one your server actually chose.
|
|
332
365
|
|
|
@@ -339,6 +372,478 @@ as off.
|
|
|
339
372
|
|
|
340
373
|
---
|
|
341
374
|
|
|
375
|
+
## The backlog
|
|
376
|
+
|
|
377
|
+
A post-it used to be a name and a prompt. That is enough to start a session and nothing like
|
|
378
|
+
enough to remember why you started it: three weeks later the title says `Fix-Invoicing`, and the
|
|
379
|
+
half hour that decided what *fixed* meant has scrolled off the top of a terminal you have since
|
|
380
|
+
closed.
|
|
381
|
+
|
|
382
|
+
The backlog is the rest of it. Same board, same notes, same gestures — what is added is what the
|
|
383
|
+
work is *about*: what it belongs to, what was settled while you were talking about it, what has
|
|
384
|
+
to be true before it can be called finished, and a check that holds the finished thing up against
|
|
385
|
+
all of that before you are allowed to tick it off.
|
|
386
|
+
|
|
387
|
+
**The board is the menu; the commands are the engine.** Every story says what the one next thing
|
|
388
|
+
to do with it is — *Discuss*, *Plan*, *Work* — and pressing that opens a terminal with
|
|
389
|
+
the command already in it. The work happens there, in Claude Code, and you do not come back to the
|
|
390
|
+
board until it is finished. Almost nothing here is typed into a form.
|
|
391
|
+
|
|
392
|
+
If you want the argument rather than the manual — why a decision has to be an object, what a
|
|
393
|
+
round of questions is for, what the counter-check is really checking — it is in
|
|
394
|
+
[docs/method.md](docs/method.md), and it is a shorter read than this section.
|
|
395
|
+
|
|
396
|
+
### Before anything else: the commands have to be on your machine
|
|
397
|
+
|
|
398
|
+
Everything below runs on ten commands you type at Claude Code, and Claude Code looks for a
|
|
399
|
+
command in exactly two places: **the repository you have open**, and **your own
|
|
400
|
+
`~/.claude/skills/`**. Neither of those is where npm puts k0. So a command that was not copied out
|
|
401
|
+
is a command that does not exist, however carefully it was written — and every button on the board
|
|
402
|
+
that offers to run one leads nowhere.
|
|
403
|
+
|
|
404
|
+
Copying them out is **one question, asked by the installer**, right after it starts the service:
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
/k0-epic — an epic, discussed in rounds, then a tree of stories
|
|
408
|
+
/k0-story — one story, straight onto the board
|
|
409
|
+
…
|
|
410
|
+
Install 11 commands and the mod for Claude Code? (Y/n)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Say yes and they are there in every repository you ever open. It is worth saying plainly what
|
|
414
|
+
happens if you do not, because it is what happened to this feature the first time round: the
|
|
415
|
+
commands were written and they worked — inside a clone of k0, and nowhere else on the machine.
|
|
416
|
+
From any other repository the board offered *Discuss*, the terminal opened, and Claude Code had
|
|
417
|
+
never heard of `/k0-discuss`. The whole backlog was invisible for want of one copy step.
|
|
418
|
+
|
|
419
|
+
**If you are not sure you said yes, run `npx k0-board@latest` again.** It asks only about the ones
|
|
420
|
+
that are missing, so somebody who already has them is not asked at all, and somebody who said no
|
|
421
|
+
in a hurry gets the question back. `ls ~/.claude/skills` answers it too.
|
|
422
|
+
|
|
423
|
+
If you **cloned this repository** rather than installing the package, they are already in its
|
|
424
|
+
`.claude/skills/` and there is nothing to do — but only while you are working *in this clone*.
|
|
425
|
+
Copy them out anyway if you use them anywhere else.
|
|
426
|
+
|
|
427
|
+
### A day with it
|
|
428
|
+
|
|
429
|
+
**You open the board.** Every story that has something to do carries **one button, first in the
|
|
430
|
+
row, saying what that is**: **Discuss**, **Plan**, **Work** — in that order, because that is the
|
|
431
|
+
order the work goes in — or **Resume**, when a terminal was opened on it and then closed. Hover it
|
|
432
|
+
and it says why this and not something else: *It has been discussed and has no plan yet*. There is
|
|
433
|
+
one button and never a menu, and there are three words on the list and no more.
|
|
434
|
+
|
|
435
|
+
There is also a story that carries **no** button, and that is an answer too. A session that is
|
|
436
|
+
running needs nothing suggested about it — the terminal is where the work is, and a double click on
|
|
437
|
+
the note goes there. A story waiting for you to look it over is waiting for a person. A story that
|
|
438
|
+
is finished is finished. Filling any of those in with a command would be k0 inventing work.
|
|
439
|
+
|
|
440
|
+
k0 works that out and the page never does. It is the same reasoning `/k0-next` does, in the same
|
|
441
|
+
place, so the button on the note and the answer the command gives can never drift apart.
|
|
442
|
+
|
|
443
|
+
**You press it.** A terminal opens in that repository and `/k0-plan K42` — the line you would have
|
|
444
|
+
typed yourself — goes in with it, already sent: k0 wrote that line out of a button you pressed, so
|
|
445
|
+
there is nothing on it for you to read over first, and a prompt left sitting unsent under the
|
|
446
|
+
cursor is a window that did nothing.
|
|
447
|
+
|
|
448
|
+
**Or you take the short way in.** **Quick Start** is the other road out of a story and it is not
|
|
449
|
+
the same road: it opens a terminal on that repository with *nothing* in it and leaves the typing to
|
|
450
|
+
you. That is the whole of it — no discussion, no plan, no command. It sits at the end of the row as
|
|
451
|
+
a quiet link on a story that has a suggestion, and it is the plain button on one that has not.
|
|
452
|
+
|
|
453
|
+
Only `/k0-work` counts as the work having begun. Press *Discuss* or *Plan* and the story stays
|
|
454
|
+
where it was until the discussion or the plan moves it itself — otherwise walking away from a
|
|
455
|
+
discussion half way through would leave a story sitting in `Working` with nothing worked on.
|
|
456
|
+
|
|
457
|
+
**You work in the terminal, and only in the terminal.** The discussion asks its rounds and writes
|
|
458
|
+
each one down as it is answered; the plan comes back for your approval with the standing decisions
|
|
459
|
+
written into it as constraints; `/k0-work` opens a worktree, does the work, keeps the log, and
|
|
460
|
+
merges it back; `/k0-verify` walks the result past every decision one at a time. None of that
|
|
461
|
+
needs the board. You can leave the tab open and watch the rounds land — it follows a live
|
|
462
|
+
discussion once a second — but nothing asks you to.
|
|
463
|
+
|
|
464
|
+
**You come back, and the button has moved on.** A story you discussed now says *Plan*. One you
|
|
465
|
+
planned says *Work*. One whose terminal you closed says *Resume*, and picks the conversation up
|
|
466
|
+
where it was rather than starting a second one beside it.
|
|
467
|
+
|
|
468
|
+
**Double click the note to go where the work is.** Its terminal if one is running; the conversation
|
|
469
|
+
it left behind if the terminal was closed; a fresh session if there was never one. It is the same
|
|
470
|
+
gesture on every note, which is what makes it worth having — and if the window has been closed by
|
|
471
|
+
hand while the session is still thinking, k0 goes and looks for it by name before it tells you
|
|
472
|
+
anything, and offers to open it again when there is really nothing left to find.
|
|
473
|
+
|
|
474
|
+
**Done is yours and nothing else's.** No command sets it and no gesture sets it: when the work is
|
|
475
|
+
really finished you press **Done** on the note, and it closes the terminal with it. A story that
|
|
476
|
+
came through its counter-check clean is offered no command at all — there is nothing left for one
|
|
477
|
+
to do, and the only thing in front of it is you pressing Done. `/k0-verify` and `/k0-split` are
|
|
478
|
+
still there and still do what they always did: they are commands you type, on the days you want
|
|
479
|
+
them, rather than advice the board pushes at you.
|
|
480
|
+
|
|
481
|
+
**Things arrive during the day, and they do not interrupt this.** Something you already know you
|
|
482
|
+
want is `/k0-story` in whatever terminal you have open — you say it, it lands on the board with a
|
|
483
|
+
key of its own, and adding *and start it* opens the session in the same breath. Something big
|
|
484
|
+
enough that you do not yet know what it is made of is `/k0-epic`: ten minutes of questions in
|
|
485
|
+
rounds, everything settled written down as it is settled, and only at the end a tree of stories
|
|
486
|
+
proposed for your approval — it creates none of them until you have said yes. Both are on the
|
|
487
|
+
board's `+` as well, which is a small menu now: **Story** opens the dialog you know, with one
|
|
488
|
+
field added for its epic; **Epic** asks which repository and then opens a terminal running
|
|
489
|
+
`/k0-epic`, because an epic is told, not typed.
|
|
490
|
+
|
|
491
|
+
### The two views
|
|
492
|
+
|
|
493
|
+
The switch in the top bar, in among the filters, says **Kanban** or **List**. It changes the shape
|
|
494
|
+
of what you are looking at and never what you are looking at: the state pills, the repository and
|
|
495
|
+
the epic lane apply to both, so switching back and forth is free and nothing appears or vanishes
|
|
496
|
+
under you.
|
|
497
|
+
|
|
498
|
+
**Kanban is for working.** It is the board you already know — one column per repository, notes
|
|
499
|
+
that reorder themselves by who is waiting for you. With a backlog behind it a note grows four
|
|
500
|
+
marks and no more: its **key**; the **epic** it belongs to, as a small label in the epic's own
|
|
501
|
+
colour, worked out from the key so there is nothing to choose and nothing to keep in step; a
|
|
502
|
+
**flag** in the bottom corner; and a warning when something it **waits on** is not finished.
|
|
503
|
+
|
|
504
|
+
The flag is put on and taken off **from the note itself** — it is the mark and the target both,
|
|
505
|
+
and it mirrors the pencil at the other corner. It is invisible until the pointer is on the note,
|
|
506
|
+
because an outline sitting on every note all the time is a mark that is everywhere and therefore
|
|
507
|
+
marks nothing. Once it is on it stays on, and the note takes a border and its key and title take
|
|
508
|
+
the flag's colour with it: the point of flagging something is finding it again from across the
|
|
509
|
+
room, and a fifteen-pixel glyph cannot be seen from there.
|
|
510
|
+
|
|
511
|
+
**Click an epic's label and the board becomes that epic.** A strip appears under the top bar with
|
|
512
|
+
its key, its title, its repository, a progress bar and `4 of 11 done`, and the way back out. Inside
|
|
513
|
+
the lane the label is not drawn on the notes — everything in here belongs to the same epic, and
|
|
514
|
+
saying so eleven times says nothing. The lane survives a reload: going into an epic is a decision
|
|
515
|
+
about where you are working, and a page that forgets it every time you press F5 is a page you stop
|
|
516
|
+
going into. The progress is counted over the epic's stories, not over the notes a filter left on
|
|
517
|
+
screen, and it is not weighted: eleven stories with one done is 1 of 11, however big the one was.
|
|
518
|
+
Anything else is an estimate, and an estimate here is a lie with a progress bar drawn round it.
|
|
519
|
+
|
|
520
|
+
**List is for planning.** The same stories as rows, three levels deep and every repository at
|
|
521
|
+
once: a thin heading per repository, an epic that opens and closes with its progress bar — and,
|
|
522
|
+
while a discussion is running on it, which round that is on — and under it its stories, with tasks
|
|
523
|
+
indented beneath the story they were cut from. Stories belonging to no epic are grouped at the
|
|
524
|
+
end. A row carries key, title, state, flag, how many decisions are still standing, how much of
|
|
525
|
+
the checklist has passed, and the same next-step button. Which epics you left open is remembered.
|
|
526
|
+
|
|
527
|
+
**Click a row and the story opens beside it**, not underneath: the counter-check first, then why
|
|
528
|
+
it exists, the rounds with their questions and answers, the decisions with the verdict each one
|
|
529
|
+
got, the plan, the checklist and the log — with a line under the title saying both what it waits
|
|
530
|
+
for and what is waiting for it, each key a way into that story. Beside rather than below, because
|
|
531
|
+
the point of a list is to run down it, and a panel that pushes the rows off the bottom of the page
|
|
532
|
+
loses the thing you were comparing against. Click an epic and the epic opens the same way — the
|
|
533
|
+
rounds it was argued out in, and the decisions every story under it is held to. That is the only
|
|
534
|
+
place that conversation can be watched, because it happens before a single story of it exists.
|
|
535
|
+
|
|
536
|
+
Two things in this view write rather than read, and they are the two you do while *looking* at a
|
|
537
|
+
backlog rather than while working on one: **the next step, started from the end of a row**, and **a
|
|
538
|
+
checklist line you have just watched work with your own eyes** — ticked in the panel, and recorded
|
|
539
|
+
as yours rather than the model's, which is the difference the checklist exists to keep.
|
|
540
|
+
|
|
541
|
+
**Dragging a row moves it.** Up and down to change the order, onto another epic's heading to move
|
|
542
|
+
it there, onto `No epic` to take it out of one. That is the whole of it: **dragging never changes
|
|
543
|
+
state.** A state is a road the work walks, and walking it by dropping a piece of paper somewhere
|
|
544
|
+
was always the wrong gesture — states move from the terminal, and from the Done button.
|
|
545
|
+
|
|
546
|
+
### The ten commands
|
|
547
|
+
|
|
548
|
+
Ten you type, and the installer offers eleven — these ten plus
|
|
549
|
+
[`/k0-import`](#filling-the-board-with-what-you-have-already-done) — and one more thing that is not a
|
|
550
|
+
command at all, [the `k0-links` mod](#what-claude-points-at-one-click-away). `/k0-whatsnew` and
|
|
551
|
+
`/k0-changelog` are deliberately not on that list: k0 runs those two itself, out of its own
|
|
552
|
+
directory, and you never type them.
|
|
553
|
+
|
|
554
|
+
| | |
|
|
555
|
+
|---|---|
|
|
556
|
+
| `/k0-story` | one story, straight onto the board — the fast door |
|
|
557
|
+
| `/k0-epic` | the long way in: rounds, decisions, then a tree of stories you approve |
|
|
558
|
+
| `/k0-discuss` | the same rounds against a story that already exists |
|
|
559
|
+
| `/k0-split` | a story that will not close, cut into tasks that inherit its decisions |
|
|
560
|
+
| `/k0-plan` | plan mode, with the standing decisions written into the plan as constraints |
|
|
561
|
+
| `/k0-work` | the worktree, the work, the log as it goes, and the merge back |
|
|
562
|
+
| `/k0-ultracode` | a whole epic, or one story, run by a manager with agents under it |
|
|
563
|
+
| `/k0-verify` | the counter-check |
|
|
564
|
+
| `/k0-next` | what to pick up now, and why |
|
|
565
|
+
| `/k0-order` | priority and dependencies, dictated: *K51 to the top, K42 waits on K37, flag K19* |
|
|
566
|
+
|
|
567
|
+
These ten are also the only ten a button on the board may start. They are written out by name in
|
|
568
|
+
the server and checked against that list before anything reaches a command line — and it is a list
|
|
569
|
+
and not a directory listing on purpose: a folder arriving in your skills directory, from a clone or
|
|
570
|
+
a package or an installer, must not thereby become something a web page can ask k0 to run.
|
|
571
|
+
|
|
572
|
+
`/k0-next` is worth one sentence of its own, because the answer is not the model's. k0 works out
|
|
573
|
+
what to pick up — a live session first, then something in `Review` and the one that has been
|
|
574
|
+
sitting there longest, then what is not waiting on unfinished work, then the flag, then how far
|
|
575
|
+
along it is, then the order you put the board in — and hands over the story with the sentence that
|
|
576
|
+
says why. Ask twice and you get the same answer, which is not true of anything a model reasons out
|
|
577
|
+
each time.
|
|
578
|
+
|
|
579
|
+
**Dependencies are a note, not a lock.** Nothing refuses to start a story that is waiting on
|
|
580
|
+
another one: the note is marked, the button that starts the work asks you once and then goes
|
|
581
|
+
ahead, and the story sinks down `/k0-next`. A backlog that will not let you work on what you want
|
|
582
|
+
is a backlog you stop using.
|
|
583
|
+
|
|
584
|
+
### An epic, a story, a task
|
|
585
|
+
|
|
586
|
+
**A story is one post-it**, and it is the thing you work on. Everything the board already does it
|
|
587
|
+
still does: a story opens a terminal, drives the session in it, and says what that session is
|
|
588
|
+
doing.
|
|
589
|
+
|
|
590
|
+
**An epic is a reason** with several stories under it — an area, a feature, a rewrite. It lives in
|
|
591
|
+
exactly one repository, because a piece of work that spans two of them is two pieces of work with
|
|
592
|
+
a wish in the middle.
|
|
593
|
+
|
|
594
|
+
**A task is a story that was cut out of another one.** It is not a different kind of thing: same
|
|
595
|
+
table, same rules, same key — a story that turned out too big to close gets split, not turned into
|
|
596
|
+
another species. A task takes its parent's epic unless you give it one of its own, because a task
|
|
597
|
+
planned outside the epic its parent sits in would be planned blind to every decision that shaped
|
|
598
|
+
the whole thing.
|
|
599
|
+
|
|
600
|
+
### The key, and where it sits
|
|
601
|
+
|
|
602
|
+
Every epic, story and task gets a **key**: `K` plus a number, `K42`. It is counted per repository,
|
|
603
|
+
shared between epics and stories, and it is **never reused and never reassigned** — not when the
|
|
604
|
+
story moves under another epic, not when you delete it, not when the repository is renamed. Two
|
|
605
|
+
repositories can both have a `K42`, and that is intended: a key means something inside its
|
|
606
|
+
repository and nowhere else. Move a story to another repository and it is given a key from *that*
|
|
607
|
+
repository, rather than carrying a number into a place that already has one.
|
|
608
|
+
|
|
609
|
+
Beside it there is a **position**: `1.12.1`. The first epic, its twelfth story, that story's first
|
|
610
|
+
task. The position is worked out fresh every time it is shown and never stored, so it cannot
|
|
611
|
+
disagree with the tree it describes — move a story and its position moves with it.
|
|
612
|
+
|
|
613
|
+
The key is the name you say out loud; the position is where the thing is sitting today. When you
|
|
614
|
+
say `K42` to a command it knows what you mean, whatever the board has been rearranged into since.
|
|
615
|
+
|
|
616
|
+
### Why a story is not a session
|
|
617
|
+
|
|
618
|
+
This is the one change underneath everything else, and it is worth a paragraph.
|
|
619
|
+
|
|
620
|
+
A card used to *be* a session: one note, one conversation, and ticking the note off ended both. So
|
|
621
|
+
a piece of work you came back to twice was two notes, and the first one was a note about a
|
|
622
|
+
conversation nobody could remember.
|
|
623
|
+
|
|
624
|
+
Now a story keeps **every session it has had**, one at a time, over as long as it takes. And it
|
|
625
|
+
carries two different clocks, which used to be one column fighting itself:
|
|
626
|
+
|
|
627
|
+
- **the story's state** — `Backlog` · `Discussed` · `Planned` · `Working` · `Review` · `Done` —
|
|
628
|
+
which is where the *work* is;
|
|
629
|
+
- **the session's status** — working, planning, holding a plan up, asking you something, your turn
|
|
630
|
+
— which is what a *terminal* is doing this second.
|
|
631
|
+
|
|
632
|
+
No transition is required. Any state may follow any other, and `Backlog` straight to `Done` is a
|
|
633
|
+
legal thing to do that nothing will warn you about — a backlog that argues with you about the road
|
|
634
|
+
is a backlog you route around. `Working` sets itself when a session goes live. `Review` is where
|
|
635
|
+
`/k0-verify` puts a story when it starts checking it. **`Done` is only ever yours**: nothing in k0
|
|
636
|
+
sets it, and the Done button on the note is still what confirms it.
|
|
637
|
+
|
|
638
|
+
The post-it itself still draws one word and one colour, exactly as before — the two clocks put
|
|
639
|
+
back together. Nothing about the board you know got louder.
|
|
640
|
+
|
|
641
|
+
### Rounds, and why they say how many are left
|
|
642
|
+
|
|
643
|
+
A round is one small group of questions — four at the most — with your answers written down before
|
|
644
|
+
the next one is asked.
|
|
645
|
+
|
|
646
|
+
Each round opens by saying where it is: **"Round 3 of about 8"**. The number comes from counting
|
|
647
|
+
the things where a different answer would produce different work, and it is recalculated after
|
|
648
|
+
every answer, because answers both close questions and open them. When it moves, it says so in the
|
|
649
|
+
same breath — *round 4 of about 6, two of the questions answered themselves* — and never drifts in
|
|
650
|
+
silence. A count that quietly becomes twelve after promising eight is a count you stop believing,
|
|
651
|
+
and once you stop believing it you start answering to get it over with.
|
|
652
|
+
|
|
653
|
+
It stops when no remaining question would change the work, which is stricter than it sounds and is
|
|
654
|
+
the only test being applied: a question worth asking is one whose two answers lead to two different
|
|
655
|
+
builds. There is a hard ceiling of **fifteen rounds**. At fifteen it stops wherever it is, shows
|
|
656
|
+
you the list of what it never got to in your own words, and says the story is recorded as it stands
|
|
657
|
+
and can be picked up whenever you like. A discussion that reaches fifteen is telling you the story
|
|
658
|
+
is really two, and it says that as well.
|
|
659
|
+
|
|
660
|
+
**Every round is written to k0 before the next question is asked.** Not at the end, not on a save.
|
|
661
|
+
A terminal that dies at round three does not take the first three with it, and neither does a
|
|
662
|
+
session that runs out of context in the middle — which is the one that actually happens, and the one
|
|
663
|
+
nobody thinks about until the second time.
|
|
664
|
+
|
|
665
|
+
### Decisions
|
|
666
|
+
|
|
667
|
+
What comes out of the rounds is not a summary. It is a row of **decisions**, one complete sentence
|
|
668
|
+
each, numbered — `D1`, `D2` — and written in your language, about behaviour rather than about
|
|
669
|
+
implementation. A decision that names a function is one you cannot check without opening the code,
|
|
670
|
+
and six months from now you will not open the code.
|
|
671
|
+
|
|
672
|
+
A decision is **never rewritten**. When you change your mind, the new decision *supersedes* the old
|
|
673
|
+
one and both stay, the old one crossed through and pointing at what replaced it. This is the whole
|
|
674
|
+
reason they are objects and not paragraphs: the point is to hold the work up against what was
|
|
675
|
+
actually said at the time, and prose you can edit afterwards proves nothing.
|
|
676
|
+
|
|
677
|
+
An epic's decisions belong to the epic, and every story under it **inherits** them rather than being
|
|
678
|
+
handed a copy. They are shown with the epic's key in front — `K7·D3` — so it is obvious a rule came
|
|
679
|
+
down from above and applies to everything in the lane. Inheriting rather than copying is what makes
|
|
680
|
+
changing your mind work: supersede `K7·D3` on the epic and it is superseded for all eleven stories
|
|
681
|
+
at once, where eleven copies would have forked the first time one of them was touched.
|
|
682
|
+
|
|
683
|
+
An epic is discussed and decided before a single story of it exists, which is why its decisions
|
|
684
|
+
have to be able to live on the epic. That is not a detail: it is the main way anybody uses this.
|
|
685
|
+
|
|
686
|
+
And when something you say now contradicts something you settled earlier, the discussion **stops
|
|
687
|
+
there and asks** — naming the decision it clashes with, saying which of the two it thinks should
|
|
688
|
+
stand, and why. Writing both down and carrying on is how you end up with two rules that disagree
|
|
689
|
+
and no way of knowing which one the work followed.
|
|
690
|
+
|
|
691
|
+
### The counter-check
|
|
692
|
+
|
|
693
|
+
Here is what this is for.
|
|
694
|
+
|
|
695
|
+
You explain a piece of work to a model, properly, for half an hour. It asks good questions — some
|
|
696
|
+
of the answers surprise you, because you did not know what you wanted until it asked. It says it
|
|
697
|
+
has understood, and it has: the summary it gives back is better than the one you would have
|
|
698
|
+
written. Then it builds something that quietly contradicts half of it. Not all of it, and not
|
|
699
|
+
obviously. One thing you settled at minute twenty is simply not there, and something you ruled out
|
|
700
|
+
is there instead. You notice three days later, and by then you cannot even prove you said it.
|
|
701
|
+
|
|
702
|
+
That half hour did not merely fail to help. It cost you the half hour and it bought a false
|
|
703
|
+
confidence that the thing was understood, which is worse than knowing it was not, because you
|
|
704
|
+
stopped watching.
|
|
705
|
+
|
|
706
|
+
`/k0-verify` is the thing that was missing. When the work is done it takes the decisions **one at a
|
|
707
|
+
time** — the story's own and the ones it inherited — and records a verdict for each: **kept**,
|
|
708
|
+
**violated**, or **not applicable**, with the evidence. A file and a line, or a sentence saying why
|
|
709
|
+
the decision does not apply here. Never a summary standing in for the row, because a summary is
|
|
710
|
+
where the one that was broken goes to hide.
|
|
711
|
+
|
|
712
|
+
Three rules make it worth something rather than a ceremony:
|
|
713
|
+
|
|
714
|
+
- **A run is the whole set or it is not a run.** One that answers nine decisions of ten is refused
|
|
715
|
+
and told which one it passed over. `na` is a verdict; silence is not. A check that reports a
|
|
716
|
+
clean sweep of whatever it happened to look at is worse than no check.
|
|
717
|
+
- **A run never overwrites the one before it.** Runs are numbered and they all stay, so you can see
|
|
718
|
+
that something was broken, then fixed, rather than only that it is fine now.
|
|
719
|
+
- **A story cannot be marked `Done` while a decision a run found broken has not been answered
|
|
720
|
+
since.** It is read decision by decision and not run by run: a later run that finds the same
|
|
721
|
+
decision kept closes it, and a later run that says nothing about it, or says it does not apply,
|
|
722
|
+
leaves it exactly where it was. This is the only refusal in the whole feature, and it applies to
|
|
723
|
+
whatever is asking: the Done button on the note, the one at the end of a row in the list, a
|
|
724
|
+
command. It comes back as a sentence saying which decision, from which run, and what to do about
|
|
725
|
+
it.
|
|
726
|
+
|
|
727
|
+
There are exactly two ways to answer it, and both are honest: **put the work right and run the
|
|
728
|
+
counter-check again**, or **supersede the decision** if it turns out the decision was the thing that
|
|
729
|
+
was wrong. What you cannot do is talk past it: a story with a broken decision is drawn on the board
|
|
730
|
+
so that it cannot be scrolled past, and pressing Done on it comes back with the sentence rather than
|
|
731
|
+
the story closed.
|
|
732
|
+
|
|
733
|
+
There is also a **checklist** on the story — what has to be true for it to be finished. `/k0-verify`
|
|
734
|
+
does itself everything a machine can do, runs the project's tests, drives the browser when the thing
|
|
735
|
+
is a web application, and leaves you only the lines that genuinely need a person.
|
|
736
|
+
|
|
737
|
+
### `/k0-work` and the worktree
|
|
738
|
+
|
|
739
|
+
`/k0-work` gives the session a working copy of its own: a git worktree under
|
|
740
|
+
`<repo>/.claude/worktrees/`, on a branch named after the story, opened **from the branch you are
|
|
741
|
+
standing on** — not from `main`, not from `origin`. You keep working in the repository, the session
|
|
742
|
+
works next door, and at the end its branch comes back in as one merge commit and the copy is
|
|
743
|
+
destroyed. The folder is kept out of git's way through `.git/info/exclude`, never by writing in
|
|
744
|
+
your `.gitignore`.
|
|
745
|
+
|
|
746
|
+
Everything the board starts opens in the story's **own repository**, never in a worktree. `/k0-work`
|
|
747
|
+
makes one when it needs one, and it is the only command here that does: the others talk about the
|
|
748
|
+
story rather than change it, and a discussion held inside somebody else's working copy is a
|
|
749
|
+
discussion about a copy.
|
|
750
|
+
|
|
751
|
+
It will not open one over uncommitted work, and it says how much there is. And three things it
|
|
752
|
+
never does, each of which has already cost somebody a day:
|
|
753
|
+
|
|
754
|
+
- **It never pushes and never opens a pull request.** The merge stops on this machine. Publishing
|
|
755
|
+
is a decision you make when you are ready to make it.
|
|
756
|
+
- **It never resolves a conflict.** There is no way for a program to tell a conflict it resolved
|
|
757
|
+
correctly from one it resolved plausibly, and taking a side to make the command succeed throws
|
|
758
|
+
away something somebody typed. A conflict stops everything and says which files.
|
|
759
|
+
- **It never runs tests, a build or a dev server in there.** A worktree copies the code but not the
|
|
760
|
+
untracked files around it, so the `.env` somebody copies across carries the *base* repository's
|
|
761
|
+
port — and a test runner that finds a server already listening on it uses that one, goes green,
|
|
762
|
+
and tells you the new code passes when what it tested was the old checkout. Tests run on the base
|
|
763
|
+
branch, after the merge.
|
|
764
|
+
|
|
765
|
+
That last rule has one honest edge. Merging commits whatever the session left pending, a commit
|
|
766
|
+
runs your repository's own hooks, and a `pre-commit` hook that runs the whole suite is normal. k0
|
|
767
|
+
does not step round it with `--no-verify` — a commit that only went through because k0 avoided your
|
|
768
|
+
hooks has not been checked at all — so the hook does run, next door, with the wrong `.env` beside
|
|
769
|
+
it. k0 says so when it happens rather than being quiet about it.
|
|
770
|
+
|
|
771
|
+
### `/k0-ultracode`: the same work, with a manager over it
|
|
772
|
+
|
|
773
|
+
On a note that is ready to be worked on, next to **Work**, there is a quieter word: **Ultracode**.
|
|
774
|
+
It is the same act at a larger size. One session becomes a **manager**: it cuts the story's plan
|
|
775
|
+
into **assignments**, gives each one to an **agent** working in a copy of the repository of its own,
|
|
776
|
+
brings the work back one piece at a time, and only then — on your branch, where the code on the disk
|
|
777
|
+
is the code that was merged — runs the tests, has the result read by an agent that wrote none of it,
|
|
778
|
+
and walks the story past every decision. It is offered on an epic too, from the epic's panel, and
|
|
779
|
+
that is what it is really for: story after story, each one finished before the next one starts.
|
|
780
|
+
|
|
781
|
+
Before it does anything it asks you two questions and never asks again. **How much rope** —
|
|
782
|
+
*interactive*, where every question an agent brings back reaches you while it is warm; *checkpoint*,
|
|
783
|
+
which stops at the cut, before the merge and on a red test run; or *autonomous*, which goes to the
|
|
784
|
+
end and comes back with the list of everything it decided on your behalf. And **how hard** — two,
|
|
785
|
+
three or five agents at a time, one repair attempt or two, one pair of fresh eyes or three. Both
|
|
786
|
+
answers go into the Log, so a terminal you closed halfway through is picked up again on the same
|
|
787
|
+
terms rather than on new ones.
|
|
788
|
+
|
|
789
|
+
What it does not do is the point of the shape. It never pushes. It never runs anything inside a
|
|
790
|
+
worktree, for the reason above. It never presses **Done** — the stories come back sitting in
|
|
791
|
+
`Review`, counter-checked, waiting for you. And it stops: the repair attempts are spent and then it
|
|
792
|
+
tells you what is still broken, having merged everything that works. A run that never ends is not
|
|
793
|
+
thoroughness, it is a run nobody can plan around.
|
|
794
|
+
|
|
795
|
+
### The `.k0/` folder
|
|
796
|
+
|
|
797
|
+
Each repository with a backlog grows a `.k0/` folder: a `README.md` explaining itself, one file per
|
|
798
|
+
epic under `epics/`, one per story or task under `stories/`. A story file opens with its header —
|
|
799
|
+
key, epic, state, flag, what it waits on, the sessions it has lived through — and then
|
|
800
|
+
**Why**, the **Prompt**, the **Discussion** round by round, the **Decisions**, the **Plan**, the
|
|
801
|
+
**Verification** run by run with its checklist, and the **Log**. An epic's file is the same header,
|
|
802
|
+
its own **Why**, **Discussion** and **Decisions**, and then the list of its stories with a line
|
|
803
|
+
saying how far it has got.
|
|
804
|
+
|
|
805
|
+
The database is the source of truth and these are printed from it — whole, every time the story
|
|
806
|
+
changes, never diffed cleverly — so a file cannot end up claiming something the board does not. But
|
|
807
|
+
they are files, so they diff, they review, and they go in the commit with the work they describe.
|
|
808
|
+
Write in them if you like: anything you put under a heading k0 does not print is left exactly where
|
|
809
|
+
you put it, and so is a line you add to the header at the top and a note you leave under the title.
|
|
810
|
+
|
|
811
|
+
**Commit the folder.** It is the only copy of this that outlives the database, and it is the way
|
|
812
|
+
back: open a repository k0 has no stories for and it reads the folder in and rebuilds them, keys
|
|
813
|
+
and all. That is the reason the files exist at all — the rest is a pleasant side effect.
|
|
814
|
+
|
|
815
|
+
The folder is written **only** inside `.k0/` — never your `.gitignore`, never a line anywhere else
|
|
816
|
+
in your repository — and a test walks the tree afterwards to prove nothing else appeared. The one
|
|
817
|
+
other thing that ever writes into a repository is `/k0-work`, which you have to ask for: it is
|
|
818
|
+
written out in full under [What it reads, and what it never
|
|
819
|
+
does](#what-it-reads-and-what-it-never-does).
|
|
820
|
+
|
|
821
|
+
One thing to expect: the git mark on that column will go from a tick to a dot the day the folder
|
|
822
|
+
first appears. That is honest — there is something there that is not committed yet — and committing
|
|
823
|
+
it puts the mark back.
|
|
824
|
+
|
|
825
|
+
### Switching it off
|
|
826
|
+
|
|
827
|
+
The whole feature is one line in `~/.k0/config.json`, the same file the idle timeout lives in:
|
|
828
|
+
|
|
829
|
+
```json
|
|
830
|
+
{ "backlog": false }
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
and the board is exactly the board it has always been: nothing extra on a note, no next-step
|
|
834
|
+
button, no Kanban/List switch in the bar, no lanes, **no `.k0/` folder created in any repository**,
|
|
835
|
+
and the commands say plainly that the backlog is switched off rather than reporting an empty one.
|
|
836
|
+
Telling somebody their backlog is empty when it is really turned off is the one answer worse than
|
|
837
|
+
no answer. The `+` goes back to being a plain `+` that opens the story dialog, with no menu behind
|
|
838
|
+
it and no epic on the form.
|
|
839
|
+
|
|
840
|
+
It is in that file and not in k0's database on purpose: a switch you would need `sqlite3` to reach
|
|
841
|
+
is not a switch. k0 re-reads the file whenever it changes, so nothing has to be restarted, and
|
|
842
|
+
deleting the line puts the default back. `"updateCheck": false` is its neighbour — [the one that
|
|
843
|
+
stops the npm question](#what-installing-it-changes).
|
|
844
|
+
|
|
845
|
+
---
|
|
846
|
+
|
|
342
847
|
## The ChangeLog
|
|
343
848
|
|
|
344
849
|
The git mark answers "is this safe" for one repository, right now. The **ChangeLog** answers a
|
|
@@ -359,7 +864,7 @@ page that comes up empty after every weekend is a page you stop opening.
|
|
|
359
864
|
**Only what you touched in that window appears.** A repository that has been dirty since March
|
|
360
865
|
and that you have not opened since is not news, and a summary that repeats it every morning is
|
|
361
866
|
one nobody is still reading by Thursday. Something has to have happened there — a commit, a file
|
|
362
|
-
saved, a
|
|
867
|
+
saved, a story moved — before k0 will tell you what is still outstanding in it. And only **your**
|
|
363
868
|
commits are counted: k0 asks git which email you commit with in that repository and shows that
|
|
364
869
|
person's day, so a repository shared with other people still tells you about yours.
|
|
365
870
|
|
|
@@ -369,9 +874,10 @@ not believe the paragraph above it.
|
|
|
369
874
|
|
|
370
875
|
### Who writes it
|
|
371
876
|
|
|
372
|
-
k0 does not. **
|
|
373
|
-
model of its own would mean a key to keep, an account to configure, and your commit
|
|
374
|
-
|
|
877
|
+
k0 does not. **Nothing about your work leaves this machine**, and that is worth more than a better
|
|
878
|
+
paragraph: a model of its own would mean a key to keep, an account to configure, and your commit
|
|
879
|
+
messages going out over a wire. The one request k0 makes is to the npm registry, asking after its
|
|
880
|
+
own version; it carries no commits, no repository names and no identifier.
|
|
375
881
|
|
|
376
882
|
It does not need one. If you are running k0 you already have Claude Code installed, signed in and
|
|
377
883
|
paid for — that is the whole point of the board — so the model is already here. k0 works out the
|
|
@@ -380,7 +886,7 @@ on the board, and there is nothing to set up: the skill that does the writing sh
|
|
|
380
886
|
package, the same way `/k0-import` does.
|
|
381
887
|
|
|
382
888
|
It is written **in your language**, without a setting anywhere, because it is written out of your
|
|
383
|
-
own commit messages and
|
|
889
|
+
own commit messages and story titles.
|
|
384
890
|
|
|
385
891
|
Nothing is saved. Every time you open the page it is written again, and changing the window
|
|
386
892
|
writes it again — which is why there is no stale summary to clear and no history to prune.
|
|
@@ -390,20 +896,142 @@ saying why the rest is missing.
|
|
|
390
896
|
|
|
391
897
|
---
|
|
392
898
|
|
|
899
|
+
## What's New
|
|
900
|
+
|
|
901
|
+
k0 updates by having its files replaced under it. You restart, everything looks the same, and
|
|
902
|
+
whatever changed is in a file called `CHANGELOG.md` that nobody opens. So the version you are
|
|
903
|
+
running drifts away from the one you learned, and the new thing sits there unused because you
|
|
904
|
+
never found out it was there.
|
|
905
|
+
|
|
906
|
+
A small **mark appears next to `k0`** in the top bar for exactly two reasons: k0 moved on while you
|
|
907
|
+
were not looking, or npm says there is a version newer than the one installed here. Hover it and it
|
|
908
|
+
says which. **It never opens the page by itself** — it sits next to the name and waits, and it goes
|
|
909
|
+
out when you have read the page, not when you close the tab.
|
|
910
|
+
|
|
911
|
+
The page says which two versions it stands between — *you had k0 0.3.1, you are running 0.4.0 now,
|
|
912
|
+
two versions later* — and then says what that means in prose, written by your own Claude out of the
|
|
913
|
+
changelog entries in between. Two controls, and both of them change who it is being written for
|
|
914
|
+
rather than what is in it: **the language**, and **how technical** — `Plain`, `Normal` or `Nerd`.
|
|
915
|
+
Both are remembered, because coming back to find the page in a language you do not read is the
|
|
916
|
+
whole page wasted.
|
|
917
|
+
|
|
918
|
+
Underneath, folded open from the first moment, are the changelog entries themselves, exactly as
|
|
919
|
+
they were written. While the prose is being written they are what there is to read; afterwards they
|
|
920
|
+
are what you check it against.
|
|
921
|
+
|
|
922
|
+
It is the same machinery as the ChangeLog, and it has the same shape: nothing is stored, no model
|
|
923
|
+
of k0's own, no key and no account — the Claude Code you already pay for does the writing, on this
|
|
924
|
+
machine. Nothing is downloaded either. k0 cannot update itself; the most it can do is say a newer
|
|
925
|
+
version exists, and leave `npx k0-board@latest` to you.
|
|
926
|
+
|
|
927
|
+
---
|
|
928
|
+
|
|
929
|
+
## Usage: what your sessions consumed
|
|
930
|
+
|
|
931
|
+
The icon with three bars, next to the ChangeLog's, opens a page that answers a question Claude Code
|
|
932
|
+
leaves you to guess at: **where did the week go?** You switch between models, between efforts,
|
|
933
|
+
between one agent and a whole workflow, and between accounts, and the only thing you ever see is a
|
|
934
|
+
limit arriving.
|
|
935
|
+
|
|
936
|
+
A week at a time, Monday to Sunday, with the arrows to go back:
|
|
937
|
+
|
|
938
|
+
- **what each day would have cost at the API price list**, stacked by model. With a subscription
|
|
939
|
+
you do not pay this — it is the one scale on which a Fable hour and a Sonnet hour can be put side
|
|
940
|
+
by side, and the page says so;
|
|
941
|
+
- **how full each account's weekly limit was**, as a line per account, and the five-hour limit as
|
|
942
|
+
it was last seen;
|
|
943
|
+
- the week split **by model and effort** (fast mode is a row of its own), by **who did the work** —
|
|
944
|
+
the conversation itself, its subagents, or a workflow's agents — by **repository** and by
|
|
945
|
+
**account**;
|
|
946
|
+
- and every **session**, the most expensive first: the model and effort it ran on, when it started,
|
|
947
|
+
how long Claude actually worked on your turns (not how long the window was open), its tokens, its
|
|
948
|
+
cost, its estimated share of the weekly limit, and how many times a limit stopped it. A session k0
|
|
949
|
+
started or imported links to its story, which opens on the board.
|
|
950
|
+
|
|
951
|
+
**It costs nothing to find out.** No model is asked and nothing goes over the network: Claude Code
|
|
952
|
+
already writes every reply's token counts, model and effort into the transcripts on your disk, and
|
|
953
|
+
k0 reads them as they grow — the history first, a few megabytes at a time so the board never
|
|
954
|
+
stalls, and after that once a minute. The first time, the page says how much history is still left
|
|
955
|
+
to read.
|
|
956
|
+
|
|
957
|
+
Two things are not in the transcripts, and the page is straight about both:
|
|
958
|
+
|
|
959
|
+
- **Which account a reply came from.** Claude Code only records the account signed in *now*. k0
|
|
960
|
+
writes down every change of account it sees from the moment it is running, and the statusline
|
|
961
|
+
snippet below writes down the account of every session it draws. Everything before that stays
|
|
962
|
+
**"Unknown account"** — it is not guessed.
|
|
963
|
+
- **How full the limits are.** Claude Code tells the statusline and keeps it nowhere else. So the
|
|
964
|
+
statusline has to write it down:
|
|
965
|
+
|
|
966
|
+
### The limits: a few lines in your statusline
|
|
967
|
+
|
|
968
|
+
If you have a statusline command, add this to it, where it has read Claude Code's JSON from standard
|
|
969
|
+
input into `input` (Node, no packages; the same idea works in any language). It appends a line to
|
|
970
|
+
`~/.k0/usage/limits.jsonl` only when a number has changed, and never breaks the bar if anything
|
|
971
|
+
fails:
|
|
972
|
+
|
|
973
|
+
```js
|
|
974
|
+
try {
|
|
975
|
+
const fs = require('fs'), path = require('path'), os = require('os')
|
|
976
|
+
const data = JSON.parse(input), rl = data.rate_limits
|
|
977
|
+
if (rl && (rl.five_hour || rl.seven_day)) {
|
|
978
|
+
const pick = (w) => (w ? { pct: w.used_percentage, resets_at: w.resets_at } : null)
|
|
979
|
+
const now = { five_hour: pick(rl.five_hour), seven_day: pick(rl.seven_day) }
|
|
980
|
+
const dir = path.join(os.homedir(), '.k0', 'usage'), seen = path.join(dir, '.last')
|
|
981
|
+
const sig = JSON.stringify([data.session_id, now])
|
|
982
|
+
let last = ''
|
|
983
|
+
try { last = fs.readFileSync(seen, 'utf8') } catch {}
|
|
984
|
+
if (sig !== last) {
|
|
985
|
+
const a = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.claude.json'), 'utf8')).oauthAccount || {}
|
|
986
|
+
const account = { uuid: a.accountUuid, email: a.emailAddress, org_type: a.organizationType, tier: a.organizationRateLimitTier }
|
|
987
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
988
|
+
fs.appendFileSync(path.join(dir, 'limits.jsonl'),
|
|
989
|
+
JSON.stringify({ at: Date.now(), session_id: data.session_id, account, model: data.model?.id, ...now }) + '\n')
|
|
990
|
+
fs.writeFileSync(seen, sig)
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
} catch {}
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
Claude Code only passes the limits to the statusline on a subscription, and only after the first
|
|
997
|
+
reply of a session. Without the snippet the page works the same, with the limits chart empty and a
|
|
998
|
+
note saying why.
|
|
999
|
+
|
|
1000
|
+
The share of the weekly limit next to each session is an **estimate**, and marked with `≈`: the
|
|
1001
|
+
statusline says how full the week is, not who filled it, so each rise is shared among the sessions
|
|
1002
|
+
that account ran in that hour, in proportion to their cost.
|
|
1003
|
+
|
|
1004
|
+
The prices are Anthropic's published API rates, dated in the source. A model k0 does not have a
|
|
1005
|
+
price for is counted in tokens and shown as `?` in dollars — never as free.
|
|
1006
|
+
|
|
1007
|
+
---
|
|
1008
|
+
|
|
393
1009
|
## The files of a session
|
|
394
1010
|
|
|
395
1011
|
The git mark is also the door: clicking it opens a file viewer **in another tab**, and the board
|
|
396
1012
|
stays where it is. Where there is no mark — a repository without git, or git that has not answered
|
|
397
|
-
yet — a **lens** takes its place, so every
|
|
1013
|
+
yet — a **lens** takes its place, so every story and every column still leads in.
|
|
398
1014
|
|
|
399
1015
|
Files on the left, what they say on the right, and a divider in between that you can drag.
|
|
400
1016
|
|
|
401
|
-
**
|
|
402
|
-
real repository code is 95% of the files, and among two thousand `.tsx` files the document you
|
|
1017
|
+
**Documents are what is listed** — markdown, html, text, PDF, Word: things you read and print. In
|
|
1018
|
+
a real repository code is 95% of the files, and among two thousand `.tsx` files the document you
|
|
403
1019
|
were after cannot be found. This closes nothing off: a code file reached by a link inside a
|
|
404
|
-
document still opens, and so do images.
|
|
1020
|
+
document still opens, and so do images — and the configuration is one switch away, below.
|
|
1021
|
+
|
|
1022
|
+
A **generated directory** — `out/`, `dist/`, `build/` — is walked into like any other, and the
|
|
1023
|
+
documents in it are listed like any others: the PDFs, and the pages you open with a double click.
|
|
1024
|
+
A document is a document wherever it was made, and it has to be findable by name. What stays out
|
|
1025
|
+
is the configuration a build leaves lying there, and the directories that hold nothing anybody
|
|
1026
|
+
reads — `node_modules` and its like — which are not walked into at all.
|
|
1027
|
+
|
|
1028
|
+
There is **one exception, and only one**: where git is in charge, git decides. k0 reads a
|
|
1029
|
+
directory your `.gitignore` names only to go and fetch the finished documents from it — the PDFs,
|
|
1030
|
+
the Word files — never the pages, because a real site's ignored `dist/` is four thousand pages and
|
|
1031
|
+
not one of them is the file you went looking for. Where git names the directory itself, everything
|
|
1032
|
+
in it comes through, pages included.
|
|
405
1033
|
|
|
406
|
-
|
|
1034
|
+
At the top come the **folders**, then the files, in three groups:
|
|
407
1035
|
|
|
408
1036
|
- **Changed** — what this session has touched: files still hanging in the working tree plus the
|
|
409
1037
|
ones inside commits made since it started.
|
|
@@ -411,19 +1039,91 @@ The listing is flat, in three groups:
|
|
|
411
1039
|
no git.
|
|
412
1040
|
- **All files** — everything else, in path order.
|
|
413
1041
|
|
|
1042
|
+
### Searching
|
|
1043
|
+
|
|
414
1044
|
The search at the top looks in two places and keeps them apart:
|
|
415
1045
|
|
|
416
|
-
- **Names** — not the exact word, but the letters you type in the order you type them
|
|
417
|
-
finds `docs/audit-report.md`. It filters as you type, asking the
|
|
1046
|
+
- **Names** — not the exact word, but the letters you type in the order you type them, **inside
|
|
1047
|
+
the file's own name**: `audrep` finds `docs/audit-report.md`. It filters as you type, asking the
|
|
1048
|
+
server nothing. The directory is never searched — it used to be, and `.env` would turn up a
|
|
1049
|
+
`v1.0-ROADMAP.md` that merely had those four letters scattered across its folder, three of them
|
|
1050
|
+
in a name nobody was reading. The letters that matched are **underlined**, so every row says why
|
|
1051
|
+
it is there: `aud`it-`rep`ort reads as the two words you meant.
|
|
418
1052
|
- **In the text** — inside the documents, with the line the word appears on and the word
|
|
419
|
-
highlighted. Because what you remember about a file is what was in it, not what it was
|
|
420
|
-
Accents do not need typing — `cafe` finds `café`.
|
|
1053
|
+
highlighted in yellow. Because what you remember about a file is what was in it, not what it was
|
|
1054
|
+
called. Accents do not need typing — `cafe` finds `café`.
|
|
1055
|
+
|
|
1056
|
+
The two marks are different on purpose: a line under the letters means they are in the file's
|
|
1057
|
+
name, yellow means the word was found inside the file.
|
|
421
1058
|
|
|
422
1059
|
There is no index. The documents are read every time: a few hundred files of a few KB, all
|
|
423
1060
|
already in the operating system's cache. An index would cost more and go stale.
|
|
424
1061
|
|
|
425
1062
|
`/` puts the cursor in the search, arrows scroll, Enter opens, Esc clears.
|
|
426
1063
|
|
|
1064
|
+
### Going into a folder
|
|
1065
|
+
|
|
1066
|
+
Click a folder and the listing narrows to it: the folders inside it first, then its files. At the
|
|
1067
|
+
top the path is written out one piece at a time, and **every piece is a way back up** — from
|
|
1068
|
+
`docs/backlog/handover` you get to `docs` in one click, and to the whole repository by clicking
|
|
1069
|
+
the repository's name. The path above an open document works the same way, so from a file you can
|
|
1070
|
+
step into the folder it lives in.
|
|
1071
|
+
|
|
1072
|
+
The arrows walk folders like anything else and Enter goes in; Esc comes back out. A folder is a
|
|
1073
|
+
real link, so ⌘/Ctrl-click opens it in another tab, and the address follows you: reload it and
|
|
1074
|
+
you are still where you were.
|
|
1075
|
+
|
|
1076
|
+
Next to it is a button that hands the folder to your **file manager** — the Finder on a Mac,
|
|
1077
|
+
Explorer on Windows, whatever your desktop uses on Linux. Every file has the same button in the
|
|
1078
|
+
row above it, and there it points the file out inside its folder rather than opening it. On a
|
|
1079
|
+
system where k0 has no way to do that, the button stays where it is, greyed out, with the reason
|
|
1080
|
+
in its tooltip.
|
|
1081
|
+
|
|
1082
|
+
### The `config` switch, beside the search
|
|
1083
|
+
|
|
1084
|
+
The viewer lists documents. The one thing that was missing from that is **configuration**: an
|
|
1085
|
+
`.env` you want to check a key in, the `package.json`, a workflow's YAML. They are not documents,
|
|
1086
|
+
and in a repository of prose they would be noise — so they live behind a switch, the **`config`**
|
|
1087
|
+
button to the right of the search box.
|
|
1088
|
+
|
|
1089
|
+
Switch it on and `.env` (and `.env.local`, and the rest of them), `.json`, `.yml`, `.yaml`,
|
|
1090
|
+
`.toml` and `.ini` join the listing, the name search and the search inside the text. **Including
|
|
1091
|
+
the ones git is told to ignore** — an `.env` is ignored by definition, and it is the file you came
|
|
1092
|
+
for. Code does not join: `.js`, `.py`, `.css` stay out either way.
|
|
1093
|
+
|
|
1094
|
+
The switch is remembered, per browser. It is not a search, it is a way of working.
|
|
1095
|
+
|
|
1096
|
+
And if you forget it is off, the search says so: when a hidden configuration file would have come
|
|
1097
|
+
**above** everything on screen — searching `.env` in a repository that has one — a line appears at
|
|
1098
|
+
the top of the results saying how many, and clicking it turns the switch on. Only then: a hidden
|
|
1099
|
+
file that merely matches somewhere does not raise it, or the line would be there on every search
|
|
1100
|
+
and you would stop seeing it.
|
|
1101
|
+
|
|
1102
|
+
Each of them opens as the kind of thing it is:
|
|
1103
|
+
|
|
1104
|
+
- a **JSON** file becomes a tree that folds, coloured by type, with the first two levels open;
|
|
1105
|
+
- an **.env** becomes a table of names and values, comments and all;
|
|
1106
|
+
- **YAML, TOML and INI** keep their shape, with keys, values and comments told apart by colour.
|
|
1107
|
+
|
|
1108
|
+
A JSON tree has its **own search box**, and that is not a duplicate of the browser's: the
|
|
1109
|
+
browser's find does not look inside a branch that is closed, so on a folded tree ⌘F says "not
|
|
1110
|
+
found" for something three lines away. This one counts what it found and opens the branches
|
|
1111
|
+
holding it.
|
|
1112
|
+
|
|
1113
|
+
### Editing a file
|
|
1114
|
+
|
|
1115
|
+
Configuration and notes can be changed from here: `.env` and the rest of the configuration above,
|
|
1116
|
+
plus `.md` and `.txt`. Click the **pencil** in the row above the document and the file becomes a
|
|
1117
|
+
text box as tall as the pane — not a small window over it, because a README does not fit in one.
|
|
1118
|
+
**Save** (or ⌘/Ctrl+S) writes it; **Cancel** goes back to what is on disk.
|
|
1119
|
+
|
|
1120
|
+
Nothing else is editable: no code, no PDFs, no images, and no creating or deleting files. That is
|
|
1121
|
+
what you opened the repository with Claude for.
|
|
1122
|
+
|
|
1123
|
+
If the file **changed on disk** while you were editing — a session wrote it, or you did, in
|
|
1124
|
+
another window — the save stops and says so, and what you typed stays where it is. k0 will not
|
|
1125
|
+
quietly write over somebody else's work.
|
|
1126
|
+
|
|
427
1127
|
### Pasting a chunk of chat
|
|
428
1128
|
|
|
429
1129
|
There is a way to reach files that does not go through searching for them. When a session ends,
|
|
@@ -431,9 +1131,14 @@ the summary in the chat says what it touched and **names the files already**. Cl
|
|
|
431
1131
|
the top, paste that piece of conversation, press **Find the files**, and the list on the left
|
|
432
1132
|
narrows to the files that text names.
|
|
433
1133
|
|
|
434
|
-
It looks **only for the names written down**, not for the subject: no index
|
|
435
|
-
|
|
436
|
-
|
|
1134
|
+
It looks **only for the names written down**, not for the subject: no index and no waiting — the
|
|
1135
|
+
file listing is already in the browser. The price is stated: a file the chat talks about without
|
|
1136
|
+
ever naming does not come out, and for that there is the search above.
|
|
1137
|
+
|
|
1138
|
+
One question does go out, and only one: when the text writes a name **in full** and the listing has
|
|
1139
|
+
no such file, the disk is asked about those names and no others. That is how a document under an
|
|
1140
|
+
ignored directory comes out of a paste — the listing never saw it, but a text naming a file names
|
|
1141
|
+
it whole.
|
|
437
1142
|
|
|
438
1143
|
The results come in two groups, because they are two different degrees of certainty:
|
|
439
1144
|
|
|
@@ -464,10 +1169,45 @@ The hard part is not finding the names, it is choosing **which**. In a repositor
|
|
|
464
1169
|
directory up, and so on to the top. If it is still ambiguous, **it does not become a link**:
|
|
465
1170
|
better nothing than sending you to the wrong README.
|
|
466
1171
|
|
|
467
|
-
Files the listing does **not** show open too.
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
stay out: `.claude/` is configuration, not something to read.
|
|
1172
|
+
Files the listing does **not** show open too. Where git rules, a directory your `.gitignore` names
|
|
1173
|
+
gives the listing only its finished documents — so a page under an ignored `dist/` is not in it.
|
|
1174
|
+
Named inside a document it still counts: the document said so, not the directory. Hidden
|
|
1175
|
+
directories really do stay out: `.claude/` is configuration, not something to read.
|
|
1176
|
+
|
|
1177
|
+
### What Claude points at, one click away
|
|
1178
|
+
|
|
1179
|
+
The same idea, one step earlier: in the Claude Code session itself. Claude says "open
|
|
1180
|
+
`localhost:4321/projects/furniture/`", "the photos are in `docs/projects/sideboard-140/`", "the
|
|
1181
|
+
manual is `README.md`", or publishes an artifact and talks about it by its title — and in the
|
|
1182
|
+
terminal all of that was dead text. With the `k0-links` mod installed, and **while k0 is running**,
|
|
1183
|
+
everything the last reply pointed at is in a row **just above the prompt**, and **one plain click**
|
|
1184
|
+
on an entry opens it:
|
|
1185
|
+
|
|
1186
|
+
| | What the reply wrote | Opens in |
|
|
1187
|
+
|---|---|---|
|
|
1188
|
+
| 🌐 | an address — `https://…`, `localhost:4321/…`, `alessioragni.com/projects/…` | the browser, in a new tab |
|
|
1189
|
+
| 📁 | a folder, relative to the repository or written in full | Finder |
|
|
1190
|
+
| 📄 | a document the viewer shows — Markdown, HTML, text, PDF, Word… | this viewer, in a new tab |
|
|
1191
|
+
| ✦ | the title of an artifact this session published | its claude.ai page |
|
|
1192
|
+
|
|
1193
|
+
Code files and a repository's own name stay out of the row: they are not places you go to. A
|
|
1194
|
+
domain counts as an address only with a path after it — `alessioragni.com` alone is usually the
|
|
1195
|
+
name of a repository.
|
|
1196
|
+
|
|
1197
|
+
**Claude's reply is left exactly as Claude Code draws it.** The macOS Terminal cannot open a link
|
|
1198
|
+
drawn inside the text — it shows the words, and a click does nothing — and redrawing every reply to
|
|
1199
|
+
get around that would have changed a screen that works. The row is the mod's own space, and its
|
|
1200
|
+
entries are buttons, which Claude Code itself receives the click for. That needs Claude Code's
|
|
1201
|
+
**fullscreen** view (`"tui": "fullscreen"` in `~/.claude/settings.json`, or `/config`), where the
|
|
1202
|
+
mouse reaches it; in the classic view the row is still there, and ctrl+x tab then Enter opens an
|
|
1203
|
+
entry.
|
|
1204
|
+
|
|
1205
|
+
It is a **mod**, a small piece of code Claude Code runs inside itself, and the installer copies it
|
|
1206
|
+
into `~/.claude/skills/k0-links` together with the commands, behind the same question. So it is
|
|
1207
|
+
there in **every** Claude Code session on the machine, not only the ones a story opened — new
|
|
1208
|
+
sessions pick it up when they start, an open one with `/reload-plugins` — and it does nothing at
|
|
1209
|
+
all while k0 is off. Documents become entries only in **a repository k0 knows**; elsewhere the
|
|
1210
|
+
addresses, folders and artifacts still do.
|
|
471
1211
|
|
|
472
1212
|
### On paper
|
|
473
1213
|
|
|
@@ -493,11 +1233,11 @@ kernel's own verdict, plus one added rule: amber when memory in use goes over 90
|
|
|
493
1233
|
the whole picture, including **what is heavy and is not k0**: if the machine is struggling because
|
|
494
1234
|
of Chrome it is fair to know that, instead of closing sessions for nothing.
|
|
495
1235
|
|
|
496
|
-
On every
|
|
1236
|
+
On every story there is **what that session weighs**. Not the `claude` process: everything it has
|
|
497
1237
|
dragged along — the MCP servers, the Chromes they open, a `tsc` started from a commit hook. That
|
|
498
|
-
is where the memory goes, and it is the thing no other tool can attribute to the right
|
|
1238
|
+
is where the memory goes, and it is the thing no other tool can attribute to the right story.
|
|
499
1239
|
|
|
500
|
-
Only one
|
|
1240
|
+
Only one story is red, the heaviest, and only while the machine is struggling: if they were all
|
|
501
1241
|
red they would say nothing.
|
|
502
1242
|
|
|
503
1243
|
Two things said plainly. The CPU is the CPU of **right now**, worked out from the difference in
|
|
@@ -506,7 +1246,7 @@ which on an old session says nothing about this minute. And summing the memory o
|
|
|
506
1246
|
counts shared memory twice, so the total is a little generous: it is the usual approximation, and
|
|
507
1247
|
it is the right one for the question that matters — which one do I close to feel better.
|
|
508
1248
|
|
|
509
|
-
And once you have decided, **`Close` on that
|
|
1249
|
+
And once you have decided, **`Close` on that story is how you give the memory back**: the session
|
|
510
1250
|
is stopped and its window goes, the work stays on the board as it was, and `Resume` picks the
|
|
511
1251
|
conversation up where it left off. Nothing has to be declared finished to stop weighing.
|
|
512
1252
|
|
|
@@ -514,6 +1254,40 @@ Reading the process table costs little on a calm machine and a lot on a struggli
|
|
|
514
1254
|
exactly when you look at it. So it is sampled every three seconds, and **only while the board is
|
|
515
1255
|
open**.
|
|
516
1256
|
|
|
1257
|
+
### And what k0 costs
|
|
1258
|
+
|
|
1259
|
+
The chip measured everybody but itself, which is the one thing a program running under launchd for
|
|
1260
|
+
weeks should be least able to hide. Hover it and the last line is **k0's own weight, its CPU, how
|
|
1261
|
+
often it asks git anything, how many queries it is holding, and how hard the watching loop is
|
|
1262
|
+
currently running**.
|
|
1263
|
+
|
|
1264
|
+
That loop is the whole of k0's cost, and it now runs at the pace the work deserves. With a session
|
|
1265
|
+
open — or with you in front of the board — it goes round every two seconds. With neither, there is
|
|
1266
|
+
nothing it could see change, so it drops to **once a minute** and k0 stops costing anything on a
|
|
1267
|
+
machine nobody is using. Pressing anything wakes it at once, so nothing ever waits on it.
|
|
1268
|
+
|
|
1269
|
+
The git marks follow the same rule. Every repository on the board used to be asked `status` and
|
|
1270
|
+
`rev-list` every five seconds, all night; now the full list is only asked while you are looking,
|
|
1271
|
+
away from the board only the repositories a session is actually working in, and a reading is good
|
|
1272
|
+
for half a minute. Nothing in a repository changes faster than that unless you make it.
|
|
1273
|
+
|
|
1274
|
+
### And what the page downloads
|
|
1275
|
+
|
|
1276
|
+
The other half of the bill is paid by the browser, and it was the larger one. The board asked for
|
|
1277
|
+
everything k0 knows once a second and got it: two thirds of a megabyte, six hundred stories with
|
|
1278
|
+
their whole "Why" and their whole plan, most of them finished weeks ago and hidden from view. Over
|
|
1279
|
+
a day with one tab open that came to **fifty-six gigabytes**, to draw post-its that had not moved.
|
|
1280
|
+
|
|
1281
|
+
Now the board sends back a stamp of the answer it already has, and when the answer would be the
|
|
1282
|
+
same — which on a board nobody is touching is every round of every day — the server says so in a
|
|
1283
|
+
couple of hundred bytes and sends nothing else. When something really did change, what goes out is
|
|
1284
|
+
only what a post-it draws, compressed. The long texts come with the story's own panel, when you
|
|
1285
|
+
open one, where they were always read from anyway.
|
|
1286
|
+
|
|
1287
|
+
A still board also stops asking so often: after a few rounds saying nothing moved it drops to one
|
|
1288
|
+
in four seconds, and the first thing that moves — or your coming back to the tab — puts it
|
|
1289
|
+
straight back to one.
|
|
1290
|
+
|
|
517
1291
|
### And the ones you forget, k0 closes for you
|
|
518
1292
|
|
|
519
1293
|
The paragraph above assumes you noticed. Most of the time nobody does: the window that is costing
|
|
@@ -521,7 +1295,7 @@ you a gigabyte is the one you stopped thinking about yesterday. So **after twelv
|
|
|
521
1295
|
nothing happening, k0 does that `Close` itself** — the session is stopped, its window goes, and the
|
|
522
1296
|
memory comes back.
|
|
523
1297
|
|
|
524
|
-
Nothing is lost by it. The
|
|
1298
|
+
Nothing is lost by it. The story stays exactly where it is with the status it had, and **Resume**
|
|
525
1299
|
picks the conversation up where it was. That is the whole reason this is safe: a closed terminal
|
|
526
1300
|
has never been a lost session.
|
|
527
1301
|
|
|
@@ -537,12 +1311,12 @@ rest is left alone, and each for its own reason:
|
|
|
537
1311
|
there may be a command of yours running in it; k0 cannot see what it is, so k0 does not touch it.
|
|
538
1312
|
On the board it reads as yellow like any other, which is exactly why this one has to be said.
|
|
539
1313
|
|
|
540
|
-
And a window you were using an hour ago is never closed, whatever the
|
|
1314
|
+
And a window you were using an hour ago is never closed, whatever the story's history says. k0 has
|
|
541
1315
|
four clocks for a session — two of its own and two Claude Code keeps — and **the newest one wins**.
|
|
542
1316
|
Being wrong in that direction leaves a window open until tomorrow; being wrong the other way closes
|
|
543
1317
|
a terminal you were about to go back to.
|
|
544
1318
|
|
|
545
|
-
A
|
|
1319
|
+
A story k0 tidied away says so: where one you closed yourself reads *session closed*, this one reads
|
|
546
1320
|
*closed automatically*. Same italic, same place, one word different.
|
|
547
1321
|
|
|
548
1322
|
And the memory chip at the end of the top bar says it is watching, and from when: **RAM 79% · CPU
|
|
@@ -561,17 +1335,17 @@ settings file changes it, and **`0` switches it off** — see below.
|
|
|
561
1335
|
|
|
562
1336
|
An empty board is no help in getting your bearings. The installer offers to do this on the first
|
|
563
1337
|
run; afterwards, `/k0-import` from a Claude Code session picks up the sessions that already
|
|
564
|
-
happened — including the ones opened by hand, outside k0 — and puts them on the board as
|
|
1338
|
+
happened — including the ones opened by hand, outside k0 — and puts them on the board as stories:
|
|
565
1339
|
the last 14 days, at most the 10 most recent per repository. `/k0-import 30 5` changes the two
|
|
566
1340
|
numbers.
|
|
567
1341
|
|
|
568
1342
|
The difference between the two is the writing. The installer uses the name the session already
|
|
569
1343
|
had, or the first few words of the first prompt. `/k0-import` has Claude read the conversation and
|
|
570
1344
|
write a title and a description in the language it was held in. That description is the line in
|
|
571
|
-
italics under the title on the note, and importing is the only thing that writes one: a
|
|
1345
|
+
italics under the title on the note, and importing is the only thing that writes one: a story you
|
|
572
1346
|
write yourself has a title and a prompt, which is all it needs.
|
|
573
1347
|
|
|
574
|
-
Imported
|
|
1348
|
+
Imported stories are born yellow — *Your turn*: **Resume** reopens the conversation where it was,
|
|
575
1349
|
**Done** clears it away. Being dead sessions they do not light the tray icon. Running it again
|
|
576
1350
|
skips the ones already imported.
|
|
577
1351
|
|
|
@@ -584,8 +1358,12 @@ real machine that separated 145 genuine sessions from 867 automated ones, and it
|
|
|
584
1358
|
|
|
585
1359
|
## The statuses
|
|
586
1360
|
|
|
587
|
-
A
|
|
588
|
-
the
|
|
1361
|
+
A story **is** the colour of its status — there is nothing else to read. On the left is the code
|
|
1362
|
+
k0 speaks internally — the API, the menu bar icon and the colours in `web/base.css` all say these
|
|
1363
|
+
seven words — then how it reads on screen. None of the seven is a column in the database: `BACKLOG`
|
|
1364
|
+
and `COMPLETED` are worked out from the story (no session, and closed), and the other five belong
|
|
1365
|
+
to the live session, not to the story. See [`docs/database.md`](docs/database.md) for where each
|
|
1366
|
+
half really lives.
|
|
589
1367
|
|
|
590
1368
|
| | | | |
|
|
591
1369
|
|---|---|---|---|
|
|
@@ -607,12 +1385,12 @@ How awake the machine has to stay while sessions are working. It is a **scale of
|
|
|
607
1385
|
four switches: each includes the one before it, and exactly **one** is always lit. Clicking the lit
|
|
608
1386
|
one again does nothing — you leave a mode, you do not switch it off.
|
|
609
1387
|
|
|
610
|
-
| Icon | Mode | The machine | The screen | The text |
|
|
1388
|
+
| Icon | Mode | The machine | The screen | The text and the windows |
|
|
611
1389
|
|---|---|---|---|---|
|
|
612
1390
|
| two **z** | **Sleep** | sleeps as it normally would | goes off | normal |
|
|
613
1391
|
| a **palm tree** | **Away** | does not sleep, not even with the lid closed | may sleep and lock | normal |
|
|
614
1392
|
| a **nerd face** with glasses | **Nerd** | does not sleep | **stays on** | normal |
|
|
615
|
-
| a **car** | **Driving** | does not sleep | **stays on** | **large
|
|
1393
|
+
| a **car** | **Driving** | does not sleep | **stays on** | **large**: the text here and in the terminals, and the terminals fill the screen |
|
|
616
1394
|
|
|
617
1395
|
The four icons do not describe the machine: they describe **where you are**. Asleep, away, at the
|
|
618
1396
|
desk, watching from across the room. That is where the order comes from, and it is why the second
|
|
@@ -622,9 +1400,9 @@ one is a palm tree and not a technical symbol: the mode does not say "the machin
|
|
|
622
1400
|
The four buttons are at the end of the board's bar, or four ticked entries in the tray menu. They
|
|
623
1401
|
are the same control: changed on one side, the other catches up within a couple of seconds.
|
|
624
1402
|
|
|
625
|
-
**Nerd** and **Driving** do exactly the same things to the machine: the only difference is
|
|
626
|
-
|
|
627
|
-
room".
|
|
1403
|
+
**Nerd** and **Driving** do exactly the same things to the machine: the only difference is how big
|
|
1404
|
+
everything is — the text, and the terminal windows it sits in. Nerd is "I am sitting here
|
|
1405
|
+
programming", Driving is "I glance at it from across the room".
|
|
628
1406
|
|
|
629
1407
|
### Why an idle inhibitor is not enough
|
|
630
1408
|
|
|
@@ -648,7 +1426,7 @@ it does not do.
|
|
|
648
1426
|
no business rewriting behind your back. The switch reports itself unavailable, and `k0-board
|
|
649
1427
|
doctor` says where to change it yourself.
|
|
650
1428
|
|
|
651
|
-
### Large text, and windows
|
|
1429
|
+
### Large text, and windows to match
|
|
652
1430
|
|
|
653
1431
|
In Driving the **text inside the terminals** goes from the profile's size to 22, the board's from
|
|
654
1432
|
17 to 22 pixels, and the **things you click** grow too — the `+`, the git lens, the corner pencil
|
|
@@ -660,16 +1438,27 @@ they reorder by urgency, reddest to the left. On a screen you glance at, two or
|
|
|
660
1438
|
visible at a time and the most urgent one has to come to you. Full screen you have them all in
|
|
661
1439
|
front of you already, and a board that reshuffles itself while you work only loses your place.
|
|
662
1440
|
|
|
663
|
-
**The windows
|
|
664
|
-
|
|
665
|
-
|
|
1441
|
+
**The windows grow with the text.** In Driving a terminal takes the whole free screen; leave
|
|
1442
|
+
Driving and it goes back to the usual 86% centred, with the text back at the profile's size. It is
|
|
1443
|
+
one gesture and not two, and it lands on the terminals **already open**, not only on the ones you
|
|
1444
|
+
open next.
|
|
1445
|
+
|
|
1446
|
+
It used to be the opposite, and the reason is worth keeping in mind: Terminal.app holds rows and
|
|
1447
|
+
columns when the font changes and resizes the window to match — going from 12 to 22 turns a 700×500
|
|
1448
|
+
window into 1378×856, measured — so k0 read each window's own bounds first and put them back, and
|
|
1449
|
+
nothing moved. What that left behind was a window holding 22 point text in a box measured for 12.
|
|
1450
|
+
Half a gesture is worse than none, so the size of the text and the size of the window now travel
|
|
1451
|
+
together, and the price is said plainly: **a window you had dragged onto another screen comes back
|
|
1452
|
+
to the middle of the main one.**
|
|
666
1453
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
1454
|
+
**All of them, every time.** k0 asks Terminal once for the windows it has open and changes those
|
|
1455
|
+
that are its own, rather than asking after every window id it has ever written down. On a board
|
|
1456
|
+
with two hundred stories almost every one of those ids names a window closed weeks ago, and asking
|
|
1457
|
+
after them one at a time took seven seconds — long enough to be cut short halfway, which left half
|
|
1458
|
+
the terminals large, half of them small, and nothing said about it anywhere. Walking the windows
|
|
1459
|
+
that exist takes about a second and does not grow with the board.
|
|
671
1460
|
|
|
672
|
-
k0 touches **only its own windows**, the ones born from a
|
|
1461
|
+
k0 touches **only its own windows**, the ones born from a story.
|
|
673
1462
|
|
|
674
1463
|
### What it remembers, and what it looks at
|
|
675
1464
|
|
|
@@ -758,7 +1547,7 @@ Worth knowing:
|
|
|
758
1547
|
|
|
759
1548
|
Two side effects of the Cmd+V k0 uses to write your prompt, worth knowing:
|
|
760
1549
|
|
|
761
|
-
- the
|
|
1550
|
+
- the story's prompt replaces whatever was on your clipboard (if the paste fails, the clipboard is
|
|
762
1551
|
put back);
|
|
763
1552
|
- to paste, the terminal is brought to the front for an instant: if you happen to be **dictating**
|
|
764
1553
|
at that moment, the dictation lands in there and sticks to the prompt.
|
|
@@ -787,7 +1576,7 @@ itself on the next round: nothing to restart.
|
|
|
787
1576
|
|
|
788
1577
|
| | |
|
|
789
1578
|
|---|---|
|
|
790
|
-
| `closeIdleTerminalsAfterHours` | How long a yellow
|
|
1579
|
+
| `closeIdleTerminalsAfterHours` | How long a yellow story's terminal may sit there before k0 closes it and gives the memory back. `12` if you say nothing. **`0` switches it off.** Anything under an hour is treated as an hour — below that this stops being a tidy-up and starts closing windows while you are using them. |
|
|
791
1580
|
|
|
792
1581
|
Delete a line to go back to its default; a file k0 cannot read is ignored altogether and the
|
|
793
1582
|
defaults hold, rather than k0 refusing to start over a stray comma.
|
|
@@ -815,46 +1604,103 @@ platform/
|
|
|
815
1604
|
shared/ what more than one of them needs: tmux, running commands, reading a process
|
|
816
1605
|
table, and reading who is holding which port
|
|
817
1606
|
server/
|
|
818
|
-
index.js the http server, the API, and the watching loop
|
|
1607
|
+
index.js the http server, the API, and the watching loop — every two seconds while a
|
|
1608
|
+
session is running or somebody is at the board, once a minute when neither, and
|
|
1609
|
+
awake at once on anything you press
|
|
819
1610
|
guard.js who is allowed to talk to this server at all: the Host and the Origin
|
|
820
|
-
db.js SQLite (node:sqlite): the
|
|
1611
|
+
db.js SQLite (node:sqlite): the only file that talks to it. epic, story, session,
|
|
1612
|
+
decision, round, check_item, dependency, session_event and the rest —
|
|
821
1613
|
docs/database.md
|
|
1614
|
+
backlog.js the model: epics, stories, tasks, decisions, dependencies, the order, and
|
|
1615
|
+
what to pick up next. Pure logic over db.js — no http, no disk
|
|
1616
|
+
mirror.js writes and re-reads <repo>/.k0/, the readable copy of the backlog. It writes
|
|
1617
|
+
nowhere else, ever, and a test proves it. No domain logic
|
|
1618
|
+
worktree.js a session working copy of its own: open it from the branch you are on, merge
|
|
1619
|
+
it back, destroy it. Never a push, never a pull request, never a conflict
|
|
1620
|
+
resolved for you, and it never runs tests or a build in there
|
|
1621
|
+
update.js the one request k0 makes — what npm says the newest version is — and the
|
|
1622
|
+
version jump that puts the mark next to k0 in the top bar
|
|
822
1623
|
paths.js where the board, the logs, the settings and the cache live
|
|
823
1624
|
settings.js the few things you can change, and the file that is the list of them —
|
|
824
1625
|
~/.k0/config.json, written out with everything in it and re-read when it changes
|
|
825
1626
|
idle.js which terminals have sat still long enough to be closed and given back. Only the
|
|
826
1627
|
deciding: it kills nothing, so every rule in it can be proved without a machine
|
|
827
1628
|
watcher.js reads Claude Code's own files and derives the statuses; also renames a session
|
|
1629
|
+
usage.js reads what every session consumed out of its transcripts, a few megabytes at a
|
|
1630
|
+
time and only what is new, plus the statusline's limit samples and which account
|
|
1631
|
+
is signed in; adds it up by the hour for the Usage page. Never asks a model
|
|
1632
|
+
prices.js the API price list the Usage page's dollars come from, dated; a model not on it
|
|
1633
|
+
has no price rather than a zero one
|
|
828
1634
|
git.js the only one that talks to git: what is committed, what is pushed, whose it is,
|
|
829
1635
|
and — for the ChangeLog — what the commits actually said
|
|
830
1636
|
changelog.js gathers what happened in a window, out of git and out of session_event. Decides
|
|
831
1637
|
which repositories are worth mentioning at all, and stores nothing
|
|
832
1638
|
writer.js hands those facts to the Claude Code already on this machine and gets the words
|
|
833
|
-
back. The only place k0 starts a model, and it never leaves the machine to do
|
|
1639
|
+
back. The only place k0 starts a model, and it never leaves the machine to do
|
|
1640
|
+
it. Keyed by skill and by window, so the ChangeLog and the What is New page can
|
|
1641
|
+
be writing at the same time without cancelling each other
|
|
834
1642
|
launcher.js starts and resumes sessions, through the platform's terminal
|
|
835
1643
|
servers.js the dev server of a repository: what starts it, whether it is up, and on what
|
|
836
1644
|
port. The only thing k0 starts that is meant to outlive k0
|
|
837
|
-
mode.js the four modes: how awake to keep the machine, and whether
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1645
|
+
mode.js the four modes: how awake to keep the machine, and whether text and windows go
|
|
1646
|
+
large. How large is `launcher.js`, which is what talks to the terminal
|
|
1647
|
+
projects.js the repositories, in the order you last used them — and which directories k0 is
|
|
1648
|
+
allowed to open at all, which is one answer and not one per endpoint
|
|
1649
|
+
sessions.js digs already-lived sessions out of the transcripts, to import as stories
|
|
1650
|
+
files.js the only one that reads the projects' disk — and the only one that writes back
|
|
1651
|
+
into it: what is there, what changed, what it says, and the one small write
|
|
1652
|
+
machine.js the only one that looks at processes and memory: what it all costs, and who is
|
|
1653
|
+
costing it — k0's own process included, which is the only honest way to publish
|
|
1654
|
+
a number like that
|
|
842
1655
|
pdf.js the document on paper, printed by a headless browser
|
|
843
|
-
web/ the
|
|
1656
|
+
web/ the four pages (html, css, js served exactly as they are)
|
|
844
1657
|
index.html the board — board.js, board.css, view.js. A note is never taller than it is
|
|
845
1658
|
wide: the title, the age and the buttons always show, the text in the middle is
|
|
846
1659
|
what gets clipped
|
|
1660
|
+
list.js the same stories as rows, list.css beside it: the other shape of the same page,
|
|
1661
|
+
not a page of its own. Handed the stories the board is already showing, so the
|
|
1662
|
+
filters cannot mean two things, and the story you open follows a live discussion
|
|
1663
|
+
by asking .../live once a second, the cadence the rest of k0 already uses
|
|
847
1664
|
files.html the file viewer — files.js, files.css
|
|
848
|
-
changelog.html what you have been doing — changelog.js, changelog.css.
|
|
849
|
-
|
|
850
|
-
|
|
1665
|
+
changelog.html what you have been doing — changelog.js, changelog.css. Read top to bottom
|
|
1666
|
+
instead of looked at, so it is one of the three pages that scroll
|
|
1667
|
+
whatsnew.html what changed in k0 between the version you had and this one — whatsnew.js,
|
|
1668
|
+
whatsnew.css. Reached from the mark next to k0, and never opened by itself
|
|
1669
|
+
base.css colours, fonts and scale: the house variables, shared by all of them
|
|
1670
|
+
awake.js the one place that repeats anything: a job that runs only while its tab is in
|
|
1671
|
+
front of you, and takes a fresh reading the moment you come back to it. A page
|
|
1672
|
+
nobody can see must not be asking the server anything — asking is also how the
|
|
1673
|
+
server learns somebody is watching
|
|
851
1674
|
md.js markdown laid out, written by hand because nothing here is compiled
|
|
852
1675
|
recency.js which repositories are still warm, and which fold away into `Old`
|
|
853
|
-
fuzzy.js searching the names: the letters you type, in the order you type them
|
|
1676
|
+
fuzzy.js searching the names: the letters you type, in the order you type them — the
|
|
1677
|
+
file viewer, the repository the new story goes in, and the repository menu on
|
|
1678
|
+
the bar, which is drawn here rather than left to the system
|
|
854
1679
|
mentions.js which of a repository's files a piece of text names
|
|
855
1680
|
refs.js what a name written inside a document points at, and which of the nine READMEs
|
|
1681
|
+
json.js a JSON file as a tree that folds, and the search that opens the right branches
|
|
1682
|
+
conf.js an .env as the table it always was, and YAML/TOML/INI with their parts told apart
|
|
856
1683
|
.claude/skills/
|
|
857
1684
|
k0-import/ the skill that fills the board with sessions you have already had
|
|
1685
|
+
k0-epic/ the long way in: rounds of questions, decisions, then a tree of stories
|
|
1686
|
+
k0-story/ one story, fast path, no ceremony
|
|
1687
|
+
k0-discuss/ an existing story, discussed in rounds until nothing more would change it
|
|
1688
|
+
k0-split/ a story too big to close, split into tasks that inherit its decisions
|
|
1689
|
+
k0-plan/ plan mode, with the standing decisions injected as constraints
|
|
1690
|
+
k0-work/ the worktree, the work, the Log as it goes, and the merge back
|
|
1691
|
+
k0-ultracode/ the manager: a plan cut into assignments, an agent and a worktree each, and every
|
|
1692
|
+
story tested and counter-checked before the next one starts
|
|
1693
|
+
k0-verify/ the counter-check: every decision one by one, the checklist, the outcome
|
|
1694
|
+
k0-next/ what to pick up now, and why — the server decides, not the model
|
|
1695
|
+
k0-order/ priority and dependencies, dictated
|
|
1696
|
+
k0-links/ not a skill but a mod: hooks Claude Code runs inside itself. At the end of each
|
|
1697
|
+
reply it finds the addresses, folders and documents the reply named, asks the
|
|
1698
|
+
disk what each path is and k0, on loopback, which documents its viewer has
|
|
1699
|
+
(POST /api/files/exist), adds the artifacts the session published, and draws them
|
|
1700
|
+
as buttons in the row above the prompt; a press runs the system's `open`. It never
|
|
1701
|
+
touches the reply. links.js is the pure half, tested by npm test; nothing in it
|
|
1702
|
+
may come from k0's own folders, because it is copied out alone
|
|
1703
|
+
k0-whatsnew/ the What is New page, written from the changelog entries k0 hands it
|
|
858
1704
|
k0-changelog/ the one that turns the facts of a stretch of work into something readable. k0
|
|
859
1705
|
calls it by itself when the ChangeLog is opened, so it is in the package too
|
|
860
1706
|
changelog/ the one that writes the changelog and the documentation when work is finished.
|
|
@@ -863,7 +1709,9 @@ web/ the three pages (html, css, js served exactly as they are)
|
|
|
863
1709
|
the road out: the documents, the tests, the commit, the push, and the tag that
|
|
864
1710
|
publishes. Also for whoever works on k0, and also not in the package
|
|
865
1711
|
docs/
|
|
866
|
-
database.md the shape of the database as it is now
|
|
1712
|
+
database.md the shape of the database as it is now, table by table, column by column
|
|
1713
|
+
method.md why a decision has to be an object, what a round of questions is for, and
|
|
1714
|
+
what the counter-check is actually checking
|
|
867
1715
|
testing.md how the tests are written, run and measured, and what is left untested on purpose
|
|
868
1716
|
test/ npm test — Node's own runner, no framework. See docs/testing.md
|
|
869
1717
|
harness.mjs check(label, got, want), and the sections the labels are grouped under
|
|
@@ -871,21 +1719,52 @@ test/ npm test — Node's own runner, no framework. See docs/testing.
|
|
|
871
1719
|
|
|
872
1720
|
### What it reads, and what it never does
|
|
873
1721
|
|
|
874
|
-
k0
|
|
875
|
-
writes
|
|
1722
|
+
k0 reads your repositories. It writes into one in three places, and all three are named here
|
|
1723
|
+
because a tool that writes where you did not expect it is a tool you stop leaving running.
|
|
1724
|
+
|
|
1725
|
+
The first is the pencil in the file viewer, on a configuration file or a note that is already
|
|
1726
|
+
there. That write is deliberately narrow — no code, no new files, no deletions — it carries the
|
|
1727
|
+
file's own permissions across, it lands as a rename so an interrupted save leaves the old file
|
|
1728
|
+
whole, and it refuses outright if the file has changed on disk since the page read it.
|
|
1729
|
+
|
|
1730
|
+
The second is the `.k0/` folder, and only ever inside it: the readable copy of that repository's
|
|
1731
|
+
backlog, rewritten whenever a story changes. Never your `.gitignore`, never a file beside it, and
|
|
1732
|
+
a test walks the tree afterwards to prove nothing else appeared. With the backlog switched off the
|
|
1733
|
+
folder is never made at all.
|
|
1734
|
+
|
|
1735
|
+
The third only happens when you ask for it, and it is `/k0-work` opening a worktree. That one is
|
|
1736
|
+
the largest thing k0 does to a repository, so it is worth reading twice: it adds a worktree under
|
|
1737
|
+
`.claude/worktrees/`, it writes two lines into `.git/info/exclude` so that directory does not show
|
|
1738
|
+
up as something you forgot to commit, and at the end it commits inside the worktree and merges
|
|
1739
|
+
that branch into the branch you were standing on. It never pushes, never opens a pull request, and
|
|
1740
|
+
never resolves a conflict on your behalf — where it cannot merge cleanly it stops and says so.
|
|
1741
|
+
None of it happens unless you run `/k0-work`.
|
|
1742
|
+
|
|
1743
|
+
k0 does not emulate a terminal and installs no settings hooks. The one thing it puts inside Claude
|
|
1744
|
+
Code is [the `k0-links` mod](#what-claude-points-at-one-click-away), and only if you
|
|
1745
|
+
said yes: it draws a row above the prompt, never touches a reply, and talks to nobody but k0 on the
|
|
1746
|
+
loopback address. Beyond that k0 reads what Claude Code already writes for itself:
|
|
876
1747
|
|
|
877
1748
|
- `~/.claude/sessions/<pid>.json` — live status (`busy`, `idle`, `waiting` with the reason for the
|
|
878
1749
|
wait) and the session id;
|
|
879
1750
|
- `~/.claude/projects/<project>/<session>.jsonl` — the transcript, read incrementally, which is
|
|
880
|
-
where you can tell whether you are inside a plan
|
|
1751
|
+
where you can tell whether you are inside a plan — and, for the Usage page, what every reply
|
|
1752
|
+
consumed, the subagents' and workflows' transcripts beside it included.
|
|
881
1753
|
|
|
882
|
-
|
|
883
|
-
|
|
1754
|
+
For the Usage page alone, two more: the account in `~/.claude.json`, read again only when that file
|
|
1755
|
+
changes, and `~/.k0/usage/limits.jsonl`, which your statusline writes if you gave it the snippet.
|
|
884
1756
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1757
|
+
Sessions are launched with `--session-id` (k0 chooses the id, so the story ↔ session link is
|
|
1758
|
+
certain), `-n` for the name, `--resume` to pick one up, and `--permission-mode plan` on new ones.
|
|
1759
|
+
Both kinds start with `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` in their environment, set on the command
|
|
1760
|
+
line the terminal is handed — `env` in front of `claude` on macOS and Linux, `$env:` before it on
|
|
1761
|
+
Windows.
|
|
1762
|
+
|
|
1763
|
+
The ChangeLog and the What's New page run Claude Code a second way: `claude -p` on the skill that
|
|
1764
|
+
writes them, with the facts on standard input and no terminal at all. Those are the only times k0
|
|
1765
|
+
starts a model, and they still open no socket of k0's own — the request is Claude Code's, made
|
|
1766
|
+
with your own account, from your own machine. Both pages can be writing at once without either
|
|
1767
|
+
cancelling the other. Those runs cannot come back as stories: `sessions.js` drops `claude -p` when it looks for
|
|
889
1768
|
sessions to import, which is also how it tells a hundred and forty real sessions from eight
|
|
890
1769
|
hundred automated ones.
|
|
891
1770
|
|
|
@@ -903,6 +1782,12 @@ Field notes the code takes for granted.
|
|
|
903
1782
|
of the two flags changes nothing — the session starts in `bypassPermissions` and there is no
|
|
904
1783
|
trace of a plan. It looks like it works, which is what makes it a trap. The only way to really
|
|
905
1784
|
start inside a plan is `--allow-dangerously-skip-permissions`.
|
|
1785
|
+
- **On a newer model Claude Code starts with no task tools.** It offers `TaskCreate`, `TaskUpdate`
|
|
1786
|
+
and the rest only to a list of older models, or when `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` is in the
|
|
1787
|
+
environment, and Opus 5 is not on the list. Nothing says so up front: the model calls
|
|
1788
|
+
`TaskCreate`, is told it is disabled for the session, and carries on without. The variable is
|
|
1789
|
+
read once, when the process starts, so a session opened before k0 set it gets the tools only by
|
|
1790
|
+
being resumed.
|
|
906
1791
|
- **While a dialog is open, the call that caused it is not yet in the transcript.** A plan to
|
|
907
1792
|
approve and a question are told apart by the `waitingFor` field of the session file:
|
|
908
1793
|
`permission prompt` is the plan, `input needed` is the question.
|
|
@@ -910,10 +1795,17 @@ Field notes the code takes for granted.
|
|
|
910
1795
|
replaced by `-`, truncated at 200 characters with a hash on the end. That is lossy: `my_project`
|
|
911
1796
|
and `my-project` become the same name, so the working directory is always read from inside the
|
|
912
1797
|
transcript, never by reversing the directory name.
|
|
913
|
-
- **A session's name lives in
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
1798
|
+
- **A session's name lives in three places** — the process's own memory, the session file it
|
|
1799
|
+
rewrites (`name`, with `nameSource: "user"` when `-n` or `/rename` set it), and the end of the
|
|
1800
|
+
transcript, in `custom-title` and `agent-name` lines that Claude Code rewrites every turn.
|
|
1801
|
+
**The last one wins.** So renaming a closed session means appending another copy; a live one
|
|
1802
|
+
would have the old name written back over it, and the only way into a live one is its own
|
|
1803
|
+
`/rename` command — typed at the keyboard. Written into the terminal as one block (Terminal's
|
|
1804
|
+
`do script`, a paste) the same line reaches it as a message, and the model answers that it
|
|
1805
|
+
cannot rename the session. The session file is how k0 knows the command took.
|
|
1806
|
+
- **The transcript is not always under the repository's slug.** A session that moves into a
|
|
1807
|
+
worktree writes under the worktree's slug from then on, and a story only knows the repository —
|
|
1808
|
+
so a rename looks in the work path, then the repository, then walks the projects directory.
|
|
917
1809
|
- **The session file appears before the interface is ready to receive.** Writing at that moment
|
|
918
1810
|
loses the first characters and swallows the Enter. So k0 waits until it can see the input box —
|
|
919
1811
|
and where a platform cannot read a terminal's screen, it waits a fixed moment and says so.
|
|
@@ -954,11 +1846,11 @@ Field notes the code takes for granted.
|
|
|
954
1846
|
The order is the fresher of two histories. The first is `~/.claude.json`, where Claude Code notes
|
|
955
1847
|
when you opened each one — but `lastStartTime` is rewritten when the session *ends*, so on its own
|
|
956
1848
|
it only tells you about the past. The second is k0's own database, which moves when you create or
|
|
957
|
-
edit a
|
|
1849
|
+
edit a story and on every status change of a live session. That is what brings the repository you
|
|
958
1850
|
are working in right now to the top.
|
|
959
1851
|
|
|
960
1852
|
The list holds directories with a `.git`, directories you have already worked in even if they are
|
|
961
|
-
not repositories, directories with a
|
|
1853
|
+
not repositories, directories with a story, directories with a document inside them — and **empty
|
|
962
1854
|
ones**.
|
|
963
1855
|
|
|
964
1856
|
Empty ones belong because an empty directory under your home is one you just made, and it cannot
|
|
@@ -967,8 +1859,8 @@ in `Others` with its `+`. Anything starting with a dot does not make it full, or
|
|
|
967
1859
|
file manager would be enough to make it disappear again.
|
|
968
1860
|
|
|
969
1861
|
**A column lives as long as its directory does.** If that directory is gone — deleted, renamed, an
|
|
970
|
-
external disk unmounted — the column does not appear, and neither do its
|
|
971
|
-
deleting**: the
|
|
1862
|
+
external disk unmounted — the column does not appear, and neither do its stories. **Hiding is not
|
|
1863
|
+
deleting**: the stories stay in the database, and if the directory comes back so do they.
|
|
972
1864
|
|
|
973
1865
|
---
|
|
974
1866
|
|
|
@@ -980,15 +1872,25 @@ HTML files from your repositories are shown in a sandbox with no permissions. Th
|
|
|
980
1872
|
and no token: anything already running as you on this machine can reach the API, and that is worth
|
|
981
1873
|
knowing rather than glossing over.
|
|
982
1874
|
|
|
1875
|
+
**One request leaves this machine, and it is about k0 rather than about you.** Once a day k0 asks
|
|
1876
|
+
the public npm registry what the newest version of `k0-board` is, so the board can say there is
|
|
1877
|
+
one. The package name is in the address and nothing else — nothing about you, your repositories,
|
|
1878
|
+
your commits or your board — nothing is downloaded, and `"updateCheck": false` in `~/.k0/config.json` switches it off entirely.
|
|
1879
|
+
|
|
983
1880
|
The full picture, and how to report a problem privately, is in [SECURITY.md](SECURITY.md).
|
|
984
1881
|
|
|
985
1882
|
## What is not here yet
|
|
986
1883
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1884
|
+
Ticking a line off on the post-it itself: a story's checklist is written by `/k0-verify`, and the
|
|
1885
|
+
place to work through it is the story's panel in the list. Writing a decision, discussing one and
|
|
1886
|
+
superseding one are still done by talking to Claude — the board says which of those to do next and
|
|
1887
|
+
opens the terminal on it, but nothing on the page writes a decision.
|
|
1888
|
+
In the viewer the listing is documents and configuration: code opens if
|
|
1889
|
+
you arrive at it from a link, but it is not browsable and the text search does not look at it.
|
|
1890
|
+
Only configuration and notes can be edited, one file at a time — nothing is diffed, no file is
|
|
1891
|
+
created or deleted, and you cannot talk to them; for that you open the repository with Claude.
|
|
1892
|
+
Sessions opened by hand outside k0 are picked up with `/k0-import`, on request: nothing notices
|
|
1893
|
+
them by itself yet.
|
|
992
1894
|
|
|
993
1895
|
## Contributing
|
|
994
1896
|
|