k0-board 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/k0-changelog/SKILL.md +2 -2
- package/.claude/skills/k0-discuss/SKILL.md +105 -0
- package/.claude/skills/k0-discuss/references/rounds.md +280 -0
- package/.claude/skills/k0-epic/SKILL.md +196 -0
- package/.claude/skills/k0-links/.claude-plugin/plugin.json +6 -0
- package/.claude/skills/k0-links/hooks/hooks.json +1 -0
- package/.claude/skills/k0-links/hooks/links.js +128 -0
- package/.claude/skills/k0-links/hooks/register.js +204 -0
- package/.claude/skills/k0-next/SKILL.md +82 -0
- package/.claude/skills/k0-order/SKILL.md +123 -0
- package/.claude/skills/k0-plan/SKILL.md +156 -0
- package/.claude/skills/k0-split/SKILL.md +169 -0
- package/.claude/skills/k0-story/SKILL.md +108 -0
- package/.claude/skills/k0-ultracode/SKILL.md +251 -0
- package/.claude/skills/k0-ultracode/references/agent-brief.md +71 -0
- package/.claude/skills/k0-ultracode/references/modes.md +49 -0
- package/.claude/skills/k0-verify/SKILL.md +219 -0
- package/.claude/skills/k0-whatsnew/SKILL.md +95 -0
- package/.claude/skills/k0-work/SKILL.md +212 -0
- package/CHANGELOG.md +361 -1
- package/README.md +931 -111
- package/bin/k0-board.js +79 -11
- package/menubar/K0MenuBar.swift +35 -5
- package/package.json +13 -1
- 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/db.js +1800 -146
- package/server/files.js +60 -21
- package/server/git.js +53 -14
- package/server/idle.js +15 -13
- package/server/index.js +1251 -186
- package/server/launcher.js +122 -14
- package/server/machine.js +10 -1
- package/server/mirror.js +1048 -0
- package/server/prices.js +59 -0
- package/server/projects.js +57 -12
- package/server/servers.js +22 -1
- package/server/sessions.js +5 -5
- package/server/settings.js +25 -2
- package/server/update.js +324 -0
- package/server/usage.js +642 -0
- package/server/watcher.js +67 -13
- package/server/worktree.js +600 -0
- package/server/writer.js +98 -26
- package/web/awake.js +62 -0
- package/web/base.css +4 -0
- package/web/board.css +396 -16
- package/web/board.js +1182 -152
- package/web/changelog.js +3 -3
- package/web/files.js +73 -16
- package/web/index.html +109 -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
|
@@ -27,7 +27,7 @@ whole thing. Markdown, starting at the first word that belongs to the summary.
|
|
|
27
27
|
"unpushed_total": 2,
|
|
28
28
|
"uncommitted_files": ["web/board.js"],
|
|
29
29
|
"unreleased_changelog": ["### Fixed", "- the board stays pinned to the bar"],
|
|
30
|
-
"
|
|
30
|
+
"stories": [{ "title": "…", "description": "…", "status": "IDLE", "done": false }]
|
|
31
31
|
}
|
|
32
32
|
]
|
|
33
33
|
}
|
|
@@ -73,7 +73,7 @@ something to put in them. This is a summary somebody reads standing up.
|
|
|
73
73
|
|
|
74
74
|
## Rules
|
|
75
75
|
|
|
76
|
-
- **Write in the language of the facts.** The commit subjects and the
|
|
76
|
+
- **Write in the language of the facts.** The commit subjects and the story titles tell you what
|
|
77
77
|
language this person works in: write in that one, and do not translate anything. The headings,
|
|
78
78
|
the bold lines, the bullets — all of it in their language.
|
|
79
79
|
- **Leave the words of the trade alone.** *commit*, *push*, *branch*, *changelog* are what these
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: k0-discuss
|
|
3
|
+
description: Takes a story that is already on the k0 board and still too vague to build, and discusses it in rounds of questions until the decisions behind it are written down one by one. Appends to the rounds and decisions the story already has instead of starting the conversation again. Use this skill when the user types "/k0-discuss", or says "discuss K42", "this story is too vague", "let's talk it through before I start", "pick up the discussion on K19", "parliamo di K42", "questa storia è troppo vaga", "riprendiamo la discussione su K19", "discutiamo prima di partire". Do not use it to create a story from nothing (that is /k0-story or /k0-epic), to break up a story that will not close (/k0-split), or to plan one whose decisions are already recorded (/k0-plan).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /k0-discuss [key]
|
|
7
|
+
|
|
8
|
+
A story on the board says what it is called and not much else. This turns it into something
|
|
9
|
+
buildable: rounds of questions, and a row of decisions somebody can hold the finished work up
|
|
10
|
+
against six months from now.
|
|
11
|
+
|
|
12
|
+
`[key]` is `K42`, or nothing — with nothing, work out which story from what the user just said.
|
|
13
|
+
|
|
14
|
+
## The rules of a round live in one file
|
|
15
|
+
|
|
16
|
+
Read `references/rounds.md` — it sits in this skill's own folder — and follow it. How many rounds
|
|
17
|
+
and how to say it, when to stop, the fifteen-round ceiling, how to ask, what to do when two
|
|
18
|
+
answers collide, how to write a decision, and why every round is written to the API before the
|
|
19
|
+
next question is asked: all of that is there and none of it is repeated here.
|
|
20
|
+
|
|
21
|
+
**If you cannot read that file, say so and stop.** Those rules are the method. Running the
|
|
22
|
+
discussion without them produces exactly the pleasant, unchecked conversation the whole feature
|
|
23
|
+
exists to prevent.
|
|
24
|
+
|
|
25
|
+
What follows is only what is particular to discussing a story that already exists.
|
|
26
|
+
|
|
27
|
+
## Procedure
|
|
28
|
+
|
|
29
|
+
1. **Find the story, and check the feature is on.**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
PORT="${K0_PORT:-4319}"
|
|
33
|
+
REPO="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)"; REPO="${REPO%/.git}"
|
|
34
|
+
[ -d "$REPO" ] || REPO="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
35
|
+
curl -sS --max-time 30 --get --data-urlencode "repo=$REPO" \
|
|
36
|
+
"http://127.0.0.1:$PORT/api/backlog" -o "$SCRATCH/k0-backlog.json"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`127.0.0.1`, not `k0.localhost`: browsers resolve that name by themselves, `curl` does not.
|
|
40
|
+
`--get --data-urlencode`, not `?repo=$REPO`: a repository path with a space in it makes `curl`
|
|
41
|
+
refuse the address outright, and one with a `#` in it quietly sends half.
|
|
42
|
+
`$SCRATCH` is the session's scratch directory; nothing is written outside it. `REPO` is the
|
|
43
|
+
repository the stories are filed under — the main one, even when this session sits in a
|
|
44
|
+
subdirectory of it or inside a worktree, which is why it is not `$PWD`.
|
|
45
|
+
|
|
46
|
+
- `curl` cannot connect → the k0 server is not running. Say so (`k0-board start`, or the tray
|
|
47
|
+
icon → *Restart*) and **stop**.
|
|
48
|
+
- `{"enabled": false}` → say in one line that the backlog is switched off in k0's settings and
|
|
49
|
+
**stop**. Do not run the discussion anyway and do not offer to turn it on.
|
|
50
|
+
- `REPO` empty → this is not a git repository. Ask once which repository this belongs to and
|
|
51
|
+
take the path he gives.
|
|
52
|
+
|
|
53
|
+
The listing carries every key, title and state. Match the key the user gave, or the
|
|
54
|
+
title he described. If two stories match, ask which one; never pick one and hope. If the
|
|
55
|
+
listing has no stories at all, say so — an empty board is not the same as a story you failed
|
|
56
|
+
to find, and it usually means the work has never been written down here.
|
|
57
|
+
|
|
58
|
+
2. **Read everything already recorded.**
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
curl -sS --max-time 30 "http://127.0.0.1:$PORT/api/backlog/story/$STORY_ID" -o "$SCRATCH/k0-story.json"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`$STORY_ID` is the `id` of the story you matched in step 1, not the key. Rounds, decisions,
|
|
65
|
+
plan, checks, log. This is the whole point of the skill: a second discussion that ignores the
|
|
66
|
+
first one is worse than no second discussion, because it spends the user's evening asking him
|
|
67
|
+
things he has already answered.
|
|
68
|
+
|
|
69
|
+
3. **Say where you are picking up from**, in one line, before the first question:
|
|
70
|
+
|
|
71
|
+
> K42 already has four rounds and six decisions from 3 September. Round 5 of about 7.
|
|
72
|
+
|
|
73
|
+
On a story with no rounds yet, say that instead and start at round 1.
|
|
74
|
+
|
|
75
|
+
4. **Run the rounds** exactly as `references/rounds.md` describes. Every round POSTed before the
|
|
76
|
+
next question leaves your mouth, every decision POSTed the moment it is settled.
|
|
77
|
+
|
|
78
|
+
5. **Close the account.** The new decisions, by number, in his words — a short list, not a
|
|
79
|
+
retelling of the conversation. Then, unless the story is already `Planned`, `Working`,
|
|
80
|
+
`Review` or `Done`, move it on:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
curl -sS -X PATCH "http://127.0.0.1:$PORT/api/backlog/story/$STORY_ID" \
|
|
84
|
+
-H 'content-type: application/json' -d '{"state": "Discussed"}'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Then one line saying what comes next — `/k0-plan K42` — and stop there. Do not start planning.
|
|
88
|
+
|
|
89
|
+
## Rules
|
|
90
|
+
|
|
91
|
+
- **Append, never replace.** New decisions get new numbers. One that contradicts an older one
|
|
92
|
+
goes through the collision rule in §4 of `references/rounds.md`: the old sentence is marked
|
|
93
|
+
superseded by the new one's `id`, never edited and never deleted. Nothing in this skill sends
|
|
94
|
+
a `DELETE`.
|
|
95
|
+
- **The body is his, not yours.** If the discussion changes what the story is fundamentally
|
|
96
|
+
about, `PATCH` the `body` — but with his sentences, in his language, and say that you did.
|
|
97
|
+
- **A story mid-flight is still discussable.** `Working` or `Review` is not a reason to refuse.
|
|
98
|
+
It is a reason to read the log first, and to say out loud that work has already started, so
|
|
99
|
+
that a new decision contradicting what is built is recognised as the rework it is.
|
|
100
|
+
- **Talk in the language the user speaks, and store what he says in that language.** The story
|
|
101
|
+
carries a `lang`: if it is empty, set it from the language of the discussion.
|
|
102
|
+
- **Never ask what the API can tell you** — the key, the epic, the dependencies, what
|
|
103
|
+
is open, how far the epic has got. It is in the two calls above. See §7 of `references/rounds.md`.
|
|
104
|
+
- **No files outside the scratch directory**, and never write into `.k0/` by hand: the server
|
|
105
|
+
mirrors the story there on its own.
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# The rounds engine
|
|
2
|
+
|
|
3
|
+
This is the one place the rules for discussing a story live. `k0-discuss` runs on them, and
|
|
4
|
+
`k0-epic`, `k0-split`, `k0-plan`, `k0-work` and `k0-verify` read this file instead of restating
|
|
5
|
+
it — they reach it as `../k0-discuss/references/rounds.md`, relative to the folder the skill
|
|
6
|
+
itself was loaded from, which is where it is whether k0 runs installed from npm or from a
|
|
7
|
+
checkout. If you find these rules written out somewhere else, that copy is wrong and this one
|
|
8
|
+
wins.
|
|
9
|
+
|
|
10
|
+
## Why any of this exists
|
|
11
|
+
|
|
12
|
+
The person you are talking to has already been through a long, pleasant discussion with a
|
|
13
|
+
model that asked good questions, understood the answers, agreed with everything — and then
|
|
14
|
+
built something that quietly contradicted half of it. Nothing checked. Nothing compared the
|
|
15
|
+
finished work against what had been decided, because nothing had written down what had been
|
|
16
|
+
decided in a form anybody could check.
|
|
17
|
+
|
|
18
|
+
So the discussion was worthless. Worse than worthless: it cost an hour and bought a false
|
|
19
|
+
sense that the thing was understood.
|
|
20
|
+
|
|
21
|
+
Everything below exists to stop that happening again. The questions are not the point. The
|
|
22
|
+
point is the row of decisions the questions leave behind, each one a sentence a person can
|
|
23
|
+
read six months later and hold the work up against. `/k0-verify` will do exactly that, one
|
|
24
|
+
decision at a time. Write them so it can.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 1. How many rounds, and saying it out loud
|
|
29
|
+
|
|
30
|
+
Before the first question, list the **open unknowns**: the things where a different answer
|
|
31
|
+
would produce different work. Not the things you are curious about — the things that fork the
|
|
32
|
+
build. A question whose two answers lead to the same code is not an unknown.
|
|
33
|
+
|
|
34
|
+
Then:
|
|
35
|
+
|
|
36
|
+
- rounds still needed ≈ open unknowns ÷ 3, rounded up (three, not four: the fourth slot is
|
|
37
|
+
for what an answer opens up);
|
|
38
|
+
- estimated total = rounds already run + that;
|
|
39
|
+
- say it in the first line of every round: **"Round 3 of about 8"**, in the user's language.
|
|
40
|
+
|
|
41
|
+
The word *about* is doing real work. It is an estimate and it is allowed to move.
|
|
42
|
+
|
|
43
|
+
**Recount after every answer**, because answers both close unknowns and create them. When the
|
|
44
|
+
number moves, say so in the same breath — one short clause, no apology:
|
|
45
|
+
|
|
46
|
+
> Round 4 of about 6 — two of the questions answered themselves.
|
|
47
|
+
|
|
48
|
+
> Round 5 of about 9 — invoicing turned out to have its own states.
|
|
49
|
+
|
|
50
|
+
**Never let the number drift in silence.** Announcing 8 and then quietly asking a twelfth
|
|
51
|
+
question is the thing that makes people stop trusting the count. If you cannot say why the
|
|
52
|
+
number moved, the number did not move: you miscounted, and you say that instead.
|
|
53
|
+
|
|
54
|
+
If the estimate ever climbs past about twelve, stop and say what you are seeing: a story that
|
|
55
|
+
needs twelve rounds is usually two stories. Offer `/k0-split`. The user decides.
|
|
56
|
+
|
|
57
|
+
Every round is written to the API with the estimate it was asked under, so the record shows
|
|
58
|
+
what you believed at the time — see §6.
|
|
59
|
+
|
|
60
|
+
## 2. When to stop
|
|
61
|
+
|
|
62
|
+
Stop when **no remaining question would change what gets built.** That is the whole test, and
|
|
63
|
+
it is stricter than it sounds. Apply it to each unknown still on your list:
|
|
64
|
+
|
|
65
|
+
- *Would a different answer change the work?* No → drop it, do not ask it.
|
|
66
|
+
- *Can it be decided during the work, and cheaply undone if it is wrong?* Then it is not a
|
|
67
|
+
decision for now. Decide it yourself later, and say so in one line.
|
|
68
|
+
- *Is it a preference the user will notice the moment he sees it?* Ask.
|
|
69
|
+
|
|
70
|
+
Do not run a last round to be thorough. Thoroughness here means one more question the user has
|
|
71
|
+
to answer to get where he was already going.
|
|
72
|
+
|
|
73
|
+
**The ceiling is 15 rounds.** At 15 you stop, whatever state the discussion is in. Post the
|
|
74
|
+
last round, then show what is still open — a plain list of the unknowns you never got to,
|
|
75
|
+
in the user's words — and say the story is recorded as it stands and can be picked up again
|
|
76
|
+
whenever he wants. Do not ask a sixteenth question. Do not decide the open ones yourself to
|
|
77
|
+
make the list look finished. A discussion that hits 15 is telling you the story is too big;
|
|
78
|
+
say that too, and offer to split it.
|
|
79
|
+
|
|
80
|
+
## 3. How to ask
|
|
81
|
+
|
|
82
|
+
`AskUserQuestion`, **at most four questions per round**. Four is a ceiling, not a target: two
|
|
83
|
+
sharp questions beat four vague ones, and a round of one is fine.
|
|
84
|
+
|
|
85
|
+
**Never pass `preview` on an option.** With `preview` set on a single-select question the
|
|
86
|
+
interface switches to a side-by-side layout and the free-text box — *Type something.* —
|
|
87
|
+
disappears. That box is how this user actually answers. He picks one of your options perhaps
|
|
88
|
+
half the time; the rest of the time he types the answer you did not think of, and that answer
|
|
89
|
+
is usually the good one. Taking the box away to show a nicer layout is a bad trade every
|
|
90
|
+
single time. There is no exception.
|
|
91
|
+
|
|
92
|
+
For each question:
|
|
93
|
+
|
|
94
|
+
- **One unknown per question.** Two unknowns bundled into one question get one answer, and you
|
|
95
|
+
will not know which one it settled.
|
|
96
|
+
- **Two to four options**, and put the **one you recommend first**. You have read the story;
|
|
97
|
+
having no opinion is not neutrality, it is work handed back.
|
|
98
|
+
- **The description carries the trade-off**, never a restatement of the label. It says what you
|
|
99
|
+
give up by choosing this. If you cannot name what is lost, you have not understood the
|
|
100
|
+
choice well enough to ask about it.
|
|
101
|
+
- Short labels. The description is where the sentence goes.
|
|
102
|
+
|
|
103
|
+
Good:
|
|
104
|
+
|
|
105
|
+
> **The user presses Done** — nothing closes a story by itself. Safest, but a finished story
|
|
106
|
+
> can sit on the board for days looking unfinished.
|
|
107
|
+
>
|
|
108
|
+
> **The last check passing closes it** — no housekeeping, but a story can close while you are
|
|
109
|
+
> still looking at it.
|
|
110
|
+
|
|
111
|
+
Bad — the description says the label again:
|
|
112
|
+
|
|
113
|
+
> **The user presses Done** — the user has to press Done to finish the story.
|
|
114
|
+
|
|
115
|
+
Then **listen to the free text.** When the typed answer does not match any option, the typed
|
|
116
|
+
answer is the answer. Do not re-ask in the hope of getting a clean click.
|
|
117
|
+
|
|
118
|
+
## 4. When two answers collide
|
|
119
|
+
|
|
120
|
+
**Before every round**, fetch what has already been recorded and read it — do not trust your
|
|
121
|
+
memory of the conversation:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
curl -sS --max-time 30 "http://127.0.0.1:$PORT/api/backlog/story/$STORY_ID" -o "$SCRATCH/k0-story.json"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Its `decisions` array is everything that binds this story: the decisions taken on it, and the
|
|
128
|
+
ones taken on its epic before it existed, which it inherits. Each carries an `owner` — `story` or
|
|
129
|
+
`epic` — and a `label`, `D3` or `K7·D3`. There is nowhere else to look: an epic's decisions are
|
|
130
|
+
rows on the epic, never prose in its `body`, and `body` is only the Why.
|
|
131
|
+
|
|
132
|
+
The inherited ones are the ones a later answer most often contradicts, because they were settled
|
|
133
|
+
weeks ago about the whole area and nobody in this conversation has said them out loud.
|
|
134
|
+
|
|
135
|
+
Compare the answer that just arrived against every decision in that list. A collision is when
|
|
136
|
+
the two **cannot both be true of the finished work**. A later answer that adds detail to an
|
|
137
|
+
earlier one is not a collision; do not cry conflict over a refinement, it teaches the user to
|
|
138
|
+
ignore you when it matters.
|
|
139
|
+
|
|
140
|
+
When they do collide, **stop in the middle of the round.** No next question, no smoothing it
|
|
141
|
+
over, no picking the newer one because it is newer.
|
|
142
|
+
|
|
143
|
+
Put both in front of him, quoted, by number:
|
|
144
|
+
|
|
145
|
+
> These two do not fit together.
|
|
146
|
+
>
|
|
147
|
+
> **D3** — A story can go straight from Backlog to Done, and nothing warns about it.
|
|
148
|
+
> **just now** — Nothing may leave Review until every check has passed.
|
|
149
|
+
>
|
|
150
|
+
> I think **D3** should win: you asked for no mandatory path twice, and the check rule only
|
|
151
|
+
> bites on stories that got as far as Review. But it is your call.
|
|
152
|
+
|
|
153
|
+
Say which one you think should win **and why**, in one sentence, and then wait. Do not continue
|
|
154
|
+
the discussion until he has chosen.
|
|
155
|
+
|
|
156
|
+
On the record, **the last answer wins**: the choice becomes a new decision with its own number,
|
|
157
|
+
and the loser is marked superseded — never edited, never deleted.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
curl -sS -X POST "http://127.0.0.1:$PORT/api/backlog/story/$STORY_ID/decision" \
|
|
161
|
+
-H 'content-type: application/json' -d @"$SCRATCH/k0-decision.json" \
|
|
162
|
+
-o "$SCRATCH/k0-new-decision.json" # → { "id": 148, "n": 9, … }
|
|
163
|
+
|
|
164
|
+
curl -sS -X PATCH "http://127.0.0.1:$PORT/api/backlog/decision/$OLD_ID" \
|
|
165
|
+
-H 'content-type: application/json' -d '{"superseded_by": 148}'
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**`superseded_by` takes the new decision's `id`, never its `n`.** They are different numbers and
|
|
169
|
+
they look alike: `id` is the row's own, unique across the whole database, and it is what the
|
|
170
|
+
answer to the POST carries next to `n`; `n` starts again at 1 on every story, so sending it
|
|
171
|
+
points the supersession at some other story's decision, or at nothing. Read the `id` out of the
|
|
172
|
+
answer. Never type a number you worked out yourself, and never reuse the one in the example.
|
|
173
|
+
|
|
174
|
+
**Supersede a decision where it lives, not where it is read.** An epic's decision is superseded on
|
|
175
|
+
the epic — one call, and every story under it sees the change at once. That is the whole reason it
|
|
176
|
+
belongs to the epic. The only copies that ever need chasing are the ones `/k0-split` made when it
|
|
177
|
+
cut a story into tasks, and those are the story's own, not the epic's: if this story has tasks
|
|
178
|
+
under it that carry a copy of the decision you are reversing, supersede each of those too, with
|
|
179
|
+
that task's own decision `id`. A copy left standing is a rule `/k0-verify` will go on holding the
|
|
180
|
+
finished work up against long after the user reversed it.
|
|
181
|
+
|
|
182
|
+
The old sentence stays readable with *(superseded by D9)* beside it. That is not bookkeeping:
|
|
183
|
+
six months on, knowing a decision was made and then reversed is worth more than a tidy list
|
|
184
|
+
that pretends it never happened.
|
|
185
|
+
|
|
186
|
+
## 5. How to write a decision
|
|
187
|
+
|
|
188
|
+
This is the part the whole feature stands on. A decision is what `/k0-verify` will hold the
|
|
189
|
+
finished work up against, one at a time. A decision nobody can check is a decision that was
|
|
190
|
+
not made.
|
|
191
|
+
|
|
192
|
+
- **One complete sentence.** Subject, verb, the thing that will be true. Not a fragment, not a
|
|
193
|
+
heading, not a note to self.
|
|
194
|
+
- **Behaviour, not implementation.** What the user will see, do, or be spared. No file paths,
|
|
195
|
+
no table names, no function names, no jargon. He does not read code and should not have to.
|
|
196
|
+
- **One decision per line.** Never merge two, however neatly they pair.
|
|
197
|
+
- **Never lose one.** Half-swallowed by voice dictation, said badly, said twice in different
|
|
198
|
+
words, dropped into the middle of an answer about something else — it still counts. When a
|
|
199
|
+
sentence came out garbled, read back what you think he meant and ask; do not quietly bin it
|
|
200
|
+
and do not guess.
|
|
201
|
+
- **In the language he spoke.** The decisions are for him, not for the repository.
|
|
202
|
+
- Write it the moment it is settled, in the same breath as the round it came from (§6).
|
|
203
|
+
|
|
204
|
+
### Three that work
|
|
205
|
+
|
|
206
|
+
- Nothing marks a story finished on its own: the user presses Done.
|
|
207
|
+
- A story can go straight from Backlog to Done, and nothing warns about it.
|
|
208
|
+
- Every post-it shows the name of the epic it belongs to, in that epic's colour.
|
|
209
|
+
|
|
210
|
+
Each one is a sentence, describes something visible, and can be checked by looking at k0.
|
|
211
|
+
|
|
212
|
+
### Three that do not
|
|
213
|
+
|
|
214
|
+
- *Add `epic_id` to the story table and join it in `listStories()`.*
|
|
215
|
+
Implementation, and the two things he would need in order to check it — a table and a
|
|
216
|
+
function — are things he never looks at. Rewritten: *a story remembers which epic it belongs
|
|
217
|
+
to, and keeps it when it is moved.*
|
|
218
|
+
|
|
219
|
+
- *Colours and states.*
|
|
220
|
+
Not a sentence and not a decision. In six months nobody, including you, can say what was
|
|
221
|
+
agreed. If this is all you have, you did not get an answer: ask again.
|
|
222
|
+
|
|
223
|
+
- *Use the epic's colour on the post-it, and allow Backlog → Done directly, and keep Done
|
|
224
|
+
manual.*
|
|
225
|
+
Three decisions on one line. When one of them is reversed there is no way to strike only
|
|
226
|
+
that one, so the whole line goes stale and the other two rot with it.
|
|
227
|
+
|
|
228
|
+
## 6. Write it down before you ask the next thing
|
|
229
|
+
|
|
230
|
+
**Every round is POSTed before the following question leaves your mouth.** Not batched at the
|
|
231
|
+
end, not held in the conversation and written up when the discussion closes.
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
curl -sS -X POST "http://127.0.0.1:$PORT/api/backlog/story/$STORY_ID/round" \
|
|
235
|
+
-H 'content-type: application/json' -d @"$SCRATCH/k0-round.json"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
with `{ "n": 3, "estimated_total": 8, "question": "…", "answer": "…" }` — `n` is 1-based per
|
|
239
|
+
story, `estimated_total` is what you announced for *that* round. Decisions go the same way, the
|
|
240
|
+
instant they are settled, not when the discussion ends.
|
|
241
|
+
|
|
242
|
+
The reason is plain: terminals die. A crash at round three must not take the first three with
|
|
243
|
+
it, and it must not leave the user re-answering questions he has already answered — that is
|
|
244
|
+
exactly the moment people stop using a tool. Write the JSON to a file under `$SCRATCH` and send
|
|
245
|
+
it with `-d @file`; long answers with quotes and newlines in them do not survive being pasted
|
|
246
|
+
inline.
|
|
247
|
+
|
|
248
|
+
Resuming is then automatic: fetch `GET /api/backlog/story/:id`, read the rounds and decisions
|
|
249
|
+
already there, carry on at the highest `n` + 1, and say where you are picking up from. Never
|
|
250
|
+
start again at round 1 on a story that already has rounds.
|
|
251
|
+
|
|
252
|
+
If `curl` cannot connect, the k0 server is not running. Say so (`k0-board start`, or the tray
|
|
253
|
+
icon → *Restart*) and **stop**. Do not run the discussion anyway and promise to save it later:
|
|
254
|
+
that promise is the failure this file exists to prevent.
|
|
255
|
+
|
|
256
|
+
## 7. What you never ask
|
|
257
|
+
|
|
258
|
+
His time is the scarce thing here. Two kinds of question waste it.
|
|
259
|
+
|
|
260
|
+
**What the server already knows.** Fetch it; do not ask, and do not reason it out either.
|
|
261
|
+
|
|
262
|
+
| you want | where it comes from |
|
|
263
|
+
|---|---|
|
|
264
|
+
| the key, the title, the state | `GET /api/backlog?repo=<path>` |
|
|
265
|
+
| which epic, how far along it is | the same call — `progress: {done, total}` |
|
|
266
|
+
| what was decided while the epic was discussed | `GET /api/backlog/story/:id` — already merged into `decisions`, marked `owner: "epic"` |
|
|
267
|
+
| what is open, what is blocked, the dependencies | the same call — `state`, `blocked`, `deps` |
|
|
268
|
+
| the rounds, decisions, checks, plan and log so far | `GET /api/backlog/story/:id` |
|
|
269
|
+
| what to pick up next, and why | `GET /api/backlog/next?repo=<path>` |
|
|
270
|
+
|
|
271
|
+
Counting is not what a model is for. Understanding what he means and writing it down clearly
|
|
272
|
+
is. Asking him for a number the database is already holding makes him do the machine's job.
|
|
273
|
+
|
|
274
|
+
**Anything with an obvious default.** Decide it, and say what you decided in one line he can
|
|
275
|
+
push back on — *"I am taking the story's colour from its epic unless you say otherwise"* — and
|
|
276
|
+
carry on without waiting. A round spent confirming the obvious buys nothing and spends the
|
|
277
|
+
attention you will need for the question that actually matters.
|
|
278
|
+
|
|
279
|
+
Also never ask: something he has already answered in this session; the same unknown a second
|
|
280
|
+
time in different words; permission to continue; or a question whose answer you would ignore.
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: k0-epic
|
|
3
|
+
description: The long way in. The user talks for ten minutes about something big — a feature, a rewrite, a whole area of the product — and this turns it into an epic on the k0 board: rounds of questions until nothing is left that would change the work, a decision written down for each thing settled, and only then a tree of stories proposed for approval and created. Use this skill when the user says "/k0-epic", "new epic", "let me tell you about something big", "I want to think this through with you", "break this down for me", or in Italian "nuovo epic", "ti racconto una cosa grossa", "ragioniamo su questa feature", "spacchettiamo questo lavoro". Do not use it for one thing he already knows he wants — that is /k0-story — nor to discuss, split or plan a story that already exists: those are /k0-discuss, /k0-split and /k0-plan.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /k0-epic
|
|
7
|
+
|
|
8
|
+
Somebody is about to describe something too big to be one post-it. The work here is in this
|
|
9
|
+
order and no other: **understand, record, propose, then write.** Thirty stories created before
|
|
10
|
+
he has agreed to them is thirty things he now has to delete.
|
|
11
|
+
|
|
12
|
+
## Before anything
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
PORT="${K0_PORT:-4319}"
|
|
16
|
+
REPO="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)"; REPO="${REPO%/.git}"
|
|
17
|
+
[ -d "$REPO" ] || REPO="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
18
|
+
curl -sS --max-time 30 --get --data-urlencode "repo=$REPO" \
|
|
19
|
+
"http://127.0.0.1:$PORT/api/backlog" -o "$SCRATCH/k0-backlog.json"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`127.0.0.1`, not `k0.localhost`: browsers resolve that name by themselves, `curl` does not.
|
|
23
|
+
`--get --data-urlencode`, not `?repo=$REPO`: a repository path with a space in it makes `curl`
|
|
24
|
+
refuse the address outright, and one with a `#` in it quietly sends half.
|
|
25
|
+
`$SCRATCH` is the session's scratch directory; nothing is written outside it. `REPO` is the
|
|
26
|
+
repository the stories are filed under — the main one, even when this session sits in a
|
|
27
|
+
subdirectory of it or inside a worktree, which is why it is not `$PWD`.
|
|
28
|
+
|
|
29
|
+
- `curl` cannot connect → the k0 server is not running. Say so (`k0-board start`, or the tray
|
|
30
|
+
icon → *Restart*) and **stop**.
|
|
31
|
+
- `{"enabled": false}` → say in one line that the backlog is switched off in k0's settings and
|
|
32
|
+
**stop**.
|
|
33
|
+
- `REPO` empty → this is not a git repository. Ask once which repository this belongs to and
|
|
34
|
+
take the path he gives.
|
|
35
|
+
|
|
36
|
+
That one answer also holds the repository's existing epics and stories. Read it before you open
|
|
37
|
+
your mouth: half of what he is about to describe may already be on the board, and saying so is
|
|
38
|
+
worth more than a good question.
|
|
39
|
+
|
|
40
|
+
## 1. Let him finish
|
|
41
|
+
|
|
42
|
+
He is dictating, probably out loud, probably jumping about. Do not interrupt with round one
|
|
43
|
+
while he is still going. When he stops, say back in three or four lines what you understood the
|
|
44
|
+
thing to be — not a summary of his words, the shape of the work — and let him correct it.
|
|
45
|
+
|
|
46
|
+
## 2. Create the epic straight away
|
|
47
|
+
|
|
48
|
+
As soon as there is a title and a why, before the first question:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
curl -sS --max-time 30 -X POST "http://127.0.0.1:$PORT/api/backlog/epic" \
|
|
52
|
+
-H 'content-type: application/json' -d @"$SCRATCH/k0-epic.json" -o "$SCRATCH/k0-epic-new.json"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
with `{ "project_path": "…", "title": "…", "body": "…", "lang": "it" }`. The `body` is why this
|
|
56
|
+
epic exists, in his words and his language. The answer carries the `key` and the
|
|
57
|
+
`id`; use those from now on and never work them out yourself.
|
|
58
|
+
|
|
59
|
+
An epic with no stories yet costs nothing and means the next ten minutes survive a dead terminal.
|
|
60
|
+
|
|
61
|
+
## 3. Run the rounds
|
|
62
|
+
|
|
63
|
+
The rules for this are in one place and this skill does not repeat them:
|
|
64
|
+
|
|
65
|
+
**`../k0-discuss/references/rounds.md` — read it now and follow it.** The path is relative to
|
|
66
|
+
the folder this skill was loaded from; the two skills are siblings wherever k0 is installed. If
|
|
67
|
+
you cannot find the file, say so and **stop** — those rules are the method, and an epic
|
|
68
|
+
discussed without them is the long pleasant conversation nobody ever checks.
|
|
69
|
+
|
|
70
|
+
How many rounds and how to announce them, when to stop, the ceiling, how to ask, what to do when
|
|
71
|
+
two answers collide, how to write a decision, and what never to ask: all of it is there and all
|
|
72
|
+
of it applies here unchanged.
|
|
73
|
+
|
|
74
|
+
One thing is particular to an epic: the rounds and the decisions belong to the **epic itself**,
|
|
75
|
+
not to a story, and not to its body.
|
|
76
|
+
|
|
77
|
+
**Write every round on the epic, before the next question.** An epic has rows of its own for
|
|
78
|
+
exactly this — there is no need to keep the transcript anywhere, and no reason to.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
curl -sS --max-time 30 -X POST "http://127.0.0.1:$PORT/api/backlog/epic/$EPIC_ID/round" \
|
|
82
|
+
-H 'content-type: application/json' -d @"$SCRATCH/round.json"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`{ "n": 3, "estimated_total": 8, "question": "…", "answer": "…" }`, in his language. Writing the
|
|
86
|
+
same `n` twice replaces that round, so the question can go down when you ask it and the answer
|
|
87
|
+
when it arrives — that is one round, not two.
|
|
88
|
+
|
|
89
|
+
**Write every decision on the epic as it is taken.**
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
curl -sS --max-time 30 -X POST "http://127.0.0.1:$PORT/api/backlog/epic/$EPIC_ID/decision" \
|
|
93
|
+
-H 'content-type: application/json' -d '{"text":"…","source":"discussion"}'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
It comes back with `id` and `n`. Keep the `id`: superseding takes a row id and never a number.
|
|
97
|
+
|
|
98
|
+
**`body` is the Why and nothing else.** Never grow it into a transcript. A decision written into
|
|
99
|
+
prose cannot be counter-checked one at a time, which is the one thing this whole feature is for,
|
|
100
|
+
and it cannot be superseded either — the strikethrough is a mark on a paragraph, not a change to
|
|
101
|
+
anything `/k0-verify` reads.
|
|
102
|
+
|
|
103
|
+
**The collision check reads the epic's decisions.** §4 of `rounds.md` says to fetch what is
|
|
104
|
+
already recorded before every round rather than trusting your memory of the conversation. Here
|
|
105
|
+
that is the epic:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
curl -sS --max-time 30 "http://127.0.0.1:$PORT/api/backlog/epic/$EPIC_ID" -o "$SCRATCH/epic.json"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`decisions` is the list, each with `id`, `n`, `text` and `superseded_by`. Everything else in §4
|
|
112
|
+
holds: stop mid-round, put both sentences in front of him, say which you think should win and
|
|
113
|
+
why, wait. The loser is superseded by the winner's row id:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
curl -sS --max-time 30 -X PATCH "http://127.0.0.1:$PORT/api/backlog/decision/$OLD_ID" \
|
|
117
|
+
-H 'content-type: application/json' -d "{\"superseded_by\":$NEW_ID}"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
A superseded decision is never deleted — the record of a reversal is worth more than a tidy list
|
|
121
|
+
— and every story of this epic sees the reversal at once, which is the reason it lives here.
|
|
122
|
+
|
|
123
|
+
Resuming after a dead terminal is the same as anywhere: re-fetch the epic, read its rounds and
|
|
124
|
+
decisions, carry on at the next number, and say where you are picking up from.
|
|
125
|
+
|
|
126
|
+
## 4. Propose the tree, and wait
|
|
127
|
+
|
|
128
|
+
Only when the rounds have stopped. One message, in his language:
|
|
129
|
+
|
|
130
|
+
- the epic, one line;
|
|
131
|
+
- the stories, in the order they would be done — **title, then one line saying what it is**;
|
|
132
|
+
- under each, the dependency when there is one: *needs the first one done*;
|
|
133
|
+
- what you have deliberately left out, if anything, one line.
|
|
134
|
+
|
|
135
|
+
No numbering scheme of your own — k0 gives every story a key the moment it exists,
|
|
136
|
+
and inventing a second one now only makes two things to reconcile.
|
|
137
|
+
|
|
138
|
+
Then ask for the tree as a whole, with `AskUserQuestion` under the rules in §3 of `rounds.md`:
|
|
139
|
+
approve it, change it, or cut something. Expect him to move things. Rework the list and ask
|
|
140
|
+
again; two passes here are cheap and thirty wrong stories are not.
|
|
141
|
+
|
|
142
|
+
**If the tree comes out longer than about twelve stories, say so before asking.** An epic that
|
|
143
|
+
big is usually two epics, and he decides which.
|
|
144
|
+
|
|
145
|
+
**Nothing is written until he has said yes.**
|
|
146
|
+
|
|
147
|
+
## 5. Write it
|
|
148
|
+
|
|
149
|
+
In this order:
|
|
150
|
+
|
|
151
|
+
1. **The stories.** One `POST /api/backlog/story` each, with `project_path`, `title`, `body`,
|
|
152
|
+
`lang`, `epic_key` — the epic's key from step 2 — and a **`prompt`**: the sentence a session
|
|
153
|
+
opening on that story starts from. Two lines is enough, in his language, and it always says
|
|
154
|
+
the same two things: what this story is, and that the plan and the standing decisions are on
|
|
155
|
+
the story, so `/k0-plan K42` or `/k0-work K42` is where to begin. Without it a session started
|
|
156
|
+
from the board's button opens cold, and ten minutes of discussion reach the terminal by luck.
|
|
157
|
+
Send each one with `-d @file`.
|
|
158
|
+
2. **The decisions: nothing to do.** They were written on the epic in step 3, as they were taken,
|
|
159
|
+
and every story carrying `epic_key` inherits them. `GET /api/backlog/story/:id` returns them
|
|
160
|
+
in the same `decisions` array as the story's own, marked `"owner": "epic"` and labelled
|
|
161
|
+
`K7·D3`, and `/k0-verify` counter-checks them one by one like any other.
|
|
162
|
+
|
|
163
|
+
**Do not copy them down onto the stories.** It is the one thing that looks helpful here and is
|
|
164
|
+
not: the copy is a second row saying the same sentence, and the day he reverses `K7·D3` on the
|
|
165
|
+
epic only the epic's changes. The copies stand, and `/k0-verify` goes on holding finished work
|
|
166
|
+
up against a rule he took back.
|
|
167
|
+
|
|
168
|
+
A story only gets a decision of its own when something was settled about *that story* and
|
|
169
|
+
about no other — usually nothing was, at this point.
|
|
170
|
+
3. **The dependencies.** `POST /api/backlog/dependency` with `{ "story_id": …, "depends_on": … }`,
|
|
171
|
+
using the ids that came back from step 1.
|
|
172
|
+
|
|
173
|
+
The epic keeps the record: its `body` is the why, its rounds are the discussion, its decisions are
|
|
174
|
+
the rules. That is what a later `/k0-discuss` on any story in this epic already has in front of
|
|
175
|
+
it, without going looking.
|
|
176
|
+
|
|
177
|
+
If anything fails, stop and say what got written and what did not. Do not retry blindly and do
|
|
178
|
+
not carry on as if the tree were complete.
|
|
179
|
+
|
|
180
|
+
## 6. Close it
|
|
181
|
+
|
|
182
|
+
Short, in his language: the epic's key and title, how many stories, and the one to start with —
|
|
183
|
+
which you get from `/api/backlog/next` — asked the same way as the listing above, with
|
|
184
|
+
`--get --data-urlencode "repo=$REPO"` — and not from your own reading of the list.
|
|
185
|
+
|
|
186
|
+
## Rules
|
|
187
|
+
|
|
188
|
+
- **Never write a story before he has agreed to the tree.** This is the rule the skill exists
|
|
189
|
+
for.
|
|
190
|
+
- **Everything he says is stored in the language he said it in.** Titles, bodies, decisions.
|
|
191
|
+
The interface stays English; his words do not get translated.
|
|
192
|
+
- **Never ask for what the API already knows** — keys, states, an epic's progress,
|
|
193
|
+
what is blocked. `rounds.md` §7 has the table.
|
|
194
|
+
- **Decisions are written the way `rounds.md` §5 says**, and at the ceiling the discussion stops
|
|
195
|
+
the way §2 says. Neither rule is repeated here, and neither is yours to soften.
|
|
196
|
+
- **No files outside the scratch directory**, and never a `git` command that changes anything.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "k0-links",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"author": { "name": "Alessio Ragni", "url": "https://alessioragni.com" },
|
|
5
|
+
"description": "While k0 is running, the addresses, folders, documents and artifacts the last reply named sit above the prompt, one click away"
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "modules": ["./register.js"] }
|