k0-board 0.4.0 → 0.6.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/LICENSE +83 -18
- package/README.md +1141 -119
- package/bin/k0-board.js +127 -12
- package/menubar/K0MenuBar.swift +35 -5
- package/package.json +14 -2
- package/platform/contract.js +30 -5
- package/platform/darwin/terminal.js +230 -56
- package/platform/index.js +2 -1
- package/platform/linux/index.js +3 -0
- 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 +5 -2
- 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/cloud.js +355 -0
- package/server/db.js +2117 -146
- package/server/files.js +60 -21
- package/server/git.js +53 -14
- package/server/idle.js +15 -13
- package/server/index.js +1341 -186
- package/server/launcher.js +122 -14
- package/server/machine.js +10 -1
- package/server/mirror.js +1069 -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/sync.js +383 -0
- package/server/update.js +325 -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/account.js +265 -0
- package/web/awake.js +62 -0
- package/web/base.css +97 -0
- package/web/board.css +396 -16
- package/web/board.js +1182 -152
- package/web/changelog.js +3 -3
- package/web/files.js +73 -16
- package/web/index.html +110 -12
- 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,27 +9,31 @@ 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
|
|
|
21
24
|
[](https://github.com/alessio-ragni/k0-board/actions/workflows/ci.yml)
|
|
22
25
|
[](https://www.npmjs.com/package/k0-board)
|
|
23
|
-
[](LICENSE)
|
|
24
27
|
|
|
25
|
-
**Contents** · [Install](#install) · [How it is used](#how-it-is-used) ·
|
|
28
|
+
**Contents** · [Install](#install) · [k0 Cloud](#k0-cloud) · [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) ·
|
|
29
33
|
[Shift+Enter starts a new line](#shiftenter-starts-a-new-line) ·
|
|
30
34
|
[Pasting into the terminal](#pasting-into-the-terminal) ·
|
|
31
35
|
[How it is put together](#how-it-is-put-together) · [Security](#security) ·
|
|
32
|
-
[What is not here yet](#what-is-not-here-yet) · [Contributing](#contributing) · [
|
|
36
|
+
[What is not here yet](#what-is-not-here-yet) · [Contributing](#contributing) · [License](#license)
|
|
33
37
|
|
|
34
38
|
---
|
|
35
39
|
|
|
@@ -67,7 +71,9 @@ that and went out from a laptop.)
|
|
|
67
71
|
| `k0-board start` | run the server in the foreground, installing nothing |
|
|
68
72
|
| `k0-board restart` | restart the service |
|
|
69
73
|
| `k0-board status` | is it running? exits 0 if it is, 1 if it is not |
|
|
70
|
-
| `k0-board doctor` | what this machine can and cannot do, and why |
|
|
74
|
+
| `k0-board doctor` | what this machine can and cannot do, and why — and where k0 Cloud stands |
|
|
75
|
+
| `k0-board login` | sign in to [k0 Cloud](#k0-cloud) with GitHub or Google: opens the board, where the buttons are |
|
|
76
|
+
| `k0-board logout` | sign out; the board stays on this machine and stops syncing |
|
|
71
77
|
|
|
72
78
|
`--yes` does not ask. `--from-source` points the service at the directory you are in instead of
|
|
73
79
|
copying it, which is what you want while working on k0 itself. `--no-open` finishes without
|
|
@@ -95,7 +101,7 @@ only browsers are obliged to know that `.localhost` means this computer — k0 o
|
|
|
95
101
|
- **Node 24 or newer.** k0 keeps the board in SQLite through `node:sqlite`, which is built into
|
|
96
102
|
Node — there is nothing to install and there are no npm dependencies at all.
|
|
97
103
|
- **Claude Code**, obviously.
|
|
98
|
-
- **git**, for the mark on each
|
|
104
|
+
- **git**, for the mark on each story that says whether your work is safe.
|
|
99
105
|
- **macOS**: Xcode Command Line Tools, to build the menu bar icon. Nothing else.
|
|
100
106
|
- **Linux**: tmux, which is how k0 drives terminals there. Optionally `xdotool` for window
|
|
101
107
|
placement, and `python3` with PyGObject for the tray icon.
|
|
@@ -108,6 +114,7 @@ only browsers are obliged to know that `.localhost` means this computer — k0 o
|
|
|
108
114
|
| Open a terminal and run Claude Code in it | ✅ | ✅ tmux | ✅ |
|
|
109
115
|
| Read the terminal to know when it is ready | ✅ | ✅ | ❌ waits a fixed moment instead |
|
|
110
116
|
| Leave your prompt in place, unsent | ✅ needs Accessibility | ✅ | ✅ |
|
|
117
|
+
| Rename a running session when its title changes | ✅ needs Accessibility | ❌ when it ends | ❌ when it ends |
|
|
111
118
|
| Place, resize and raise windows | ✅ | ✅ X11 only | ✅ |
|
|
112
119
|
| Large text in terminals for driving mode | ✅ | ❌ | ❌ |
|
|
113
120
|
| Keep the machine awake | ✅ | ✅ | ✅ |
|
|
@@ -138,12 +145,146 @@ Nothing on this list happens before you have seen it and said yes. Everything on
|
|
|
138
145
|
| **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
146
|
| **macOS only** — one key binding | your Terminal profile (backed up first) | so Shift+Enter starts a new line |
|
|
140
147
|
| **macOS only** — Accessibility for `node` | you grant it by hand, in System Settings | so k0 can place a prompt without sending it |
|
|
148
|
+
| 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
149
|
|
|
142
150
|
That last one deserves a sentence of its own: a process with the Accessibility permission can
|
|
143
151
|
send keystrokes to any application, and here it is granted to your `node`, not to a signed k0
|
|
144
152
|
app. Skipping it breaks nothing — the prompt gets typed and the session starts by itself.
|
|
145
153
|
|
|
146
|
-
k0
|
|
154
|
+
k0 needs **an account**, and it talks to **exactly two places**. You sign in with GitHub or Google,
|
|
155
|
+
and your board is kept in sync with **k0 Cloud** — k0's own database, on Supabase, in the EU — so
|
|
156
|
+
it survives a lost laptop and can be read from a browser. The board you work on is still the copy
|
|
157
|
+
on this machine: without a connection k0 keeps working, and catches up when the connection is back.
|
|
158
|
+
|
|
159
|
+
The second place is the public npm registry. Once a day k0 asks it what the newest version of
|
|
160
|
+
`k0-board` is, so the board can mention that there is one. The package name is in the address and
|
|
161
|
+
nothing else is in the request: not the version you are running, not your repositories, not your
|
|
162
|
+
commits, not your board, not an identifier of any kind. Nothing is downloaded and nothing is run —
|
|
163
|
+
k0 cannot update itself. Set `"updateCheck": false` in `~/.k0/config.json` and that socket is never
|
|
164
|
+
opened. Everything else stays as it was: no fonts fetched, no telemetry, no analytics, no
|
|
165
|
+
`git fetch`, and the models still run here, through your own Claude Code.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## k0 Cloud
|
|
170
|
+
|
|
171
|
+
Your board lives on your machine and keeps working with no network at all. k0 Cloud holds a copy
|
|
172
|
+
of it, so it survives a lost laptop, reaches your other machines, and — coming with the site — can
|
|
173
|
+
be read from a browser at `k0-board.com/app/`.
|
|
174
|
+
|
|
175
|
+
Who owns which piece of it, where the keys live and how somebody is let in: [`docs/cloud.md`](docs/cloud.md).
|
|
176
|
+
|
|
177
|
+
### Signing in
|
|
178
|
+
|
|
179
|
+
The first time you open the board it shows **Connect your account**, with a button for GitHub and
|
|
180
|
+
one for Google. Those are the only two ways in; there is no password of k0's own. The browser goes
|
|
181
|
+
to the provider, you say yes there, and it comes back to the board on this machine —
|
|
182
|
+
`http://k0.localhost:4319/auth/callback` — which finishes the sign-in by itself. k0 never sees a
|
|
183
|
+
password, and the one-time code that comes back is worth nothing on its own: it only works
|
|
184
|
+
together with a secret this machine made before sending the browser off (PKCE).
|
|
185
|
+
|
|
186
|
+
What keeps you signed in is written to `~/.k0/cloud.json`, readable by you and nobody else.
|
|
187
|
+
|
|
188
|
+
`k0-board login` from a terminal does the same thing: it opens the board, which is where the
|
|
189
|
+
buttons are, or says who is already signed in.
|
|
190
|
+
|
|
191
|
+
The screen only stands in front of the board when there is a way past it. If the cloud has no
|
|
192
|
+
sign-in switched on yet, the board simply opens: blocking it for something you cannot do anything
|
|
193
|
+
about would be k0's failure passed off as yours. Offline on the very first start, the screen says
|
|
194
|
+
the cloud cannot be reached instead of offering buttons that would not work.
|
|
195
|
+
|
|
196
|
+
### Early access
|
|
197
|
+
|
|
198
|
+
Signing in is not the same as being let in. k0 is in early access: an account opens once it has
|
|
199
|
+
been approved, by hand. Until then the board says **You are on the list**, nothing is sent
|
|
200
|
+
anywhere, and the board goes on working exactly as before. It notices the approval by itself — no
|
|
201
|
+
restart, no second sign-in. *Use another account* on that screen signs out and starts again.
|
|
202
|
+
|
|
203
|
+
(Approving accounts is done from an admin page that is coming with the site.)
|
|
204
|
+
|
|
205
|
+
### What goes up, and what never leaves the machine
|
|
206
|
+
|
|
207
|
+
Every few seconds, while you are signed in and let in, k0 sends what changed and fetches what your
|
|
208
|
+
other machines changed: epics, stories, tasks, decisions, rounds, checklists, dependencies, the
|
|
209
|
+
Log, and the sessions a story has had. A repository is named in the cloud by its `origin` remote,
|
|
210
|
+
cleaned of any password and of the difference between `git@` and `https://`, so the same
|
|
211
|
+
repository checked out on two machines is one column; a repository with no remote stays a name
|
|
212
|
+
known only to this machine.
|
|
213
|
+
|
|
214
|
+
What never leaves: which terminal window a session is in, the folder it is working in, and the
|
|
215
|
+
commit it started at. Nothing from your repositories either — not files, not diffs, not commits.
|
|
216
|
+
|
|
217
|
+
Sessions go up but do not come down. A session is a terminal on the machine that opened it; the
|
|
218
|
+
other machine has nothing to attach it to, so it would only be a ghost there. The cloud keeps
|
|
219
|
+
their status so the web board can show it.
|
|
220
|
+
|
|
221
|
+
When the same thing was changed in two places, a change made here and not yet sent wins over one
|
|
222
|
+
arriving from the cloud — it is what the person at this machine just did — and in the cloud a later
|
|
223
|
+
change wins over an older one that arrives late, so a laptop coming back after a day away does not
|
|
224
|
+
put yesterday's version over this morning's.
|
|
225
|
+
|
|
226
|
+
### Offline, and keys with a `~`
|
|
227
|
+
|
|
228
|
+
A key is one number for your whole account: `K150` is the same story whichever repository it is in
|
|
229
|
+
and whichever machine is looking at it. So the number comes from the cloud, which is the only place
|
|
230
|
+
two machines can agree on what comes next. k0 asks for it the moment you create a story or an
|
|
231
|
+
epic, and waits at most two and a half seconds.
|
|
232
|
+
|
|
233
|
+
When the cloud does not answer, the story is made anyway, with a **provisional key**: `K~3`. It
|
|
234
|
+
works everywhere a key does. As soon as the cloud is back the sync gives it its real number, oldest
|
|
235
|
+
first, and renames its file in `.k0/`. Nothing is reserved in advance, so the numbers still run in
|
|
236
|
+
the order the stories were made.
|
|
237
|
+
|
|
238
|
+
### Moving a board you already had
|
|
239
|
+
|
|
240
|
+
A board that existed before you signed in was numbered on this machine — per repository, if it is
|
|
241
|
+
older than k0 Cloud — and the cloud's counter starts somewhere else. Using the cloud's numbers
|
|
242
|
+
straight away would give your next story a `K1` the board already has. So the first time an
|
|
243
|
+
account is linked on a machine whose board has stories, **nothing is sent and no number is taken
|
|
244
|
+
from the cloud** until the board has been moved.
|
|
245
|
+
|
|
246
|
+
The board offers it: **Move your board to k0 Cloud**. *Show me the new numbers* lists every story
|
|
247
|
+
and epic, repository by repository, with its old key beside its new one, and says how many pieces
|
|
248
|
+
of text — a plan, a prompt, a decision — mention a key and will be updated with it. Nothing has
|
|
249
|
+
changed yet at that point. *Move it* then:
|
|
250
|
+
|
|
251
|
+
1. copies the whole database to `~/.k0/backups/k0-before-cloud-<time>.db`, in one consistent file;
|
|
252
|
+
2. renumbers every story and epic once, in the order they were made, starting from the cloud's
|
|
253
|
+
next number;
|
|
254
|
+
3. rewrites the keys written inside the text — plans, prompts, bodies, decisions, rounds, the Log,
|
|
255
|
+
the checklist — within the same repository, since that is the only place a bare `K12` ever
|
|
256
|
+
meant anything;
|
|
257
|
+
4. renames the files in `.k0/`;
|
|
258
|
+
5. writes `~/.k0/backups/k0-before-cloud-<time>.keys.json`, every old key beside its new one;
|
|
259
|
+
6. moves the cloud's counter past the board, and sends the whole board up.
|
|
260
|
+
|
|
261
|
+
When it is done the board says how many it moved, from which number, and where the two files are,
|
|
262
|
+
and stays on that page until you close it.
|
|
263
|
+
|
|
264
|
+
*Not now* means not now: the board keeps its old numbers and keeps working, and the offer comes
|
|
265
|
+
back the next time the board is opened.
|
|
266
|
+
|
|
267
|
+
### The account chip
|
|
268
|
+
|
|
269
|
+
At the end of the top bar, once you are signed in: your picture, and a dot. **Green**, everything
|
|
270
|
+
is in the cloud. **Amber**, changes are waiting to go up — or a story still has a provisional key.
|
|
271
|
+
**Grey**, the cloud cannot be reached and the board is carrying on by itself. Click it for who is
|
|
272
|
+
signed in, **Sync now**, and **Sign out**.
|
|
273
|
+
|
|
274
|
+
### Signing out
|
|
275
|
+
|
|
276
|
+
**Sign out** in that menu, or `k0-board logout`. The board stays on this machine exactly as it is;
|
|
277
|
+
it stops syncing, keys are counted on this machine again, and nothing is queued for later.
|
|
278
|
+
|
|
279
|
+
`k0-board doctor` has a *k0 Cloud* section: who is signed in, whether they have been let in,
|
|
280
|
+
whether the board still has to be moved, whether the cloud answers, and how many changes are
|
|
281
|
+
waiting.
|
|
282
|
+
|
|
283
|
+
### Switching it off
|
|
284
|
+
|
|
285
|
+
`K0_CLOUD=off` in the server's environment switches the cloud off entirely: no sign-in screen, no
|
|
286
|
+
chip, no socket. It is meant for working on k0 itself and for the tests. Without an account, keys
|
|
287
|
+
are still one counter for the whole board rather than one per repository, kept on this machine.
|
|
147
288
|
|
|
148
289
|
---
|
|
149
290
|
|
|
@@ -152,9 +293,13 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
152
293
|
### The board
|
|
153
294
|
|
|
154
295
|
- **+** — at the left, next to k0, and next to every repository name on the board: that one opens
|
|
155
|
-
a
|
|
156
|
-
|
|
157
|
-
|
|
296
|
+
a story with the repository already chosen. Two fields and no more: the repository and a title.
|
|
297
|
+
Nothing is asked about what the story is for, because both ways out of the dialog open a terminal
|
|
298
|
+
and you say it there. (With a backlog behind the board the `+` at the left is a menu of two — a
|
|
299
|
+
story typed here, or an epic told to a terminal — the dialog gains a field for the story's epic,
|
|
300
|
+
and the two buttons are *Discuss* and *Quick Start*. Editing a story that exists adds a list of
|
|
301
|
+
**notes**, which sit on the post-it for you to read and are never sent to Claude Code. It is
|
|
302
|
+
written out [below](#the-two-views).)
|
|
158
303
|
|
|
159
304
|
The repository has to be **picked from the list** (searchable, most used at the top; arrow keys
|
|
160
305
|
to move, Enter takes the highlighted row): a name typed by hand does not count. On leaving the
|
|
@@ -168,19 +313,26 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
168
313
|
spaces, and the capitals you typed stay where you put them — `fix api` becomes `Fix-Api`, while
|
|
169
314
|
`Fix API` stays `Fix-API`. What you see in the field is exactly the name the session will have.
|
|
170
315
|
|
|
171
|
-
- **the pencil** (top right of a
|
|
172
|
-
itself does nothing. On a
|
|
316
|
+
- **the pencil** (top right of a story) — the only way to open the editor: clicking the story
|
|
317
|
+
itself does nothing. On a story that is already finished, where there is nothing left to edit,
|
|
173
318
|
the **bin** takes its place.
|
|
174
319
|
|
|
175
|
-
Changing the title — only the title; the prompt has nothing to do with it —
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
320
|
+
Changing the title — only the title; the prompt has nothing to do with it — renames the session
|
|
321
|
+
too, in three places at three moments. The window's title bar, **immediately**, session running
|
|
322
|
+
or not. The session itself, if it is still running, **the first time you look at it**: when that
|
|
323
|
+
window is the one in front of you and Claude Code is sitting idle with nothing under the cursor,
|
|
324
|
+
k0 types `/rename` with the new name into it and presses Enter — you will see the command go by.
|
|
325
|
+
It never brings the window up to do that: the keyboard is yours, and a terminal jumping up while
|
|
326
|
+
you type somewhere else would take your next words. And the list of sessions you can resume,
|
|
327
|
+
**when the session ends** — while the process is alive the transcript already has an owner, and
|
|
328
|
+
it would write the old name back over ours. On Linux and Windows the second of the three is
|
|
329
|
+
missing, and `k0-board doctor` says so: there the name catches up when the session ends. The
|
|
330
|
+
same happens when a skill changes the title through the API.
|
|
331
|
+
|
|
332
|
+
- **Start** — opens a new terminal window, runs `claude` in the right repository under the story's
|
|
181
333
|
name, and puts the prompt in it. You press Enter.
|
|
182
334
|
|
|
183
|
-
The session is **born in plan mode**, always. On the board the
|
|
335
|
+
The session is **born in plan mode**, always. On the board the story turns **Planning** as soon
|
|
184
336
|
as it gets to work, and amber **Needs approval** when the plan is ready. If you need something
|
|
185
337
|
else, shift+tab as usual. **Resume** forces nothing: that session already had a mode, and it
|
|
186
338
|
comes back as it was.
|
|
@@ -189,6 +341,11 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
189
341
|
never asking anything are two things Claude Code does not do together — the why is
|
|
190
342
|
[further down](#the-traps).
|
|
191
343
|
|
|
344
|
+
Every session, new or resumed, is also born **with Claude Code's task list switched on**. On a
|
|
345
|
+
newer model Claude Code leaves it off unless it is told otherwise, and the commands that plan,
|
|
346
|
+
work and check keep a task per step — so without it they would be asking for a tool that is not
|
|
347
|
+
there.
|
|
348
|
+
|
|
192
349
|
The window is born **centred on the screen you are using**, at 86% of the free space: the same
|
|
193
350
|
margin on all four sides, never under a menu bar or a dock. Open more than one and they stack
|
|
194
351
|
in the middle — double click brings the one underneath back.
|
|
@@ -201,12 +358,16 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
201
358
|
it. It is what stops you losing track of which window is which.
|
|
202
359
|
|
|
203
360
|
- **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
|
|
361
|
+
reopens the same conversation exactly where it was. The story's prompt is **not** put back in —
|
|
205
362
|
that conversation answered it hours ago, and typing it in again would be at best something stale
|
|
206
363
|
in the way.
|
|
207
364
|
|
|
208
365
|
- **Done** — closes the work **and its terminal**, with no questions: undo it with **Reopen**, and
|
|
209
|
-
pick the conversation up again with **Resume**.
|
|
366
|
+
pick the conversation up again with **Resume**. On a story that has never been started there is
|
|
367
|
+
no terminal to close, and the button is there anyway as long as there is a backlog behind the
|
|
368
|
+
board — a story planned here and then worked on in a terminal you opened yourself has to be
|
|
369
|
+
closable, and `Done` is the only thing in k0 that closes one. With the backlog switched off it
|
|
370
|
+
is not drawn on those stories at all.
|
|
210
371
|
|
|
211
372
|
The session is stopped first and only then is the window closed. Closing a window with `claude`
|
|
212
373
|
still inside it makes macOS put up the "terminate running processes" dialog, and the window does
|
|
@@ -214,7 +375,7 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
214
375
|
|
|
215
376
|
- **Close** — a link at the end of the row, quieter than the buttons because it is the one you
|
|
216
377
|
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
|
|
378
|
+
goes, and the machine gets the memory back; the story stays exactly where it is, with the colour
|
|
218
379
|
it had — the one asking you something stays red, the one holding a plan up stays amber, the one
|
|
219
380
|
at your turn stays yellow — and **Resume** takes it from there. It is what a dozen windows open
|
|
220
381
|
and a computer running out of air are answered with.
|
|
@@ -222,9 +383,9 @@ k0 makes **no network requests**. Not one, not even for a font.
|
|
|
222
383
|
It is **not there while the session is working**: stopping one mid-thought is not memory saved,
|
|
223
384
|
it is work lost. Wait for it to come back to you, and then close it.
|
|
224
385
|
|
|
225
|
-
The only thing that asks for confirmation is throwing a
|
|
386
|
+
The only thing that asks for confirmation is throwing a story away.
|
|
226
387
|
|
|
227
|
-
|
|
388
|
+
Stories reorder themselves inside a column: first the ones waiting for you, then the ones grinding
|
|
228
389
|
away, backlog at the bottom, and among equals the most recent first.
|
|
229
390
|
|
|
230
391
|
### Moving around
|
|
@@ -261,16 +422,16 @@ that is waiting for you is the opposite of what the board is for. A terminal sim
|
|
|
261
422
|
**Your turn** is not one of those: it is the resting state of every window you have not closed,
|
|
262
423
|
and a session you finished with three weeks ago would otherwise hold its column at full width for
|
|
263
424
|
ever. It folds like anything else — and folding closes nothing, so the terminal is still open and
|
|
264
|
-
the
|
|
425
|
+
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
426
|
on the next reload, so a column never disappears out from under your hands.
|
|
266
427
|
|
|
267
428
|
**The last two columns on the right are `Old` and `Others`**, and they are the same list twice
|
|
268
429
|
over: a `+`, a name and the git mark, in alphabetical order. `Old` is the repositories that have
|
|
269
430
|
work on the board, just not lately; `Others` is the ones that have no column because they have no
|
|
270
|
-
|
|
431
|
+
stories at all. **Click a row in `Old` and the column comes back** at full width for the rest of the
|
|
271
432
|
visit — with everything that was in it, which is why the row itself says nothing about how much
|
|
272
433
|
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
|
|
434
|
+
getting into the files of a directory you are not working on, and giving birth to the first story
|
|
274
435
|
there with the `+`.
|
|
275
436
|
|
|
276
437
|
Next to a column's `+` there is one more button, which **puts that column away now** instead of
|
|
@@ -281,18 +442,18 @@ back to your turn every few seconds and it would spend the session blinking.
|
|
|
281
442
|
Unlike the automatic fold, this one is remembered across reloads, until you fetch the column back
|
|
282
443
|
or something in it wakes up. It **closes nothing**: no session is stopped and no terminal is
|
|
283
444
|
shut. It is the board that gets smaller, not the work — what closes a session is `Close` or `Done`
|
|
284
|
-
on a
|
|
445
|
+
on a story.
|
|
285
446
|
|
|
286
447
|
### The git mark
|
|
287
448
|
|
|
288
|
-
On every
|
|
449
|
+
On every story, next to the repository name, and next to every column name, one symbol says
|
|
289
450
|
whether the work is safe: a **dot** with how many files, if there is work that is nowhere yet; an
|
|
290
451
|
**up arrow** with how many commits, if it is committed but not pushed; a faded **tick**, if
|
|
291
452
|
everything is saved. Hover to read it in full — branch, files, commits, and how many of those
|
|
292
453
|
commits belong to that session. **Click it and the files open.**
|
|
293
454
|
|
|
294
|
-
A
|
|
295
|
-
its own. A
|
|
455
|
+
A story running in an **isolated worktree** has a working tree of its own, so the mark is really
|
|
456
|
+
its own. A story working in the base repository shares the working tree with everybody — there the
|
|
296
457
|
dot belongs to the repository, and the only thing that belongs to the session is the commits made
|
|
297
458
|
since it started, which k0 counts by remembering where `HEAD` was at that moment.
|
|
298
459
|
|
|
@@ -325,8 +486,9 @@ that asked for it, close every session, restart k0 itself — the server stays u
|
|
|
325
486
|
stays green. This is the whole reason it exists: a dev server started inside a session belongs to
|
|
326
487
|
that session, and dies with it.
|
|
327
488
|
|
|
328
|
-
**k0 never asks the server whether it is up.**
|
|
329
|
-
|
|
489
|
+
**k0 never asks the server whether it is up.** Nothing here opens a socket to it — k0 talks to its
|
|
490
|
+
own cloud and to npm, and to nothing it finds running on your machine. "Up" means the process is alive *and*
|
|
491
|
+
the operating system says it is holding a TCP port
|
|
330
492
|
open. That is stronger evidence than a reply would be, and it is where the port in the tooltip
|
|
331
493
|
comes from — k0 never guesses a port, it reads the one your server actually chose.
|
|
332
494
|
|
|
@@ -339,6 +501,480 @@ as off.
|
|
|
339
501
|
|
|
340
502
|
---
|
|
341
503
|
|
|
504
|
+
## The backlog
|
|
505
|
+
|
|
506
|
+
A post-it used to be a name and a prompt. That is enough to start a session and nothing like
|
|
507
|
+
enough to remember why you started it: three weeks later the title says `Fix-Invoicing`, and the
|
|
508
|
+
half hour that decided what *fixed* meant has scrolled off the top of a terminal you have since
|
|
509
|
+
closed.
|
|
510
|
+
|
|
511
|
+
The backlog is the rest of it. Same board, same notes, same gestures — what is added is what the
|
|
512
|
+
work is *about*: what it belongs to, what was settled while you were talking about it, what has
|
|
513
|
+
to be true before it can be called finished, and a check that holds the finished thing up against
|
|
514
|
+
all of that before you are allowed to tick it off.
|
|
515
|
+
|
|
516
|
+
**The board is the menu; the commands are the engine.** Every story says what the one next thing
|
|
517
|
+
to do with it is — *Discuss*, *Plan*, *Work* — and pressing that opens a terminal with
|
|
518
|
+
the command already in it. The work happens there, in Claude Code, and you do not come back to the
|
|
519
|
+
board until it is finished. Almost nothing here is typed into a form.
|
|
520
|
+
|
|
521
|
+
If you want the argument rather than the manual — why a decision has to be an object, what a
|
|
522
|
+
round of questions is for, what the counter-check is really checking — it is in
|
|
523
|
+
[docs/method.md](docs/method.md), and it is a shorter read than this section.
|
|
524
|
+
|
|
525
|
+
### Before anything else: the commands have to be on your machine
|
|
526
|
+
|
|
527
|
+
Everything below runs on ten commands you type at Claude Code, and Claude Code looks for a
|
|
528
|
+
command in exactly two places: **the repository you have open**, and **your own
|
|
529
|
+
`~/.claude/skills/`**. Neither of those is where npm puts k0. So a command that was not copied out
|
|
530
|
+
is a command that does not exist, however carefully it was written — and every button on the board
|
|
531
|
+
that offers to run one leads nowhere.
|
|
532
|
+
|
|
533
|
+
Copying them out is **one question, asked by the installer**, right after it starts the service:
|
|
534
|
+
|
|
535
|
+
```
|
|
536
|
+
/k0-epic — an epic, discussed in rounds, then a tree of stories
|
|
537
|
+
/k0-story — one story, straight onto the board
|
|
538
|
+
…
|
|
539
|
+
Install 11 commands and the mod for Claude Code? (Y/n)
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Say yes and they are there in every repository you ever open. It is worth saying plainly what
|
|
543
|
+
happens if you do not, because it is what happened to this feature the first time round: the
|
|
544
|
+
commands were written and they worked — inside a clone of k0, and nowhere else on the machine.
|
|
545
|
+
From any other repository the board offered *Discuss*, the terminal opened, and Claude Code had
|
|
546
|
+
never heard of `/k0-discuss`. The whole backlog was invisible for want of one copy step.
|
|
547
|
+
|
|
548
|
+
**If you are not sure you said yes, run `npx k0-board@latest` again.** It asks only about the ones
|
|
549
|
+
that are missing, so somebody who already has them is not asked at all, and somebody who said no
|
|
550
|
+
in a hurry gets the question back. `ls ~/.claude/skills` answers it too.
|
|
551
|
+
|
|
552
|
+
If you **cloned this repository** rather than installing the package, they are already in its
|
|
553
|
+
`.claude/skills/` and there is nothing to do — but only while you are working *in this clone*.
|
|
554
|
+
Copy them out anyway if you use them anywhere else.
|
|
555
|
+
|
|
556
|
+
### A day with it
|
|
557
|
+
|
|
558
|
+
**You open the board.** Every story that has something to do carries **one button, first in the
|
|
559
|
+
row, saying what that is**: **Discuss**, **Plan**, **Work** — in that order, because that is the
|
|
560
|
+
order the work goes in — or **Resume**, when a terminal was opened on it and then closed. Hover it
|
|
561
|
+
and it says why this and not something else: *It has been discussed and has no plan yet*. There is
|
|
562
|
+
one button and never a menu, and there are three words on the list and no more.
|
|
563
|
+
|
|
564
|
+
There is also a story that carries **no** button, and that is an answer too. A session that is
|
|
565
|
+
running needs nothing suggested about it — the terminal is where the work is, and a double click on
|
|
566
|
+
the note goes there. A story waiting for you to look it over is waiting for a person. A story that
|
|
567
|
+
is finished is finished. Filling any of those in with a command would be k0 inventing work.
|
|
568
|
+
|
|
569
|
+
k0 works that out and the page never does. It is the same reasoning `/k0-next` does, in the same
|
|
570
|
+
place, so the button on the note and the answer the command gives can never drift apart.
|
|
571
|
+
|
|
572
|
+
**You press it.** A terminal opens in that repository and `/k0-plan K42` — the line you would have
|
|
573
|
+
typed yourself — goes in with it, already sent: k0 wrote that line out of a button you pressed, so
|
|
574
|
+
there is nothing on it for you to read over first, and a prompt left sitting unsent under the
|
|
575
|
+
cursor is a window that did nothing.
|
|
576
|
+
|
|
577
|
+
**Or you take the short way in.** **Quick Start** is the other road out of a story and it is not
|
|
578
|
+
the same road: it opens a terminal on that repository with *nothing* in it and leaves the typing to
|
|
579
|
+
you. That is the whole of it — no discussion, no plan, no command. It sits at the end of the row as
|
|
580
|
+
a quiet link on a story that has a suggestion, and it is the plain button on one that has not.
|
|
581
|
+
|
|
582
|
+
Only `/k0-work` counts as the work having begun. Press *Discuss* or *Plan* and the story stays
|
|
583
|
+
where it was until the discussion or the plan moves it itself — otherwise walking away from a
|
|
584
|
+
discussion half way through would leave a story sitting in `Working` with nothing worked on.
|
|
585
|
+
|
|
586
|
+
**You work in the terminal, and only in the terminal.** The discussion asks its rounds and writes
|
|
587
|
+
each one down as it is answered; the plan comes back for your approval with the standing decisions
|
|
588
|
+
written into it as constraints; `/k0-work` opens a worktree, does the work, keeps the log, and
|
|
589
|
+
merges it back; `/k0-verify` walks the result past every decision one at a time. None of that
|
|
590
|
+
needs the board. You can leave the tab open and watch the rounds land — it follows a live
|
|
591
|
+
discussion once a second — but nothing asks you to.
|
|
592
|
+
|
|
593
|
+
**You come back, and the button has moved on.** A story you discussed now says *Plan*. One you
|
|
594
|
+
planned says *Work*. One whose terminal you closed says *Resume*, and picks the conversation up
|
|
595
|
+
where it was rather than starting a second one beside it.
|
|
596
|
+
|
|
597
|
+
**Double click the note to go where the work is.** Its terminal if one is running; the conversation
|
|
598
|
+
it left behind if the terminal was closed; a fresh session if there was never one. It is the same
|
|
599
|
+
gesture on every note, which is what makes it worth having — and if the window has been closed by
|
|
600
|
+
hand while the session is still thinking, k0 goes and looks for it by name before it tells you
|
|
601
|
+
anything, and offers to open it again when there is really nothing left to find.
|
|
602
|
+
|
|
603
|
+
**Done is yours and nothing else's.** No command sets it and no gesture sets it: when the work is
|
|
604
|
+
really finished you press **Done** on the note, and it closes the terminal with it. A story that
|
|
605
|
+
came through its counter-check clean is offered no command at all — there is nothing left for one
|
|
606
|
+
to do, and the only thing in front of it is you pressing Done. `/k0-verify` and `/k0-split` are
|
|
607
|
+
still there and still do what they always did: they are commands you type, on the days you want
|
|
608
|
+
them, rather than advice the board pushes at you.
|
|
609
|
+
|
|
610
|
+
**Things arrive during the day, and they do not interrupt this.** Something you already know you
|
|
611
|
+
want is `/k0-story` in whatever terminal you have open — you say it, it lands on the board with a
|
|
612
|
+
key of its own, and adding *and start it* opens the session in the same breath. Something big
|
|
613
|
+
enough that you do not yet know what it is made of is `/k0-epic`: ten minutes of questions in
|
|
614
|
+
rounds, everything settled written down as it is settled, and only at the end a tree of stories
|
|
615
|
+
proposed for your approval — it creates none of them until you have said yes. Both are on the
|
|
616
|
+
board's `+` as well, which is a small menu now: **Story** opens the dialog you know, with one
|
|
617
|
+
field added for its epic; **Epic** asks which repository and then opens a terminal running
|
|
618
|
+
`/k0-epic`, because an epic is told, not typed.
|
|
619
|
+
|
|
620
|
+
### The two views
|
|
621
|
+
|
|
622
|
+
The switch in the top bar, in among the filters, says **Kanban** or **List**. It changes the shape
|
|
623
|
+
of what you are looking at and never what you are looking at: the state pills, the repository and
|
|
624
|
+
the epic lane apply to both, so switching back and forth is free and nothing appears or vanishes
|
|
625
|
+
under you.
|
|
626
|
+
|
|
627
|
+
**Kanban is for working.** It is the board you already know — one column per repository, notes
|
|
628
|
+
that reorder themselves by who is waiting for you. With a backlog behind it a note grows four
|
|
629
|
+
marks and no more: its **key**; the **epic** it belongs to, as a small label in the epic's own
|
|
630
|
+
colour, worked out from the key so there is nothing to choose and nothing to keep in step; a
|
|
631
|
+
**flag** in the bottom corner; and a warning when something it **waits on** is not finished.
|
|
632
|
+
|
|
633
|
+
The flag is put on and taken off **from the note itself** — it is the mark and the target both,
|
|
634
|
+
and it mirrors the pencil at the other corner. It is invisible until the pointer is on the note,
|
|
635
|
+
because an outline sitting on every note all the time is a mark that is everywhere and therefore
|
|
636
|
+
marks nothing. Once it is on it stays on, and the note takes a border and its key and title take
|
|
637
|
+
the flag's colour with it: the point of flagging something is finding it again from across the
|
|
638
|
+
room, and a fifteen-pixel glyph cannot be seen from there.
|
|
639
|
+
|
|
640
|
+
**Click an epic's label and the board becomes that epic.** A strip appears under the top bar with
|
|
641
|
+
its key, its title, its repository, a progress bar and `4 of 11 done`, and the way back out. Inside
|
|
642
|
+
the lane the label is not drawn on the notes — everything in here belongs to the same epic, and
|
|
643
|
+
saying so eleven times says nothing. The lane survives a reload: going into an epic is a decision
|
|
644
|
+
about where you are working, and a page that forgets it every time you press F5 is a page you stop
|
|
645
|
+
going into. The progress is counted over the epic's stories, not over the notes a filter left on
|
|
646
|
+
screen, and it is not weighted: eleven stories with one done is 1 of 11, however big the one was.
|
|
647
|
+
Anything else is an estimate, and an estimate here is a lie with a progress bar drawn round it.
|
|
648
|
+
|
|
649
|
+
**List is for planning.** The same stories as rows, three levels deep and every repository at
|
|
650
|
+
once: a thin heading per repository, an epic that opens and closes with its progress bar — and,
|
|
651
|
+
while a discussion is running on it, which round that is on — and under it its stories, with tasks
|
|
652
|
+
indented beneath the story they were cut from. Stories belonging to no epic are grouped at the
|
|
653
|
+
end. A row carries key, title, state, flag, how many decisions are still standing, how much of
|
|
654
|
+
the checklist has passed, and the same next-step button. Which epics you left open is remembered.
|
|
655
|
+
|
|
656
|
+
**Click a row and the story opens beside it**, not underneath: the counter-check first, then why
|
|
657
|
+
it exists, the rounds with their questions and answers, the decisions with the verdict each one
|
|
658
|
+
got, the plan, the checklist and the log — with a line under the title saying both what it waits
|
|
659
|
+
for and what is waiting for it, each key a way into that story. Beside rather than below, because
|
|
660
|
+
the point of a list is to run down it, and a panel that pushes the rows off the bottom of the page
|
|
661
|
+
loses the thing you were comparing against. Click an epic and the epic opens the same way — the
|
|
662
|
+
rounds it was argued out in, and the decisions every story under it is held to. That is the only
|
|
663
|
+
place that conversation can be watched, because it happens before a single story of it exists.
|
|
664
|
+
|
|
665
|
+
Two things in this view write rather than read, and they are the two you do while *looking* at a
|
|
666
|
+
backlog rather than while working on one: **the next step, started from the end of a row**, and **a
|
|
667
|
+
checklist line you have just watched work with your own eyes** — ticked in the panel, and recorded
|
|
668
|
+
as yours rather than the model's, which is the difference the checklist exists to keep.
|
|
669
|
+
|
|
670
|
+
**Dragging a row moves it.** Up and down to change the order, onto another epic's heading to move
|
|
671
|
+
it there, onto `No epic` to take it out of one. That is the whole of it: **dragging never changes
|
|
672
|
+
state.** A state is a road the work walks, and walking it by dropping a piece of paper somewhere
|
|
673
|
+
was always the wrong gesture — states move from the terminal, and from the Done button.
|
|
674
|
+
|
|
675
|
+
### The ten commands
|
|
676
|
+
|
|
677
|
+
Ten you type, and the installer offers eleven — these ten plus
|
|
678
|
+
[`/k0-import`](#filling-the-board-with-what-you-have-already-done) — and one more thing that is not a
|
|
679
|
+
command at all, [the `k0-links` mod](#what-claude-points-at-one-click-away). `/k0-whatsnew` and
|
|
680
|
+
`/k0-changelog` are deliberately not on that list: k0 runs those two itself, out of its own
|
|
681
|
+
directory, and you never type them.
|
|
682
|
+
|
|
683
|
+
| | |
|
|
684
|
+
|---|---|
|
|
685
|
+
| `/k0-story` | one story, straight onto the board — the fast door |
|
|
686
|
+
| `/k0-epic` | the long way in: rounds, decisions, then a tree of stories you approve |
|
|
687
|
+
| `/k0-discuss` | the same rounds against a story that already exists |
|
|
688
|
+
| `/k0-split` | a story that will not close, cut into tasks that inherit its decisions |
|
|
689
|
+
| `/k0-plan` | plan mode, with the standing decisions written into the plan as constraints |
|
|
690
|
+
| `/k0-work` | the worktree, the work, the log as it goes, and the merge back |
|
|
691
|
+
| `/k0-ultracode` | a whole epic, or one story, run by a manager with agents under it |
|
|
692
|
+
| `/k0-verify` | the counter-check |
|
|
693
|
+
| `/k0-next` | what to pick up now, and why |
|
|
694
|
+
| `/k0-order` | priority and dependencies, dictated: *K51 to the top, K42 waits on K37, flag K19* |
|
|
695
|
+
|
|
696
|
+
These ten are also the only ten a button on the board may start. They are written out by name in
|
|
697
|
+
the server and checked against that list before anything reaches a command line — and it is a list
|
|
698
|
+
and not a directory listing on purpose: a folder arriving in your skills directory, from a clone or
|
|
699
|
+
a package or an installer, must not thereby become something a web page can ask k0 to run.
|
|
700
|
+
|
|
701
|
+
`/k0-next` is worth one sentence of its own, because the answer is not the model's. k0 works out
|
|
702
|
+
what to pick up — a live session first, then something in `Review` and the one that has been
|
|
703
|
+
sitting there longest, then what is not waiting on unfinished work, then the flag, then how far
|
|
704
|
+
along it is, then the order you put the board in — and hands over the story with the sentence that
|
|
705
|
+
says why. Ask twice and you get the same answer, which is not true of anything a model reasons out
|
|
706
|
+
each time.
|
|
707
|
+
|
|
708
|
+
**Dependencies are a note, not a lock.** Nothing refuses to start a story that is waiting on
|
|
709
|
+
another one: the note is marked, the button that starts the work asks you once and then goes
|
|
710
|
+
ahead, and the story sinks down `/k0-next`. A backlog that will not let you work on what you want
|
|
711
|
+
is a backlog you stop using.
|
|
712
|
+
|
|
713
|
+
### An epic, a story, a task
|
|
714
|
+
|
|
715
|
+
**A story is one post-it**, and it is the thing you work on. Everything the board already does it
|
|
716
|
+
still does: a story opens a terminal, drives the session in it, and says what that session is
|
|
717
|
+
doing.
|
|
718
|
+
|
|
719
|
+
**An epic is a reason** with several stories under it — an area, a feature, a rewrite. It lives in
|
|
720
|
+
exactly one repository, because a piece of work that spans two of them is two pieces of work with
|
|
721
|
+
a wish in the middle.
|
|
722
|
+
|
|
723
|
+
**A task is a story that was cut out of another one.** It is not a different kind of thing: same
|
|
724
|
+
table, same rules, same key — a story that turned out too big to close gets split, not turned into
|
|
725
|
+
another species. A task takes its parent's epic unless you give it one of its own, because a task
|
|
726
|
+
planned outside the epic its parent sits in would be planned blind to every decision that shaped
|
|
727
|
+
the whole thing.
|
|
728
|
+
|
|
729
|
+
### The key, and where it sits
|
|
730
|
+
|
|
731
|
+
Every epic, story and task gets a **key**: `K` plus a number, `K42`. It is **one number for your
|
|
732
|
+
whole account** — every repository, every machine — shared between epics and stories, and it is
|
|
733
|
+
**never reused and never reassigned**: not when the story moves under another epic, not when you
|
|
734
|
+
delete it, not when the repository is renamed, and not when the story moves to another repository,
|
|
735
|
+
since there is no other `K42` there for it to collide with. The number comes from k0 Cloud's
|
|
736
|
+
counter; a story made while the cloud cannot be reached gets a provisional key, `K~3`, until the
|
|
737
|
+
sync gives it its real one — see [Offline, and keys with a `~`](#offline-and-keys-with-a-). Without
|
|
738
|
+
an account the same single counter is kept on this machine.
|
|
739
|
+
|
|
740
|
+
Beside it there is a **position**: `1.12.1`. The first epic, its twelfth story, that story's first
|
|
741
|
+
task. The position is worked out fresh every time it is shown and never stored, so it cannot
|
|
742
|
+
disagree with the tree it describes — move a story and its position moves with it.
|
|
743
|
+
|
|
744
|
+
The key is the name you say out loud; the position is where the thing is sitting today. When you
|
|
745
|
+
say `K42` to a command it knows what you mean, whatever the board has been rearranged into since.
|
|
746
|
+
|
|
747
|
+
### Why a story is not a session
|
|
748
|
+
|
|
749
|
+
This is the one change underneath everything else, and it is worth a paragraph.
|
|
750
|
+
|
|
751
|
+
A card used to *be* a session: one note, one conversation, and ticking the note off ended both. So
|
|
752
|
+
a piece of work you came back to twice was two notes, and the first one was a note about a
|
|
753
|
+
conversation nobody could remember.
|
|
754
|
+
|
|
755
|
+
Now a story keeps **every session it has had**, one at a time, over as long as it takes. And it
|
|
756
|
+
carries two different clocks, which used to be one column fighting itself:
|
|
757
|
+
|
|
758
|
+
- **the story's state** — `Backlog` · `Discussed` · `Planned` · `Working` · `Review` · `Done` —
|
|
759
|
+
which is where the *work* is;
|
|
760
|
+
- **the session's status** — working, planning, holding a plan up, asking you something, your turn
|
|
761
|
+
— which is what a *terminal* is doing this second.
|
|
762
|
+
|
|
763
|
+
No transition is required. Any state may follow any other, and `Backlog` straight to `Done` is a
|
|
764
|
+
legal thing to do that nothing will warn you about — a backlog that argues with you about the road
|
|
765
|
+
is a backlog you route around. `Working` sets itself when a session goes live. `Review` is where
|
|
766
|
+
`/k0-verify` puts a story when it starts checking it. **`Done` is only ever yours**: nothing in k0
|
|
767
|
+
sets it, and the Done button on the note is still what confirms it.
|
|
768
|
+
|
|
769
|
+
The post-it itself still draws one word and one colour, exactly as before — the two clocks put
|
|
770
|
+
back together. Nothing about the board you know got louder.
|
|
771
|
+
|
|
772
|
+
### Rounds, and why they say how many are left
|
|
773
|
+
|
|
774
|
+
A round is one small group of questions — four at the most — with your answers written down before
|
|
775
|
+
the next one is asked.
|
|
776
|
+
|
|
777
|
+
Each round opens by saying where it is: **"Round 3 of about 8"**. The number comes from counting
|
|
778
|
+
the things where a different answer would produce different work, and it is recalculated after
|
|
779
|
+
every answer, because answers both close questions and open them. When it moves, it says so in the
|
|
780
|
+
same breath — *round 4 of about 6, two of the questions answered themselves* — and never drifts in
|
|
781
|
+
silence. A count that quietly becomes twelve after promising eight is a count you stop believing,
|
|
782
|
+
and once you stop believing it you start answering to get it over with.
|
|
783
|
+
|
|
784
|
+
It stops when no remaining question would change the work, which is stricter than it sounds and is
|
|
785
|
+
the only test being applied: a question worth asking is one whose two answers lead to two different
|
|
786
|
+
builds. There is a hard ceiling of **fifteen rounds**. At fifteen it stops wherever it is, shows
|
|
787
|
+
you the list of what it never got to in your own words, and says the story is recorded as it stands
|
|
788
|
+
and can be picked up whenever you like. A discussion that reaches fifteen is telling you the story
|
|
789
|
+
is really two, and it says that as well.
|
|
790
|
+
|
|
791
|
+
**Every round is written to k0 before the next question is asked.** Not at the end, not on a save.
|
|
792
|
+
A terminal that dies at round three does not take the first three with it, and neither does a
|
|
793
|
+
session that runs out of context in the middle — which is the one that actually happens, and the one
|
|
794
|
+
nobody thinks about until the second time.
|
|
795
|
+
|
|
796
|
+
### Decisions
|
|
797
|
+
|
|
798
|
+
What comes out of the rounds is not a summary. It is a row of **decisions**, one complete sentence
|
|
799
|
+
each, numbered — `D1`, `D2` — and written in your language, about behaviour rather than about
|
|
800
|
+
implementation. A decision that names a function is one you cannot check without opening the code,
|
|
801
|
+
and six months from now you will not open the code.
|
|
802
|
+
|
|
803
|
+
A decision is **never rewritten**. When you change your mind, the new decision *supersedes* the old
|
|
804
|
+
one and both stay, the old one crossed through and pointing at what replaced it. This is the whole
|
|
805
|
+
reason they are objects and not paragraphs: the point is to hold the work up against what was
|
|
806
|
+
actually said at the time, and prose you can edit afterwards proves nothing.
|
|
807
|
+
|
|
808
|
+
An epic's decisions belong to the epic, and every story under it **inherits** them rather than being
|
|
809
|
+
handed a copy. They are shown with the epic's key in front — `K7·D3` — so it is obvious a rule came
|
|
810
|
+
down from above and applies to everything in the lane. Inheriting rather than copying is what makes
|
|
811
|
+
changing your mind work: supersede `K7·D3` on the epic and it is superseded for all eleven stories
|
|
812
|
+
at once, where eleven copies would have forked the first time one of them was touched.
|
|
813
|
+
|
|
814
|
+
An epic is discussed and decided before a single story of it exists, which is why its decisions
|
|
815
|
+
have to be able to live on the epic. That is not a detail: it is the main way anybody uses this.
|
|
816
|
+
|
|
817
|
+
And when something you say now contradicts something you settled earlier, the discussion **stops
|
|
818
|
+
there and asks** — naming the decision it clashes with, saying which of the two it thinks should
|
|
819
|
+
stand, and why. Writing both down and carrying on is how you end up with two rules that disagree
|
|
820
|
+
and no way of knowing which one the work followed.
|
|
821
|
+
|
|
822
|
+
### The counter-check
|
|
823
|
+
|
|
824
|
+
Here is what this is for.
|
|
825
|
+
|
|
826
|
+
You explain a piece of work to a model, properly, for half an hour. It asks good questions — some
|
|
827
|
+
of the answers surprise you, because you did not know what you wanted until it asked. It says it
|
|
828
|
+
has understood, and it has: the summary it gives back is better than the one you would have
|
|
829
|
+
written. Then it builds something that quietly contradicts half of it. Not all of it, and not
|
|
830
|
+
obviously. One thing you settled at minute twenty is simply not there, and something you ruled out
|
|
831
|
+
is there instead. You notice three days later, and by then you cannot even prove you said it.
|
|
832
|
+
|
|
833
|
+
That half hour did not merely fail to help. It cost you the half hour and it bought a false
|
|
834
|
+
confidence that the thing was understood, which is worse than knowing it was not, because you
|
|
835
|
+
stopped watching.
|
|
836
|
+
|
|
837
|
+
`/k0-verify` is the thing that was missing. When the work is done it takes the decisions **one at a
|
|
838
|
+
time** — the story's own and the ones it inherited — and records a verdict for each: **kept**,
|
|
839
|
+
**violated**, or **not applicable**, with the evidence. A file and a line, or a sentence saying why
|
|
840
|
+
the decision does not apply here. Never a summary standing in for the row, because a summary is
|
|
841
|
+
where the one that was broken goes to hide.
|
|
842
|
+
|
|
843
|
+
Three rules make it worth something rather than a ceremony:
|
|
844
|
+
|
|
845
|
+
- **A run is the whole set or it is not a run.** One that answers nine decisions of ten is refused
|
|
846
|
+
and told which one it passed over. `na` is a verdict; silence is not. A check that reports a
|
|
847
|
+
clean sweep of whatever it happened to look at is worse than no check.
|
|
848
|
+
- **A run never overwrites the one before it.** Runs are numbered and they all stay, so you can see
|
|
849
|
+
that something was broken, then fixed, rather than only that it is fine now.
|
|
850
|
+
- **A story cannot be marked `Done` while a decision a run found broken has not been answered
|
|
851
|
+
since.** It is read decision by decision and not run by run: a later run that finds the same
|
|
852
|
+
decision kept closes it, and a later run that says nothing about it, or says it does not apply,
|
|
853
|
+
leaves it exactly where it was. This is the only refusal in the whole feature, and it applies to
|
|
854
|
+
whatever is asking: the Done button on the note, the one at the end of a row in the list, a
|
|
855
|
+
command. It comes back as a sentence saying which decision, from which run, and what to do about
|
|
856
|
+
it.
|
|
857
|
+
|
|
858
|
+
There are exactly two ways to answer it, and both are honest: **put the work right and run the
|
|
859
|
+
counter-check again**, or **supersede the decision** if it turns out the decision was the thing that
|
|
860
|
+
was wrong. What you cannot do is talk past it: a story with a broken decision is drawn on the board
|
|
861
|
+
so that it cannot be scrolled past, and pressing Done on it comes back with the sentence rather than
|
|
862
|
+
the story closed.
|
|
863
|
+
|
|
864
|
+
There is also a **checklist** on the story — what has to be true for it to be finished. `/k0-verify`
|
|
865
|
+
does itself everything a machine can do, runs the project's tests, drives the browser when the thing
|
|
866
|
+
is a web application, and leaves you only the lines that genuinely need a person.
|
|
867
|
+
|
|
868
|
+
### `/k0-work` and the worktree
|
|
869
|
+
|
|
870
|
+
`/k0-work` gives the session a working copy of its own: a git worktree under
|
|
871
|
+
`<repo>/.claude/worktrees/`, on a branch named after the story, opened **from the branch you are
|
|
872
|
+
standing on** — not from `main`, not from `origin`. You keep working in the repository, the session
|
|
873
|
+
works next door, and at the end its branch comes back in as one merge commit and the copy is
|
|
874
|
+
destroyed. The folder is kept out of git's way through `.git/info/exclude`, never by writing in
|
|
875
|
+
your `.gitignore`.
|
|
876
|
+
|
|
877
|
+
Everything the board starts opens in the story's **own repository**, never in a worktree. `/k0-work`
|
|
878
|
+
makes one when it needs one, and it is the only command here that does: the others talk about the
|
|
879
|
+
story rather than change it, and a discussion held inside somebody else's working copy is a
|
|
880
|
+
discussion about a copy.
|
|
881
|
+
|
|
882
|
+
It will not open one over uncommitted work, and it says how much there is. And three things it
|
|
883
|
+
never does, each of which has already cost somebody a day:
|
|
884
|
+
|
|
885
|
+
- **It never pushes and never opens a pull request.** The merge stops on this machine. Publishing
|
|
886
|
+
is a decision you make when you are ready to make it.
|
|
887
|
+
- **It never resolves a conflict.** There is no way for a program to tell a conflict it resolved
|
|
888
|
+
correctly from one it resolved plausibly, and taking a side to make the command succeed throws
|
|
889
|
+
away something somebody typed. A conflict stops everything and says which files.
|
|
890
|
+
- **It never runs tests, a build or a dev server in there.** A worktree copies the code but not the
|
|
891
|
+
untracked files around it, so the `.env` somebody copies across carries the *base* repository's
|
|
892
|
+
port — and a test runner that finds a server already listening on it uses that one, goes green,
|
|
893
|
+
and tells you the new code passes when what it tested was the old checkout. Tests run on the base
|
|
894
|
+
branch, after the merge.
|
|
895
|
+
|
|
896
|
+
That last rule has one honest edge. Merging commits whatever the session left pending, a commit
|
|
897
|
+
runs your repository's own hooks, and a `pre-commit` hook that runs the whole suite is normal. k0
|
|
898
|
+
does not step round it with `--no-verify` — a commit that only went through because k0 avoided your
|
|
899
|
+
hooks has not been checked at all — so the hook does run, next door, with the wrong `.env` beside
|
|
900
|
+
it. k0 says so when it happens rather than being quiet about it.
|
|
901
|
+
|
|
902
|
+
### `/k0-ultracode`: the same work, with a manager over it
|
|
903
|
+
|
|
904
|
+
On a note that is ready to be worked on, next to **Work**, there is a quieter word: **Ultracode**.
|
|
905
|
+
It is the same act at a larger size. One session becomes a **manager**: it cuts the story's plan
|
|
906
|
+
into **assignments**, gives each one to an **agent** working in a copy of the repository of its own,
|
|
907
|
+
brings the work back one piece at a time, and only then — on your branch, where the code on the disk
|
|
908
|
+
is the code that was merged — runs the tests, has the result read by an agent that wrote none of it,
|
|
909
|
+
and walks the story past every decision. It is offered on an epic too, from the epic's panel, and
|
|
910
|
+
that is what it is really for: story after story, each one finished before the next one starts.
|
|
911
|
+
|
|
912
|
+
Before it does anything it asks you two questions and never asks again. **How much rope** —
|
|
913
|
+
*interactive*, where every question an agent brings back reaches you while it is warm; *checkpoint*,
|
|
914
|
+
which stops at the cut, before the merge and on a red test run; or *autonomous*, which goes to the
|
|
915
|
+
end and comes back with the list of everything it decided on your behalf. And **how hard** — two,
|
|
916
|
+
three or five agents at a time, one repair attempt or two, one pair of fresh eyes or three. Both
|
|
917
|
+
answers go into the Log, so a terminal you closed halfway through is picked up again on the same
|
|
918
|
+
terms rather than on new ones.
|
|
919
|
+
|
|
920
|
+
What it does not do is the point of the shape. It never pushes. It never runs anything inside a
|
|
921
|
+
worktree, for the reason above. It never presses **Done** — the stories come back sitting in
|
|
922
|
+
`Review`, counter-checked, waiting for you. And it stops: the repair attempts are spent and then it
|
|
923
|
+
tells you what is still broken, having merged everything that works. A run that never ends is not
|
|
924
|
+
thoroughness, it is a run nobody can plan around.
|
|
925
|
+
|
|
926
|
+
### The `.k0/` folder
|
|
927
|
+
|
|
928
|
+
Each repository with a backlog grows a `.k0/` folder: a `README.md` explaining itself, one file per
|
|
929
|
+
epic under `epics/`, one per story or task under `stories/`. A story file opens with its header —
|
|
930
|
+
key, epic, state, flag, what it waits on, the sessions it has lived through — and then
|
|
931
|
+
**Why**, the **Prompt**, the **Discussion** round by round, the **Decisions**, the **Plan**, the
|
|
932
|
+
**Verification** run by run with its checklist, and the **Log**. An epic's file is the same header,
|
|
933
|
+
its own **Why**, **Discussion** and **Decisions**, and then the list of its stories with a line
|
|
934
|
+
saying how far it has got.
|
|
935
|
+
|
|
936
|
+
The database is the source of truth and these are printed from it — whole, every time the story
|
|
937
|
+
changes, never diffed cleverly — so a file cannot end up claiming something the board does not. But
|
|
938
|
+
they are files, so they diff, they review, and they go in the commit with the work they describe.
|
|
939
|
+
Write in them if you like: anything you put under a heading k0 does not print is left exactly where
|
|
940
|
+
you put it, and so is a line you add to the header at the top and a note you leave under the title.
|
|
941
|
+
|
|
942
|
+
**Commit the folder.** It is the only copy of this that outlives the database, and it is the way
|
|
943
|
+
back: open a repository k0 has no stories for and it reads the folder in and rebuilds them, keys
|
|
944
|
+
and all. That is the reason the files exist at all — the rest is a pleasant side effect.
|
|
945
|
+
|
|
946
|
+
The folder is written **only** inside `.k0/` — never your `.gitignore`, never a line anywhere else
|
|
947
|
+
in your repository — and a test walks the tree afterwards to prove nothing else appeared. The one
|
|
948
|
+
other thing that ever writes into a repository is `/k0-work`, which you have to ask for: it is
|
|
949
|
+
written out in full under [What it reads, and what it never
|
|
950
|
+
does](#what-it-reads-and-what-it-never-does).
|
|
951
|
+
|
|
952
|
+
One thing to expect: the git mark on that column will go from a tick to a dot the day the folder
|
|
953
|
+
first appears. That is honest — there is something there that is not committed yet — and committing
|
|
954
|
+
it puts the mark back.
|
|
955
|
+
|
|
956
|
+
### Switching it off
|
|
957
|
+
|
|
958
|
+
The whole feature is one line in `~/.k0/config.json`, the same file the idle timeout lives in:
|
|
959
|
+
|
|
960
|
+
```json
|
|
961
|
+
{ "backlog": false }
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
and the board is exactly the board it has always been: nothing extra on a note, no next-step
|
|
965
|
+
button, no Kanban/List switch in the bar, no lanes, **no `.k0/` folder created in any repository**,
|
|
966
|
+
and the commands say plainly that the backlog is switched off rather than reporting an empty one.
|
|
967
|
+
Telling somebody their backlog is empty when it is really turned off is the one answer worse than
|
|
968
|
+
no answer. The `+` goes back to being a plain `+` that opens the story dialog, with no menu behind
|
|
969
|
+
it and no epic on the form.
|
|
970
|
+
|
|
971
|
+
It is in that file and not in k0's database on purpose: a switch you would need `sqlite3` to reach
|
|
972
|
+
is not a switch. k0 re-reads the file whenever it changes, so nothing has to be restarted, and
|
|
973
|
+
deleting the line puts the default back. `"updateCheck": false` is its neighbour — [the one that
|
|
974
|
+
stops the npm question](#what-installing-it-changes).
|
|
975
|
+
|
|
976
|
+
---
|
|
977
|
+
|
|
342
978
|
## The ChangeLog
|
|
343
979
|
|
|
344
980
|
The git mark answers "is this safe" for one repository, right now. The **ChangeLog** answers a
|
|
@@ -359,7 +995,7 @@ page that comes up empty after every weekend is a page you stop opening.
|
|
|
359
995
|
**Only what you touched in that window appears.** A repository that has been dirty since March
|
|
360
996
|
and that you have not opened since is not news, and a summary that repeats it every morning is
|
|
361
997
|
one nobody is still reading by Thursday. Something has to have happened there — a commit, a file
|
|
362
|
-
saved, a
|
|
998
|
+
saved, a story moved — before k0 will tell you what is still outstanding in it. And only **your**
|
|
363
999
|
commits are counted: k0 asks git which email you commit with in that repository and shows that
|
|
364
1000
|
person's day, so a repository shared with other people still tells you about yours.
|
|
365
1001
|
|
|
@@ -369,9 +1005,10 @@ not believe the paragraph above it.
|
|
|
369
1005
|
|
|
370
1006
|
### Who writes it
|
|
371
1007
|
|
|
372
|
-
k0 does not. **k0
|
|
373
|
-
model of its own would mean a key to keep,
|
|
374
|
-
|
|
1008
|
+
k0 does not. **No model of k0's own reads your work**, and that is worth more than a better
|
|
1009
|
+
paragraph: a model of its own would mean a key to keep, a second account to configure, and your
|
|
1010
|
+
commit messages going out over a wire to somebody's model. The facts are gathered on this machine
|
|
1011
|
+
and written up here; what k0 Cloud keeps is your board, not your commits or your diffs.
|
|
375
1012
|
|
|
376
1013
|
It does not need one. If you are running k0 you already have Claude Code installed, signed in and
|
|
377
1014
|
paid for — that is the whole point of the board — so the model is already here. k0 works out the
|
|
@@ -380,7 +1017,7 @@ on the board, and there is nothing to set up: the skill that does the writing sh
|
|
|
380
1017
|
package, the same way `/k0-import` does.
|
|
381
1018
|
|
|
382
1019
|
It is written **in your language**, without a setting anywhere, because it is written out of your
|
|
383
|
-
own commit messages and
|
|
1020
|
+
own commit messages and story titles.
|
|
384
1021
|
|
|
385
1022
|
Nothing is saved. Every time you open the page it is written again, and changing the window
|
|
386
1023
|
writes it again — which is why there is no stale summary to clear and no history to prune.
|
|
@@ -390,11 +1027,121 @@ saying why the rest is missing.
|
|
|
390
1027
|
|
|
391
1028
|
---
|
|
392
1029
|
|
|
1030
|
+
## What's New
|
|
1031
|
+
|
|
1032
|
+
k0 updates by having its files replaced under it. You restart, everything looks the same, and
|
|
1033
|
+
whatever changed is in a file called `CHANGELOG.md` that nobody opens. So the version you are
|
|
1034
|
+
running drifts away from the one you learned, and the new thing sits there unused because you
|
|
1035
|
+
never found out it was there.
|
|
1036
|
+
|
|
1037
|
+
A small **mark appears next to `k0`** in the top bar for exactly two reasons: k0 moved on while you
|
|
1038
|
+
were not looking, or npm says there is a version newer than the one installed here. Hover it and it
|
|
1039
|
+
says which. **It never opens the page by itself** — it sits next to the name and waits, and it goes
|
|
1040
|
+
out when you have read the page, not when you close the tab.
|
|
1041
|
+
|
|
1042
|
+
The page says which two versions it stands between — *you had k0 0.3.1, you are running 0.4.0 now,
|
|
1043
|
+
two versions later* — and then says what that means in prose, written by your own Claude out of the
|
|
1044
|
+
changelog entries in between. Two controls, and both of them change who it is being written for
|
|
1045
|
+
rather than what is in it: **the language**, and **how technical** — `Plain`, `Normal` or `Nerd`.
|
|
1046
|
+
Both are remembered, because coming back to find the page in a language you do not read is the
|
|
1047
|
+
whole page wasted.
|
|
1048
|
+
|
|
1049
|
+
Underneath, folded open from the first moment, are the changelog entries themselves, exactly as
|
|
1050
|
+
they were written. While the prose is being written they are what there is to read; afterwards they
|
|
1051
|
+
are what you check it against.
|
|
1052
|
+
|
|
1053
|
+
It is the same machinery as the ChangeLog, and it has the same shape: nothing is stored, no model
|
|
1054
|
+
of k0's own and no key of its own — the Claude Code you already pay for does the writing, on this
|
|
1055
|
+
machine. Nothing is downloaded either. k0 cannot update itself; the most it can do is say a newer
|
|
1056
|
+
version exists, and leave `npx k0-board@latest` to you.
|
|
1057
|
+
|
|
1058
|
+
---
|
|
1059
|
+
|
|
1060
|
+
## Usage: what your sessions consumed
|
|
1061
|
+
|
|
1062
|
+
The icon with three bars, next to the ChangeLog's, opens a page that answers a question Claude Code
|
|
1063
|
+
leaves you to guess at: **where did the week go?** You switch between models, between efforts,
|
|
1064
|
+
between one agent and a whole workflow, and between accounts, and the only thing you ever see is a
|
|
1065
|
+
limit arriving.
|
|
1066
|
+
|
|
1067
|
+
A week at a time, Monday to Sunday, with the arrows to go back:
|
|
1068
|
+
|
|
1069
|
+
- **what each day would have cost at the API price list**, stacked by model. With a subscription
|
|
1070
|
+
you do not pay this — it is the one scale on which a Fable hour and a Sonnet hour can be put side
|
|
1071
|
+
by side, and the page says so;
|
|
1072
|
+
- **how full each account's weekly limit was**, as a line per account, and the five-hour limit as
|
|
1073
|
+
it was last seen;
|
|
1074
|
+
- the week split **by model and effort** (fast mode is a row of its own), by **who did the work** —
|
|
1075
|
+
the conversation itself, its subagents, or a workflow's agents — by **repository** and by
|
|
1076
|
+
**account**;
|
|
1077
|
+
- and every **session**, the most expensive first: the model and effort it ran on, when it started,
|
|
1078
|
+
how long Claude actually worked on your turns (not how long the window was open), its tokens, its
|
|
1079
|
+
cost, its estimated share of the weekly limit, and how many times a limit stopped it. A session k0
|
|
1080
|
+
started or imported links to its story, which opens on the board.
|
|
1081
|
+
|
|
1082
|
+
**It costs nothing to find out.** No model is asked and nothing goes over the network: Claude Code
|
|
1083
|
+
already writes every reply's token counts, model and effort into the transcripts on your disk, and
|
|
1084
|
+
k0 reads them as they grow — the history first, a few megabytes at a time so the board never
|
|
1085
|
+
stalls, and after that once a minute. The first time, the page says how much history is still left
|
|
1086
|
+
to read.
|
|
1087
|
+
|
|
1088
|
+
Two things are not in the transcripts, and the page is straight about both:
|
|
1089
|
+
|
|
1090
|
+
- **Which account a reply came from.** Claude Code only records the account signed in *now*. k0
|
|
1091
|
+
writes down every change of account it sees from the moment it is running, and the statusline
|
|
1092
|
+
snippet below writes down the account of every session it draws. Everything before that stays
|
|
1093
|
+
**"Unknown account"** — it is not guessed.
|
|
1094
|
+
- **How full the limits are.** Claude Code tells the statusline and keeps it nowhere else. So the
|
|
1095
|
+
statusline has to write it down:
|
|
1096
|
+
|
|
1097
|
+
### The limits: a few lines in your statusline
|
|
1098
|
+
|
|
1099
|
+
If you have a statusline command, add this to it, where it has read Claude Code's JSON from standard
|
|
1100
|
+
input into `input` (Node, no packages; the same idea works in any language). It appends a line to
|
|
1101
|
+
`~/.k0/usage/limits.jsonl` only when a number has changed, and never breaks the bar if anything
|
|
1102
|
+
fails:
|
|
1103
|
+
|
|
1104
|
+
```js
|
|
1105
|
+
try {
|
|
1106
|
+
const fs = require('fs'), path = require('path'), os = require('os')
|
|
1107
|
+
const data = JSON.parse(input), rl = data.rate_limits
|
|
1108
|
+
if (rl && (rl.five_hour || rl.seven_day)) {
|
|
1109
|
+
const pick = (w) => (w ? { pct: w.used_percentage, resets_at: w.resets_at } : null)
|
|
1110
|
+
const now = { five_hour: pick(rl.five_hour), seven_day: pick(rl.seven_day) }
|
|
1111
|
+
const dir = path.join(os.homedir(), '.k0', 'usage'), seen = path.join(dir, '.last')
|
|
1112
|
+
const sig = JSON.stringify([data.session_id, now])
|
|
1113
|
+
let last = ''
|
|
1114
|
+
try { last = fs.readFileSync(seen, 'utf8') } catch {}
|
|
1115
|
+
if (sig !== last) {
|
|
1116
|
+
const a = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.claude.json'), 'utf8')).oauthAccount || {}
|
|
1117
|
+
const account = { uuid: a.accountUuid, email: a.emailAddress, org_type: a.organizationType, tier: a.organizationRateLimitTier }
|
|
1118
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
1119
|
+
fs.appendFileSync(path.join(dir, 'limits.jsonl'),
|
|
1120
|
+
JSON.stringify({ at: Date.now(), session_id: data.session_id, account, model: data.model?.id, ...now }) + '\n')
|
|
1121
|
+
fs.writeFileSync(seen, sig)
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
} catch {}
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
Claude Code only passes the limits to the statusline on a subscription, and only after the first
|
|
1128
|
+
reply of a session. Without the snippet the page works the same, with the limits chart empty and a
|
|
1129
|
+
note saying why.
|
|
1130
|
+
|
|
1131
|
+
The share of the weekly limit next to each session is an **estimate**, and marked with `≈`: the
|
|
1132
|
+
statusline says how full the week is, not who filled it, so each rise is shared among the sessions
|
|
1133
|
+
that account ran in that hour, in proportion to their cost.
|
|
1134
|
+
|
|
1135
|
+
The prices are Anthropic's published API rates, dated in the source. A model k0 does not have a
|
|
1136
|
+
price for is counted in tokens and shown as `?` in dollars — never as free.
|
|
1137
|
+
|
|
1138
|
+
---
|
|
1139
|
+
|
|
393
1140
|
## The files of a session
|
|
394
1141
|
|
|
395
1142
|
The git mark is also the door: clicking it opens a file viewer **in another tab**, and the board
|
|
396
1143
|
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
|
|
1144
|
+
yet — a **lens** takes its place, so every story and every column still leads in.
|
|
398
1145
|
|
|
399
1146
|
Files on the left, what they say on the right, and a divider in between that you can drag.
|
|
400
1147
|
|
|
@@ -403,6 +1150,18 @@ a real repository code is 95% of the files, and among two thousand `.tsx` files
|
|
|
403
1150
|
were after cannot be found. This closes nothing off: a code file reached by a link inside a
|
|
404
1151
|
document still opens, and so do images — and the configuration is one switch away, below.
|
|
405
1152
|
|
|
1153
|
+
A **generated directory** — `out/`, `dist/`, `build/` — is walked into like any other, and the
|
|
1154
|
+
documents in it are listed like any others: the PDFs, and the pages you open with a double click.
|
|
1155
|
+
A document is a document wherever it was made, and it has to be findable by name. What stays out
|
|
1156
|
+
is the configuration a build leaves lying there, and the directories that hold nothing anybody
|
|
1157
|
+
reads — `node_modules` and its like — which are not walked into at all.
|
|
1158
|
+
|
|
1159
|
+
There is **one exception, and only one**: where git is in charge, git decides. k0 reads a
|
|
1160
|
+
directory your `.gitignore` names only to go and fetch the finished documents from it — the PDFs,
|
|
1161
|
+
the Word files — never the pages, because a real site's ignored `dist/` is four thousand pages and
|
|
1162
|
+
not one of them is the file you went looking for. Where git names the directory itself, everything
|
|
1163
|
+
in it comes through, pages included.
|
|
1164
|
+
|
|
406
1165
|
At the top come the **folders**, then the files, in three groups:
|
|
407
1166
|
|
|
408
1167
|
- **Changed** — what this session has touched: files still hanging in the working tree plus the
|
|
@@ -503,9 +1262,14 @@ the summary in the chat says what it touched and **names the files already**. Cl
|
|
|
503
1262
|
the top, paste that piece of conversation, press **Find the files**, and the list on the left
|
|
504
1263
|
narrows to the files that text names.
|
|
505
1264
|
|
|
506
|
-
It looks **only for the names written down**, not for the subject: no index
|
|
507
|
-
|
|
508
|
-
|
|
1265
|
+
It looks **only for the names written down**, not for the subject: no index and no waiting — the
|
|
1266
|
+
file listing is already in the browser. The price is stated: a file the chat talks about without
|
|
1267
|
+
ever naming does not come out, and for that there is the search above.
|
|
1268
|
+
|
|
1269
|
+
One question does go out, and only one: when the text writes a name **in full** and the listing has
|
|
1270
|
+
no such file, the disk is asked about those names and no others. That is how a document under an
|
|
1271
|
+
ignored directory comes out of a paste — the listing never saw it, but a text naming a file names
|
|
1272
|
+
it whole.
|
|
509
1273
|
|
|
510
1274
|
The results come in two groups, because they are two different degrees of certainty:
|
|
511
1275
|
|
|
@@ -536,10 +1300,45 @@ The hard part is not finding the names, it is choosing **which**. In a repositor
|
|
|
536
1300
|
directory up, and so on to the top. If it is still ambiguous, **it does not become a link**:
|
|
537
1301
|
better nothing than sending you to the wrong README.
|
|
538
1302
|
|
|
539
|
-
Files the listing does **not** show open too.
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
stay out: `.claude/` is configuration, not something to read.
|
|
1303
|
+
Files the listing does **not** show open too. Where git rules, a directory your `.gitignore` names
|
|
1304
|
+
gives the listing only its finished documents — so a page under an ignored `dist/` is not in it.
|
|
1305
|
+
Named inside a document it still counts: the document said so, not the directory. Hidden
|
|
1306
|
+
directories really do stay out: `.claude/` is configuration, not something to read.
|
|
1307
|
+
|
|
1308
|
+
### What Claude points at, one click away
|
|
1309
|
+
|
|
1310
|
+
The same idea, one step earlier: in the Claude Code session itself. Claude says "open
|
|
1311
|
+
`localhost:4321/projects/furniture/`", "the photos are in `docs/projects/sideboard-140/`", "the
|
|
1312
|
+
manual is `README.md`", or publishes an artifact and talks about it by its title — and in the
|
|
1313
|
+
terminal all of that was dead text. With the `k0-links` mod installed, and **while k0 is running**,
|
|
1314
|
+
everything the last reply pointed at is in a row **just above the prompt**, and **one plain click**
|
|
1315
|
+
on an entry opens it:
|
|
1316
|
+
|
|
1317
|
+
| | What the reply wrote | Opens in |
|
|
1318
|
+
|---|---|---|
|
|
1319
|
+
| 🌐 | an address — `https://…`, `localhost:4321/…`, `alessioragni.com/projects/…` | the browser, in a new tab |
|
|
1320
|
+
| 📁 | a folder, relative to the repository or written in full | Finder |
|
|
1321
|
+
| 📄 | a document the viewer shows — Markdown, HTML, text, PDF, Word… | this viewer, in a new tab |
|
|
1322
|
+
| ✦ | the title of an artifact this session published | its claude.ai page |
|
|
1323
|
+
|
|
1324
|
+
Code files and a repository's own name stay out of the row: they are not places you go to. A
|
|
1325
|
+
domain counts as an address only with a path after it — `alessioragni.com` alone is usually the
|
|
1326
|
+
name of a repository.
|
|
1327
|
+
|
|
1328
|
+
**Claude's reply is left exactly as Claude Code draws it.** The macOS Terminal cannot open a link
|
|
1329
|
+
drawn inside the text — it shows the words, and a click does nothing — and redrawing every reply to
|
|
1330
|
+
get around that would have changed a screen that works. The row is the mod's own space, and its
|
|
1331
|
+
entries are buttons, which Claude Code itself receives the click for. That needs Claude Code's
|
|
1332
|
+
**fullscreen** view (`"tui": "fullscreen"` in `~/.claude/settings.json`, or `/config`), where the
|
|
1333
|
+
mouse reaches it; in the classic view the row is still there, and ctrl+x tab then Enter opens an
|
|
1334
|
+
entry.
|
|
1335
|
+
|
|
1336
|
+
It is a **mod**, a small piece of code Claude Code runs inside itself, and the installer copies it
|
|
1337
|
+
into `~/.claude/skills/k0-links` together with the commands, behind the same question. So it is
|
|
1338
|
+
there in **every** Claude Code session on the machine, not only the ones a story opened — new
|
|
1339
|
+
sessions pick it up when they start, an open one with `/reload-plugins` — and it does nothing at
|
|
1340
|
+
all while k0 is off. Documents become entries only in **a repository k0 knows**; elsewhere the
|
|
1341
|
+
addresses, folders and artifacts still do.
|
|
543
1342
|
|
|
544
1343
|
### On paper
|
|
545
1344
|
|
|
@@ -565,11 +1364,11 @@ kernel's own verdict, plus one added rule: amber when memory in use goes over 90
|
|
|
565
1364
|
the whole picture, including **what is heavy and is not k0**: if the machine is struggling because
|
|
566
1365
|
of Chrome it is fair to know that, instead of closing sessions for nothing.
|
|
567
1366
|
|
|
568
|
-
On every
|
|
1367
|
+
On every story there is **what that session weighs**. Not the `claude` process: everything it has
|
|
569
1368
|
dragged along — the MCP servers, the Chromes they open, a `tsc` started from a commit hook. That
|
|
570
|
-
is where the memory goes, and it is the thing no other tool can attribute to the right
|
|
1369
|
+
is where the memory goes, and it is the thing no other tool can attribute to the right story.
|
|
571
1370
|
|
|
572
|
-
Only one
|
|
1371
|
+
Only one story is red, the heaviest, and only while the machine is struggling: if they were all
|
|
573
1372
|
red they would say nothing.
|
|
574
1373
|
|
|
575
1374
|
Two things said plainly. The CPU is the CPU of **right now**, worked out from the difference in
|
|
@@ -578,7 +1377,7 @@ which on an old session says nothing about this minute. And summing the memory o
|
|
|
578
1377
|
counts shared memory twice, so the total is a little generous: it is the usual approximation, and
|
|
579
1378
|
it is the right one for the question that matters — which one do I close to feel better.
|
|
580
1379
|
|
|
581
|
-
And once you have decided, **`Close` on that
|
|
1380
|
+
And once you have decided, **`Close` on that story is how you give the memory back**: the session
|
|
582
1381
|
is stopped and its window goes, the work stays on the board as it was, and `Resume` picks the
|
|
583
1382
|
conversation up where it left off. Nothing has to be declared finished to stop weighing.
|
|
584
1383
|
|
|
@@ -586,6 +1385,40 @@ Reading the process table costs little on a calm machine and a lot on a struggli
|
|
|
586
1385
|
exactly when you look at it. So it is sampled every three seconds, and **only while the board is
|
|
587
1386
|
open**.
|
|
588
1387
|
|
|
1388
|
+
### And what k0 costs
|
|
1389
|
+
|
|
1390
|
+
The chip measured everybody but itself, which is the one thing a program running under launchd for
|
|
1391
|
+
weeks should be least able to hide. Hover it and the last line is **k0's own weight, its CPU, how
|
|
1392
|
+
often it asks git anything, how many queries it is holding, and how hard the watching loop is
|
|
1393
|
+
currently running**.
|
|
1394
|
+
|
|
1395
|
+
That loop is the whole of k0's cost, and it now runs at the pace the work deserves. With a session
|
|
1396
|
+
open — or with you in front of the board — it goes round every two seconds. With neither, there is
|
|
1397
|
+
nothing it could see change, so it drops to **once a minute** and k0 stops costing anything on a
|
|
1398
|
+
machine nobody is using. Pressing anything wakes it at once, so nothing ever waits on it.
|
|
1399
|
+
|
|
1400
|
+
The git marks follow the same rule. Every repository on the board used to be asked `status` and
|
|
1401
|
+
`rev-list` every five seconds, all night; now the full list is only asked while you are looking,
|
|
1402
|
+
away from the board only the repositories a session is actually working in, and a reading is good
|
|
1403
|
+
for half a minute. Nothing in a repository changes faster than that unless you make it.
|
|
1404
|
+
|
|
1405
|
+
### And what the page downloads
|
|
1406
|
+
|
|
1407
|
+
The other half of the bill is paid by the browser, and it was the larger one. The board asked for
|
|
1408
|
+
everything k0 knows once a second and got it: two thirds of a megabyte, six hundred stories with
|
|
1409
|
+
their whole "Why" and their whole plan, most of them finished weeks ago and hidden from view. Over
|
|
1410
|
+
a day with one tab open that came to **fifty-six gigabytes**, to draw post-its that had not moved.
|
|
1411
|
+
|
|
1412
|
+
Now the board sends back a stamp of the answer it already has, and when the answer would be the
|
|
1413
|
+
same — which on a board nobody is touching is every round of every day — the server says so in a
|
|
1414
|
+
couple of hundred bytes and sends nothing else. When something really did change, what goes out is
|
|
1415
|
+
only what a post-it draws, compressed. The long texts come with the story's own panel, when you
|
|
1416
|
+
open one, where they were always read from anyway.
|
|
1417
|
+
|
|
1418
|
+
A still board also stops asking so often: after a few rounds saying nothing moved it drops to one
|
|
1419
|
+
in four seconds, and the first thing that moves — or your coming back to the tab — puts it
|
|
1420
|
+
straight back to one.
|
|
1421
|
+
|
|
589
1422
|
### And the ones you forget, k0 closes for you
|
|
590
1423
|
|
|
591
1424
|
The paragraph above assumes you noticed. Most of the time nobody does: the window that is costing
|
|
@@ -593,7 +1426,7 @@ you a gigabyte is the one you stopped thinking about yesterday. So **after twelv
|
|
|
593
1426
|
nothing happening, k0 does that `Close` itself** — the session is stopped, its window goes, and the
|
|
594
1427
|
memory comes back.
|
|
595
1428
|
|
|
596
|
-
Nothing is lost by it. The
|
|
1429
|
+
Nothing is lost by it. The story stays exactly where it is with the status it had, and **Resume**
|
|
597
1430
|
picks the conversation up where it was. That is the whole reason this is safe: a closed terminal
|
|
598
1431
|
has never been a lost session.
|
|
599
1432
|
|
|
@@ -609,12 +1442,12 @@ rest is left alone, and each for its own reason:
|
|
|
609
1442
|
there may be a command of yours running in it; k0 cannot see what it is, so k0 does not touch it.
|
|
610
1443
|
On the board it reads as yellow like any other, which is exactly why this one has to be said.
|
|
611
1444
|
|
|
612
|
-
And a window you were using an hour ago is never closed, whatever the
|
|
1445
|
+
And a window you were using an hour ago is never closed, whatever the story's history says. k0 has
|
|
613
1446
|
four clocks for a session — two of its own and two Claude Code keeps — and **the newest one wins**.
|
|
614
1447
|
Being wrong in that direction leaves a window open until tomorrow; being wrong the other way closes
|
|
615
1448
|
a terminal you were about to go back to.
|
|
616
1449
|
|
|
617
|
-
A
|
|
1450
|
+
A story k0 tidied away says so: where one you closed yourself reads *session closed*, this one reads
|
|
618
1451
|
*closed automatically*. Same italic, same place, one word different.
|
|
619
1452
|
|
|
620
1453
|
And the memory chip at the end of the top bar says it is watching, and from when: **RAM 79% · CPU
|
|
@@ -633,17 +1466,17 @@ settings file changes it, and **`0` switches it off** — see below.
|
|
|
633
1466
|
|
|
634
1467
|
An empty board is no help in getting your bearings. The installer offers to do this on the first
|
|
635
1468
|
run; afterwards, `/k0-import` from a Claude Code session picks up the sessions that already
|
|
636
|
-
happened — including the ones opened by hand, outside k0 — and puts them on the board as
|
|
1469
|
+
happened — including the ones opened by hand, outside k0 — and puts them on the board as stories:
|
|
637
1470
|
the last 14 days, at most the 10 most recent per repository. `/k0-import 30 5` changes the two
|
|
638
1471
|
numbers.
|
|
639
1472
|
|
|
640
1473
|
The difference between the two is the writing. The installer uses the name the session already
|
|
641
1474
|
had, or the first few words of the first prompt. `/k0-import` has Claude read the conversation and
|
|
642
1475
|
write a title and a description in the language it was held in. That description is the line in
|
|
643
|
-
italics under the title on the note, and importing is the only thing that writes one: a
|
|
1476
|
+
italics under the title on the note, and importing is the only thing that writes one: a story you
|
|
644
1477
|
write yourself has a title and a prompt, which is all it needs.
|
|
645
1478
|
|
|
646
|
-
Imported
|
|
1479
|
+
Imported stories are born yellow — *Your turn*: **Resume** reopens the conversation where it was,
|
|
647
1480
|
**Done** clears it away. Being dead sessions they do not light the tray icon. Running it again
|
|
648
1481
|
skips the ones already imported.
|
|
649
1482
|
|
|
@@ -656,8 +1489,12 @@ real machine that separated 145 genuine sessions from 867 automated ones, and it
|
|
|
656
1489
|
|
|
657
1490
|
## The statuses
|
|
658
1491
|
|
|
659
|
-
A
|
|
660
|
-
the
|
|
1492
|
+
A story **is** the colour of its status — there is nothing else to read. On the left is the code
|
|
1493
|
+
k0 speaks internally — the API, the menu bar icon and the colours in `web/base.css` all say these
|
|
1494
|
+
seven words — then how it reads on screen. None of the seven is a column in the database: `BACKLOG`
|
|
1495
|
+
and `COMPLETED` are worked out from the story (no session, and closed), and the other five belong
|
|
1496
|
+
to the live session, not to the story. See [`docs/database.md`](docs/database.md) for where each
|
|
1497
|
+
half really lives.
|
|
661
1498
|
|
|
662
1499
|
| | | | |
|
|
663
1500
|
|---|---|---|---|
|
|
@@ -679,12 +1516,12 @@ How awake the machine has to stay while sessions are working. It is a **scale of
|
|
|
679
1516
|
four switches: each includes the one before it, and exactly **one** is always lit. Clicking the lit
|
|
680
1517
|
one again does nothing — you leave a mode, you do not switch it off.
|
|
681
1518
|
|
|
682
|
-
| Icon | Mode | The machine | The screen | The text |
|
|
1519
|
+
| Icon | Mode | The machine | The screen | The text and the windows |
|
|
683
1520
|
|---|---|---|---|---|
|
|
684
1521
|
| two **z** | **Sleep** | sleeps as it normally would | goes off | normal |
|
|
685
1522
|
| a **palm tree** | **Away** | does not sleep, not even with the lid closed | may sleep and lock | normal |
|
|
686
1523
|
| a **nerd face** with glasses | **Nerd** | does not sleep | **stays on** | normal |
|
|
687
|
-
| a **car** | **Driving** | does not sleep | **stays on** | **large
|
|
1524
|
+
| a **car** | **Driving** | does not sleep | **stays on** | **large**: the text here and in the terminals, and the terminals fill the screen |
|
|
688
1525
|
|
|
689
1526
|
The four icons do not describe the machine: they describe **where you are**. Asleep, away, at the
|
|
690
1527
|
desk, watching from across the room. That is where the order comes from, and it is why the second
|
|
@@ -694,9 +1531,9 @@ one is a palm tree and not a technical symbol: the mode does not say "the machin
|
|
|
694
1531
|
The four buttons are at the end of the board's bar, or four ticked entries in the tray menu. They
|
|
695
1532
|
are the same control: changed on one side, the other catches up within a couple of seconds.
|
|
696
1533
|
|
|
697
|
-
**Nerd** and **Driving** do exactly the same things to the machine: the only difference is
|
|
698
|
-
|
|
699
|
-
room".
|
|
1534
|
+
**Nerd** and **Driving** do exactly the same things to the machine: the only difference is how big
|
|
1535
|
+
everything is — the text, and the terminal windows it sits in. Nerd is "I am sitting here
|
|
1536
|
+
programming", Driving is "I glance at it from across the room".
|
|
700
1537
|
|
|
701
1538
|
### Why an idle inhibitor is not enough
|
|
702
1539
|
|
|
@@ -720,7 +1557,7 @@ it does not do.
|
|
|
720
1557
|
no business rewriting behind your back. The switch reports itself unavailable, and `k0-board
|
|
721
1558
|
doctor` says where to change it yourself.
|
|
722
1559
|
|
|
723
|
-
### Large text, and windows
|
|
1560
|
+
### Large text, and windows to match
|
|
724
1561
|
|
|
725
1562
|
In Driving the **text inside the terminals** goes from the profile's size to 22, the board's from
|
|
726
1563
|
17 to 22 pixels, and the **things you click** grow too — the `+`, the git lens, the corner pencil
|
|
@@ -732,16 +1569,27 @@ they reorder by urgency, reddest to the left. On a screen you glance at, two or
|
|
|
732
1569
|
visible at a time and the most urgent one has to come to you. Full screen you have them all in
|
|
733
1570
|
front of you already, and a board that reshuffles itself while you work only loses your place.
|
|
734
1571
|
|
|
735
|
-
**The windows
|
|
736
|
-
|
|
737
|
-
|
|
1572
|
+
**The windows grow with the text.** In Driving a terminal takes the whole free screen; leave
|
|
1573
|
+
Driving and it goes back to the usual 86% centred, with the text back at the profile's size. It is
|
|
1574
|
+
one gesture and not two, and it lands on the terminals **already open**, not only on the ones you
|
|
1575
|
+
open next.
|
|
738
1576
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
1577
|
+
It used to be the opposite, and the reason is worth keeping in mind: Terminal.app holds rows and
|
|
1578
|
+
columns when the font changes and resizes the window to match — going from 12 to 22 turns a 700×500
|
|
1579
|
+
window into 1378×856, measured — so k0 read each window's own bounds first and put them back, and
|
|
1580
|
+
nothing moved. What that left behind was a window holding 22 point text in a box measured for 12.
|
|
1581
|
+
Half a gesture is worse than none, so the size of the text and the size of the window now travel
|
|
1582
|
+
together, and the price is said plainly: **a window you had dragged onto another screen comes back
|
|
1583
|
+
to the middle of the main one.**
|
|
743
1584
|
|
|
744
|
-
k0
|
|
1585
|
+
**All of them, every time.** k0 asks Terminal once for the windows it has open and changes those
|
|
1586
|
+
that are its own, rather than asking after every window id it has ever written down. On a board
|
|
1587
|
+
with two hundred stories almost every one of those ids names a window closed weeks ago, and asking
|
|
1588
|
+
after them one at a time took seven seconds — long enough to be cut short halfway, which left half
|
|
1589
|
+
the terminals large, half of them small, and nothing said about it anywhere. Walking the windows
|
|
1590
|
+
that exist takes about a second and does not grow with the board.
|
|
1591
|
+
|
|
1592
|
+
k0 touches **only its own windows**, the ones born from a story.
|
|
745
1593
|
|
|
746
1594
|
### What it remembers, and what it looks at
|
|
747
1595
|
|
|
@@ -830,7 +1678,7 @@ Worth knowing:
|
|
|
830
1678
|
|
|
831
1679
|
Two side effects of the Cmd+V k0 uses to write your prompt, worth knowing:
|
|
832
1680
|
|
|
833
|
-
- the
|
|
1681
|
+
- the story's prompt replaces whatever was on your clipboard (if the paste fails, the clipboard is
|
|
834
1682
|
put back);
|
|
835
1683
|
- to paste, the terminal is brought to the front for an instant: if you happen to be **dictating**
|
|
836
1684
|
at that moment, the dictation lands in there and sticks to the prompt.
|
|
@@ -859,7 +1707,7 @@ itself on the next round: nothing to restart.
|
|
|
859
1707
|
|
|
860
1708
|
| | |
|
|
861
1709
|
|---|---|
|
|
862
|
-
| `closeIdleTerminalsAfterHours` | How long a yellow
|
|
1710
|
+
| `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. |
|
|
863
1711
|
|
|
864
1712
|
Delete a line to go back to its default; a file k0 cannot read is ignored altogether and the
|
|
865
1713
|
defaults hold, rather than k0 refusing to start over a stray comma.
|
|
@@ -887,49 +1735,110 @@ platform/
|
|
|
887
1735
|
shared/ what more than one of them needs: tmux, running commands, reading a process
|
|
888
1736
|
table, and reading who is holding which port
|
|
889
1737
|
server/
|
|
890
|
-
index.js the http server, the API, and the watching loop
|
|
1738
|
+
index.js the http server, the API, and the watching loop — every two seconds while a
|
|
1739
|
+
session is running or somebody is at the board, once a minute when neither, and
|
|
1740
|
+
awake at once on anything you press
|
|
891
1741
|
guard.js who is allowed to talk to this server at all: the Host and the Origin
|
|
892
|
-
db.js SQLite (node:sqlite): the
|
|
1742
|
+
db.js SQLite (node:sqlite): the only file that talks to it. epic, story, session,
|
|
1743
|
+
decision, round, check_item, dependency, session_event and the rest —
|
|
893
1744
|
docs/database.md
|
|
1745
|
+
backlog.js the model: epics, stories, tasks, decisions, dependencies, the order, and
|
|
1746
|
+
what to pick up next. Pure logic over db.js — no http, no disk
|
|
1747
|
+
mirror.js writes and re-reads <repo>/.k0/, the readable copy of the backlog. It writes
|
|
1748
|
+
nowhere else, ever, and a test proves it. No domain logic
|
|
1749
|
+
worktree.js a session working copy of its own: open it from the branch you are on, merge
|
|
1750
|
+
it back, destroy it. Never a push, never a pull request, never a conflict
|
|
1751
|
+
resolved for you, and it never runs tests or a build in there
|
|
1752
|
+
update.js one of the two places k0 reaches outside — what npm says the newest version
|
|
1753
|
+
is — and the version jump that puts the mark next to k0 in the top bar
|
|
1754
|
+
cloud.js the other place k0 reaches outside, and the only door to k0 Cloud: signing
|
|
1755
|
+
in, the next K number, rows up and rows down. Plain fetch, no client library
|
|
1756
|
+
sync.js moves rows between the board and the cloud every five seconds, and the
|
|
1757
|
+
one-time move of a board that predates the account. Carries rows; decides
|
|
1758
|
+
nothing about what they mean
|
|
894
1759
|
paths.js where the board, the logs, the settings and the cache live
|
|
895
1760
|
settings.js the few things you can change, and the file that is the list of them —
|
|
896
1761
|
~/.k0/config.json, written out with everything in it and re-read when it changes
|
|
897
1762
|
idle.js which terminals have sat still long enough to be closed and given back. Only the
|
|
898
1763
|
deciding: it kills nothing, so every rule in it can be proved without a machine
|
|
899
1764
|
watcher.js reads Claude Code's own files and derives the statuses; also renames a session
|
|
1765
|
+
usage.js reads what every session consumed out of its transcripts, a few megabytes at a
|
|
1766
|
+
time and only what is new, plus the statusline's limit samples and which account
|
|
1767
|
+
is signed in; adds it up by the hour for the Usage page. Never asks a model
|
|
1768
|
+
prices.js the API price list the Usage page's dollars come from, dated; a model not on it
|
|
1769
|
+
has no price rather than a zero one
|
|
900
1770
|
git.js the only one that talks to git: what is committed, what is pushed, whose it is,
|
|
901
1771
|
and — for the ChangeLog — what the commits actually said
|
|
902
1772
|
changelog.js gathers what happened in a window, out of git and out of session_event. Decides
|
|
903
1773
|
which repositories are worth mentioning at all, and stores nothing
|
|
904
1774
|
writer.js hands those facts to the Claude Code already on this machine and gets the words
|
|
905
|
-
back. The only place k0 starts a model, and it never leaves the machine to do
|
|
1775
|
+
back. The only place k0 starts a model, and it never leaves the machine to do
|
|
1776
|
+
it. Keyed by skill and by window, so the ChangeLog and the What is New page can
|
|
1777
|
+
be writing at the same time without cancelling each other
|
|
906
1778
|
launcher.js starts and resumes sessions, through the platform's terminal
|
|
907
1779
|
servers.js the dev server of a repository: what starts it, whether it is up, and on what
|
|
908
1780
|
port. The only thing k0 starts that is meant to outlive k0
|
|
909
|
-
mode.js the four modes: how awake to keep the machine, and whether
|
|
910
|
-
|
|
911
|
-
|
|
1781
|
+
mode.js the four modes: how awake to keep the machine, and whether text and windows go
|
|
1782
|
+
large. How large is `launcher.js`, which is what talks to the terminal
|
|
1783
|
+
projects.js the repositories, in the order you last used them — and which directories k0 is
|
|
1784
|
+
allowed to open at all, which is one answer and not one per endpoint
|
|
1785
|
+
sessions.js digs already-lived sessions out of the transcripts, to import as stories
|
|
912
1786
|
files.js the only one that reads the projects' disk — and the only one that writes back
|
|
913
1787
|
into it: what is there, what changed, what it says, and the one small write
|
|
914
|
-
machine.js the only one that looks at processes and memory: what it all costs, and who is
|
|
1788
|
+
machine.js the only one that looks at processes and memory: what it all costs, and who is
|
|
1789
|
+
costing it — k0's own process included, which is the only honest way to publish
|
|
1790
|
+
a number like that
|
|
915
1791
|
pdf.js the document on paper, printed by a headless browser
|
|
916
|
-
web/ the
|
|
1792
|
+
web/ the four pages (html, css, js served exactly as they are)
|
|
917
1793
|
index.html the board — board.js, board.css, view.js. A note is never taller than it is
|
|
918
1794
|
wide: the title, the age and the buttons always show, the text in the middle is
|
|
919
1795
|
what gets clipped
|
|
1796
|
+
list.js the same stories as rows, list.css beside it: the other shape of the same page,
|
|
1797
|
+
not a page of its own. Handed the stories the board is already showing, so the
|
|
1798
|
+
filters cannot mean two things, and the story you open follows a live discussion
|
|
1799
|
+
by asking .../live once a second, the cadence the rest of k0 already uses
|
|
920
1800
|
files.html the file viewer — files.js, files.css
|
|
921
|
-
changelog.html what you have been doing — changelog.js, changelog.css.
|
|
922
|
-
|
|
923
|
-
|
|
1801
|
+
changelog.html what you have been doing — changelog.js, changelog.css. Read top to bottom
|
|
1802
|
+
instead of looked at, so it is one of the three pages that scroll
|
|
1803
|
+
whatsnew.html what changed in k0 between the version you had and this one — whatsnew.js,
|
|
1804
|
+
whatsnew.css. Reached from the mark next to k0, and never opened by itself
|
|
1805
|
+
base.css colours, fonts and scale: the house variables, shared by all of them
|
|
1806
|
+
account.js the account on the board: the chip at the end of the top bar, and the screen
|
|
1807
|
+
in front of the board until you are signed in, let in and moved
|
|
1808
|
+
awake.js the one place that repeats anything: a job that runs only while its tab is in
|
|
1809
|
+
front of you, and takes a fresh reading the moment you come back to it. A page
|
|
1810
|
+
nobody can see must not be asking the server anything — asking is also how the
|
|
1811
|
+
server learns somebody is watching
|
|
924
1812
|
md.js markdown laid out, written by hand because nothing here is compiled
|
|
925
1813
|
recency.js which repositories are still warm, and which fold away into `Old`
|
|
926
|
-
fuzzy.js searching the names: the letters you type, in the order you type them
|
|
1814
|
+
fuzzy.js searching the names: the letters you type, in the order you type them — the
|
|
1815
|
+
file viewer, the repository the new story goes in, and the repository menu on
|
|
1816
|
+
the bar, which is drawn here rather than left to the system
|
|
927
1817
|
mentions.js which of a repository's files a piece of text names
|
|
928
1818
|
refs.js what a name written inside a document points at, and which of the nine READMEs
|
|
929
1819
|
json.js a JSON file as a tree that folds, and the search that opens the right branches
|
|
930
1820
|
conf.js an .env as the table it always was, and YAML/TOML/INI with their parts told apart
|
|
931
1821
|
.claude/skills/
|
|
932
1822
|
k0-import/ the skill that fills the board with sessions you have already had
|
|
1823
|
+
k0-epic/ the long way in: rounds of questions, decisions, then a tree of stories
|
|
1824
|
+
k0-story/ one story, fast path, no ceremony
|
|
1825
|
+
k0-discuss/ an existing story, discussed in rounds until nothing more would change it
|
|
1826
|
+
k0-split/ a story too big to close, split into tasks that inherit its decisions
|
|
1827
|
+
k0-plan/ plan mode, with the standing decisions injected as constraints
|
|
1828
|
+
k0-work/ the worktree, the work, the Log as it goes, and the merge back
|
|
1829
|
+
k0-ultracode/ the manager: a plan cut into assignments, an agent and a worktree each, and every
|
|
1830
|
+
story tested and counter-checked before the next one starts
|
|
1831
|
+
k0-verify/ the counter-check: every decision one by one, the checklist, the outcome
|
|
1832
|
+
k0-next/ what to pick up now, and why — the server decides, not the model
|
|
1833
|
+
k0-order/ priority and dependencies, dictated
|
|
1834
|
+
k0-links/ not a skill but a mod: hooks Claude Code runs inside itself. At the end of each
|
|
1835
|
+
reply it finds the addresses, folders and documents the reply named, asks the
|
|
1836
|
+
disk what each path is and k0, on loopback, which documents its viewer has
|
|
1837
|
+
(POST /api/files/exist), adds the artifacts the session published, and draws them
|
|
1838
|
+
as buttons in the row above the prompt; a press runs the system's `open`. It never
|
|
1839
|
+
touches the reply. links.js is the pure half, tested by npm test; nothing in it
|
|
1840
|
+
may come from k0's own folders, because it is copied out alone
|
|
1841
|
+
k0-whatsnew/ the What is New page, written from the changelog entries k0 hands it
|
|
933
1842
|
k0-changelog/ the one that turns the facts of a stretch of work into something readable. k0
|
|
934
1843
|
calls it by itself when the ChangeLog is opened, so it is in the package too
|
|
935
1844
|
changelog/ the one that writes the changelog and the documentation when work is finished.
|
|
@@ -937,36 +1846,97 @@ web/ the three pages (html, css, js served exactly as they are)
|
|
|
937
1846
|
commit-push-deploy/
|
|
938
1847
|
the road out: the documents, the tests, the commit, the push, and the tag that
|
|
939
1848
|
publishes. Also for whoever works on k0, and also not in the package
|
|
1849
|
+
supabase/ k0 Cloud's own side: migrations/ is its database (accounts, workspaces, the
|
|
1850
|
+
rows of every board, the counter), config.toml its sign-in settings. The secrets
|
|
1851
|
+
are in ~/.config/k0-cloud/.env, never in the repository
|
|
1852
|
+
site/ k0-board.com: static pages, no build. app/ is the read-only web board and the
|
|
1853
|
+
page where accounts are approved — both coming with the site
|
|
940
1854
|
docs/
|
|
941
|
-
database.md the shape of the database as it is now
|
|
1855
|
+
database.md the shape of the database as it is now, table by table, column by column
|
|
1856
|
+
method.md why a decision has to be an object, what a round of questions is for, and
|
|
1857
|
+
what the counter-check is actually checking
|
|
942
1858
|
testing.md how the tests are written, run and measured, and what is left untested on purpose
|
|
943
1859
|
test/ npm test — Node's own runner, no framework. See docs/testing.md
|
|
944
1860
|
harness.mjs check(label, got, want), and the sections the labels are grouped under
|
|
945
1861
|
```
|
|
946
1862
|
|
|
1863
|
+
### How the board reaches the cloud
|
|
1864
|
+
|
|
1865
|
+
The board's rules live on the machine, in SQLite, and they stay there: states, decisions, rounds,
|
|
1866
|
+
dependencies. The cloud does not model the board table by table. It keeps **one document per
|
|
1867
|
+
row**, keyed by a `uid` the machine gave that row, so a change to k0's own tables needs no change
|
|
1868
|
+
in the cloud. What the cloud does own is what a single machine cannot: who you are, whether you
|
|
1869
|
+
have been let in, which workspace your rows belong to — a personal one today, built so a team is a
|
|
1870
|
+
second kind of workspace and nothing else moves — and the one counter that numbers your stories.
|
|
1871
|
+
|
|
1872
|
+
**Changes are noticed by triggers, not by the code that makes them.** Every synced table has
|
|
1873
|
+
triggers that write a line into an `outbox` table on insert, update and delete. About forty places
|
|
1874
|
+
in `db.js` write to those tables, and a list of "remember to tell the cloud" calls would be forty
|
|
1875
|
+
chances to forget one; a trigger cannot be forgotten. Two switches decide whether the triggers
|
|
1876
|
+
write anything: one that is off until an account is linked, so a board with no cloud does not grow
|
|
1877
|
+
a queue for ever, and one that is on while rows that came *from* the cloud are being written, so
|
|
1878
|
+
they are not sent straight back.
|
|
1879
|
+
|
|
1880
|
+
A round, every five seconds, does three things in order: gives provisional keys their real
|
|
1881
|
+
numbers, oldest first; sends the outbox up as documents, with references to other rows written as
|
|
1882
|
+
`<column>_uid` because an integer id means nothing in another database; and fetches what other
|
|
1883
|
+
machines wrote since the last round, in the order that puts an epic before its stories and a story
|
|
1884
|
+
before its decisions. A row whose owner has not arrived yet is left for a later round rather than
|
|
1885
|
+
written pointing at nothing. A failed round never throws at the board: it says so in the chip and
|
|
1886
|
+
tries again.
|
|
1887
|
+
|
|
1888
|
+
In the cloud every row is fenced off by the database's own row-level rules: only a member of the
|
|
1889
|
+
workspace, with an approved account, can read or write it. The address and the key in `cloud.js`
|
|
1890
|
+
are public on purpose — the key identifies the project and grants nothing by itself.
|
|
1891
|
+
|
|
947
1892
|
### What it reads, and what it never does
|
|
948
1893
|
|
|
949
|
-
k0 reads your repositories. It writes into one
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1894
|
+
k0 reads your repositories. It writes into one in three places, and all three are named here
|
|
1895
|
+
because a tool that writes where you did not expect it is a tool you stop leaving running.
|
|
1896
|
+
|
|
1897
|
+
The first is the pencil in the file viewer, on a configuration file or a note that is already
|
|
1898
|
+
there. That write is deliberately narrow — no code, no new files, no deletions — it carries the
|
|
1899
|
+
file's own permissions across, it lands as a rename so an interrupted save leaves the old file
|
|
1900
|
+
whole, and it refuses outright if the file has changed on disk since the page read it.
|
|
954
1901
|
|
|
955
|
-
|
|
956
|
-
|
|
1902
|
+
The second is the `.k0/` folder, and only ever inside it: the readable copy of that repository's
|
|
1903
|
+
backlog, rewritten whenever a story changes. Never your `.gitignore`, never a file beside it, and
|
|
1904
|
+
a test walks the tree afterwards to prove nothing else appeared. With the backlog switched off the
|
|
1905
|
+
folder is never made at all.
|
|
1906
|
+
|
|
1907
|
+
The third only happens when you ask for it, and it is `/k0-work` opening a worktree. That one is
|
|
1908
|
+
the largest thing k0 does to a repository, so it is worth reading twice: it adds a worktree under
|
|
1909
|
+
`.claude/worktrees/`, it writes two lines into `.git/info/exclude` so that directory does not show
|
|
1910
|
+
up as something you forgot to commit, and at the end it commits inside the worktree and merges
|
|
1911
|
+
that branch into the branch you were standing on. It never pushes, never opens a pull request, and
|
|
1912
|
+
never resolves a conflict on your behalf — where it cannot merge cleanly it stops and says so.
|
|
1913
|
+
None of it happens unless you run `/k0-work`.
|
|
1914
|
+
|
|
1915
|
+
k0 does not emulate a terminal and installs no settings hooks. The one thing it puts inside Claude
|
|
1916
|
+
Code is [the `k0-links` mod](#what-claude-points-at-one-click-away), and only if you
|
|
1917
|
+
said yes: it draws a row above the prompt, never touches a reply, and talks to nobody but k0 on the
|
|
1918
|
+
loopback address. Beyond that k0 reads what Claude Code already writes for itself:
|
|
957
1919
|
|
|
958
1920
|
- `~/.claude/sessions/<pid>.json` — live status (`busy`, `idle`, `waiting` with the reason for the
|
|
959
1921
|
wait) and the session id;
|
|
960
1922
|
- `~/.claude/projects/<project>/<session>.jsonl` — the transcript, read incrementally, which is
|
|
961
|
-
where you can tell whether you are inside a plan
|
|
1923
|
+
where you can tell whether you are inside a plan — and, for the Usage page, what every reply
|
|
1924
|
+
consumed, the subagents' and workflows' transcripts beside it included.
|
|
962
1925
|
|
|
963
|
-
|
|
964
|
-
|
|
1926
|
+
For the Usage page alone, two more: the account in `~/.claude.json`, read again only when that file
|
|
1927
|
+
changes, and `~/.k0/usage/limits.jsonl`, which your statusline writes if you gave it the snippet.
|
|
965
1928
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1929
|
+
Sessions are launched with `--session-id` (k0 chooses the id, so the story ↔ session link is
|
|
1930
|
+
certain), `-n` for the name, `--resume` to pick one up, and `--permission-mode plan` on new ones.
|
|
1931
|
+
Both kinds start with `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` in their environment, set on the command
|
|
1932
|
+
line the terminal is handed — `env` in front of `claude` on macOS and Linux, `$env:` before it on
|
|
1933
|
+
Windows.
|
|
1934
|
+
|
|
1935
|
+
The ChangeLog and the What's New page run Claude Code a second way: `claude -p` on the skill that
|
|
1936
|
+
writes them, with the facts on standard input and no terminal at all. Those are the only times k0
|
|
1937
|
+
starts a model, and the model runs on Claude Code's own connection — the request is Claude Code's,
|
|
1938
|
+
made with your own Claude account, from your own machine, and it goes nowhere near k0 Cloud. Both pages can be writing at once without either
|
|
1939
|
+
cancelling the other. Those runs cannot come back as stories: `sessions.js` drops `claude -p` when it looks for
|
|
970
1940
|
sessions to import, which is also how it tells a hundred and forty real sessions from eight
|
|
971
1941
|
hundred automated ones.
|
|
972
1942
|
|
|
@@ -984,6 +1954,12 @@ Field notes the code takes for granted.
|
|
|
984
1954
|
of the two flags changes nothing — the session starts in `bypassPermissions` and there is no
|
|
985
1955
|
trace of a plan. It looks like it works, which is what makes it a trap. The only way to really
|
|
986
1956
|
start inside a plan is `--allow-dangerously-skip-permissions`.
|
|
1957
|
+
- **On a newer model Claude Code starts with no task tools.** It offers `TaskCreate`, `TaskUpdate`
|
|
1958
|
+
and the rest only to a list of older models, or when `CLAUDE_CODE_ENABLE_TODO_TOOLS=1` is in the
|
|
1959
|
+
environment, and Opus 5 is not on the list. Nothing says so up front: the model calls
|
|
1960
|
+
`TaskCreate`, is told it is disabled for the session, and carries on without. The variable is
|
|
1961
|
+
read once, when the process starts, so a session opened before k0 set it gets the tools only by
|
|
1962
|
+
being resumed.
|
|
987
1963
|
- **While a dialog is open, the call that caused it is not yet in the transcript.** A plan to
|
|
988
1964
|
approve and a question are told apart by the `waitingFor` field of the session file:
|
|
989
1965
|
`permission prompt` is the plan, `input needed` is the question.
|
|
@@ -991,10 +1967,17 @@ Field notes the code takes for granted.
|
|
|
991
1967
|
replaced by `-`, truncated at 200 characters with a hash on the end. That is lossy: `my_project`
|
|
992
1968
|
and `my-project` become the same name, so the working directory is always read from inside the
|
|
993
1969
|
transcript, never by reversing the directory name.
|
|
994
|
-
- **A session's name lives in
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1970
|
+
- **A session's name lives in three places** — the process's own memory, the session file it
|
|
1971
|
+
rewrites (`name`, with `nameSource: "user"` when `-n` or `/rename` set it), and the end of the
|
|
1972
|
+
transcript, in `custom-title` and `agent-name` lines that Claude Code rewrites every turn.
|
|
1973
|
+
**The last one wins.** So renaming a closed session means appending another copy; a live one
|
|
1974
|
+
would have the old name written back over it, and the only way into a live one is its own
|
|
1975
|
+
`/rename` command — typed at the keyboard. Written into the terminal as one block (Terminal's
|
|
1976
|
+
`do script`, a paste) the same line reaches it as a message, and the model answers that it
|
|
1977
|
+
cannot rename the session. The session file is how k0 knows the command took.
|
|
1978
|
+
- **The transcript is not always under the repository's slug.** A session that moves into a
|
|
1979
|
+
worktree writes under the worktree's slug from then on, and a story only knows the repository —
|
|
1980
|
+
so a rename looks in the work path, then the repository, then walks the projects directory.
|
|
998
1981
|
- **The session file appears before the interface is ready to receive.** Writing at that moment
|
|
999
1982
|
loses the first characters and swallows the Enter. So k0 waits until it can see the input box —
|
|
1000
1983
|
and where a platform cannot read a terminal's screen, it waits a fixed moment and says so.
|
|
@@ -1029,17 +2012,36 @@ Field notes the code takes for granted.
|
|
|
1029
2012
|
XML, and with a `1b` byte inside, that XML is not even valid. And `killall cfprefsd` twice, not
|
|
1030
2013
|
once: **before** writing, so the preferences daemon flushes what it still holds from the Terminal
|
|
1031
2014
|
that just quit, and **after**, or nobody sees the change.
|
|
2015
|
+
- **The cloud's numbers cannot be used before the board has moved.** An old board was numbered on
|
|
2016
|
+
the machine, and the cloud's counter starts at 1: the first story numbered by the cloud would
|
|
2017
|
+
collide with a `K1` already on the board. So a linked machine with stories records nothing and
|
|
2018
|
+
asks for no number until the move has run — and the move pushes the cloud's counter past the
|
|
2019
|
+
whole board before the first sync.
|
|
2020
|
+
- **There is no way to look at the cloud's next number without using it.** A number asked for is a
|
|
2021
|
+
number handed out. So the move's preview takes one, and the move then starts from exactly that
|
|
2022
|
+
number; the gap it would otherwise leave never appears.
|
|
2023
|
+
- **`VACUUM INTO`, not a copy of `k0.db`.** With the write-ahead log on, the file alone is not the
|
|
2024
|
+
board — the last changes may still be in `-wal`. The copy taken before the move is one consistent
|
|
2025
|
+
file with all of it folded in.
|
|
2026
|
+
- **Keys inside text are rewritten in one pass, with the whole map.** One key after another would
|
|
2027
|
+
turn a `K3` that became `K12` into whatever `K12` became.
|
|
2028
|
+
- **Supabase's new `sb_secret_…` keys cannot be sent as a Bearer token.** The admin API — creating
|
|
2029
|
+
a throwaway account, approving one from a script — needs the `service_role` JWT instead. Both
|
|
2030
|
+
live in `~/.config/k0-cloud/.env`.
|
|
2031
|
+
- **`supabase config push` fails on the storage part with CLI 2.106**, but the auth part — the
|
|
2032
|
+
redirect addresses, the providers — has already been applied by then. Check the dashboard rather
|
|
2033
|
+
than trusting the exit code.
|
|
1032
2034
|
|
|
1033
2035
|
### Where the repository list comes from
|
|
1034
2036
|
|
|
1035
2037
|
The order is the fresher of two histories. The first is `~/.claude.json`, where Claude Code notes
|
|
1036
2038
|
when you opened each one — but `lastStartTime` is rewritten when the session *ends*, so on its own
|
|
1037
2039
|
it only tells you about the past. The second is k0's own database, which moves when you create or
|
|
1038
|
-
edit a
|
|
2040
|
+
edit a story and on every status change of a live session. That is what brings the repository you
|
|
1039
2041
|
are working in right now to the top.
|
|
1040
2042
|
|
|
1041
2043
|
The list holds directories with a `.git`, directories you have already worked in even if they are
|
|
1042
|
-
not repositories, directories with a
|
|
2044
|
+
not repositories, directories with a story, directories with a document inside them — and **empty
|
|
1043
2045
|
ones**.
|
|
1044
2046
|
|
|
1045
2047
|
Empty ones belong because an empty directory under your home is one you just made, and it cannot
|
|
@@ -1048,8 +2050,8 @@ in `Others` with its `+`. Anything starting with a dot does not make it full, or
|
|
|
1048
2050
|
file manager would be enough to make it disappear again.
|
|
1049
2051
|
|
|
1050
2052
|
**A column lives as long as its directory does.** If that directory is gone — deleted, renamed, an
|
|
1051
|
-
external disk unmounted — the column does not appear, and neither do its
|
|
1052
|
-
deleting**: the
|
|
2053
|
+
external disk unmounted — the column does not appear, and neither do its stories. **Hiding is not
|
|
2054
|
+
deleting**: the stories stay in the database, and if the directory comes back so do they.
|
|
1053
2055
|
|
|
1054
2056
|
---
|
|
1055
2057
|
|
|
@@ -1057,15 +2059,27 @@ deleting**: the cards stay in the database, and if the directory comes back so d
|
|
|
1057
2059
|
|
|
1058
2060
|
The server listens on loopback only, and refuses requests that arrive with a `Host` or `Origin`
|
|
1059
2061
|
it does not recognise — which is what stops a web page you happen to have open from talking to it.
|
|
1060
|
-
HTML files from your repositories are shown in a sandbox with no permissions.
|
|
1061
|
-
|
|
2062
|
+
HTML files from your repositories are shown in a sandbox with no permissions. The local API has no
|
|
2063
|
+
login of its own: anything already running as you on this machine can reach it, and that is worth
|
|
1062
2064
|
knowing rather than glossing over.
|
|
1063
2065
|
|
|
2066
|
+
**k0 talks to two places, and to nothing else.** The first is k0 Cloud, where your board is synced
|
|
2067
|
+
once you have signed in with GitHub or Google. The token that keeps you signed in sits in `~/.k0/`,
|
|
2068
|
+
readable by you alone, and in the cloud every workspace's rows are fenced off from every other's by
|
|
2069
|
+
the database itself. The second is the public npm registry, once a day, asking what the newest
|
|
2070
|
+
version of `k0-board` is. The package name is in the address and nothing else — nothing about you,
|
|
2071
|
+
your repositories, your commits or your board — nothing is downloaded, and `"updateCheck": false`
|
|
2072
|
+
in `~/.k0/config.json` switches it off entirely. No telemetry, no analytics, no fonts from anywhere.
|
|
2073
|
+
|
|
1064
2074
|
The full picture, and how to report a problem privately, is in [SECURITY.md](SECURITY.md).
|
|
1065
2075
|
|
|
1066
2076
|
## What is not here yet
|
|
1067
2077
|
|
|
1068
|
-
|
|
2078
|
+
Ticking a line off on the post-it itself: a story's checklist is written by `/k0-verify`, and the
|
|
2079
|
+
place to work through it is the story's panel in the list. Writing a decision, discussing one and
|
|
2080
|
+
superseding one are still done by talking to Claude — the board says which of those to do next and
|
|
2081
|
+
opens the terminal on it, but nothing on the page writes a decision.
|
|
2082
|
+
In the viewer the listing is documents and configuration: code opens if
|
|
1069
2083
|
you arrive at it from a link, but it is not browsable and the text search does not look at it.
|
|
1070
2084
|
Only configuration and notes can be edited, one file at a time — nothing is diffed, no file is
|
|
1071
2085
|
created or deleted, and you cannot talk to them; for that you open the repository with Claude.
|
|
@@ -1078,6 +2092,14 @@ Yes please — especially if you are on Linux or Windows, where nobody has tried
|
|
|
1078
2092
|
[CONTRIBUTING.md](CONTRIBUTING.md); the fastest useful thing you can send is the output of
|
|
1079
2093
|
`k0-board doctor`.
|
|
1080
2094
|
|
|
1081
|
-
##
|
|
2095
|
+
## License
|
|
2096
|
+
|
|
2097
|
+
k0 is source-available under the [Sustainable Use License](LICENSE) © Alessio Ragni ·
|
|
2098
|
+
[alessioragni.com](https://alessioragni.com). Every line of it is public, and you may use it, change
|
|
2099
|
+
it, and run it for yourself or inside your company, for your own work; you may also pass it on,
|
|
2100
|
+
free of charge, for non-commercial purposes. What it does not allow is offering k0 to other people
|
|
2101
|
+
as a paid or hosted service of your own. It is not an open source license in the OSI sense, and k0
|
|
2102
|
+
does not call itself one.
|
|
1082
2103
|
|
|
1083
|
-
|
|
2104
|
+
Versions up to and including 0.5.0 were released under the MIT License, and they stay that way: a
|
|
2105
|
+
copy of one of those keeps every right MIT gave it.
|