ai4kanban 0.7.1 → 0.8.1

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/README.md CHANGED
@@ -65,17 +65,12 @@ akb skill install # add it, or bring an older copy up to date
65
65
  That writes one file into `.claude/skills/kanban/` (Claude Code) and
66
66
  `.agents/skills/kanban/` (Codex): `SKILL.md`, a short note telling a coding agent the board
67
67
  is here and that `akb` owns it. The board app does the same thing from a button:
68
- **Configuration → Setup**.
68
+ **Configuration → General**.
69
69
 
70
70
  Nothing else is copied in. The flows ship inside the command (`akb guide`), so a newer
71
- command is newer flows in every project at once and the command itself stays where npm put
72
- it, so a project's git history never carries 350 kB of it.
73
-
74
- An agent that finds no `akb` on the PATH doesn't stop: the note's first section says what to
75
- run instead — the copy in this project where there is one, and otherwise `npx --yes
76
- ai4kanban@<the version that wrote the note>`, pinned so the rules match the board. A run
77
- started from the app or the CLI is told the same thing in its own words, and `akb skill`
78
- says it to you at the moment the note lands.
71
+ command is newer flows in every project at once, and a project's git history never carries
72
+ 350 kB of it. An agent that finds no `akb` on the PATH doesn't stop: the note names what to
73
+ run instead, pinned to the version that wrote it so the rules match the board.
79
74
 
80
75
  ## Update
81
76
 
@@ -86,15 +81,11 @@ npm install -g ai4kanban@latest # a newer command
86
81
  akb update # a repaired board, from the project root
87
82
  ```
88
83
 
89
- `akb update` refreshes a skill folder that is already there — it never adds one, since not
90
- having it is an ordinary state now adds whatever an older release never wrote to the
91
- board, clears out what it no longer writes, and prints which version you moved from and to
92
- with a link to everything that changed in between. Your cards, config, and memory are never
93
- touched.
94
-
95
- It can't do the first line to itself — replacing the file that is running is how you get
96
- half a command — so it checks npm and names that line when it is behind, rather than
97
- reporting success a release late.
84
+ `akb update` refreshes a skill folder that is already there — it never adds one adds
85
+ whatever an older release never wrote to the board, clears out what it no longer writes, and
86
+ prints which version you moved from and to with a link to everything that changed in between.
87
+ Your cards, config, and memory are never touched. It can't do the first line to itself, so it
88
+ checks npm and names that line when it is behind.
98
89
 
99
90
  ## Put an agent to work
100
91
 
@@ -103,8 +94,10 @@ card can be built from a terminal, over ssh, or from a script, without a chat se
103
94
  without a browser.
104
95
 
105
96
  ```bash
106
- akb implement 12 # build the card
107
- akb refine 12 # sharpen it until it is ready to build
97
+ akb implement 12 # build the card, then review what was built
98
+ akb review 12 # judge the delivery in flight on it again
99
+ akb refine 12 # sharpen it; defaults to standard QA
100
+ akb refine 12 --effort lightweight --print # use the chosen effort inline
108
101
  akb create "add dark mode" # write the card(s) for it
109
102
  akb propose # write the next tasks
110
103
  akb archive 12 # finish it
@@ -118,11 +111,10 @@ point at, and the command that closes the job.
118
111
  akb implement 12 --print # the steps, for whoever is asking
119
112
  ```
120
113
 
121
- That is the mode for an agent already in a session: it does the job in the conversation
122
- it is already in, rather than paying for a second agent to do the job it is sitting there
123
- to do. Start a run when you want the work to happen on its own. `akb help runs` carries
124
- the whole rule, beside the commands it applies to. An agent working inside a run the board
125
- started always gets the printed flow, so a run can't spawn a copy of itself.
114
+ That is the mode for an agent already in a session: it does the job where it is, rather than
115
+ paying for a second agent to do it. Start a run when you want the work to happen on its own.
116
+ An agent working inside a run always gets the printed flow, so a run can't spawn a copy of
117
+ itself. `akb help runs` carries the whole rule.
126
118
 
127
119
  The run keeps working after the command returns. Watch it, or stop it, from anywhere —
128
120
  including from the board app, which drives its buttons through these same commands:
@@ -168,31 +160,19 @@ akb chat 12 # the conversation so far
168
160
  akb chat 12 --clear # forget it and start fresh
169
161
  ```
170
162
 
171
- Before opening a fresh conversation, `akb chat` ensures this repo has the kanban skill. The
172
- first prompt is only the skill invocation and your message: `/kanban …` for Claude Code,
173
- `$kanban …` for Codex, and `Use the kanban skill: …` for an agent without direct skill-call
174
- syntax. There is no second chat flow or copied board snapshot; the skill reads the current
175
- board when it needs it.
176
-
177
- The reply arrives as it is written, and the next message lands in the same session — the
178
- agent still has everything said before, so you can ask a follow-up without explaining your
179
- project again. Every message is its own command, so the conversation is picked up from any
180
- terminal and survives closing one. The board's conversation and each card's are separate,
181
- and both live under `docs/kanban/.chats/`, on your machine and out of git.
182
-
183
- From there, chat behaves exactly like using the kanban skill in your coding agent. The skill
184
- prints the board-specific flow and does the work in the conversation by default; ask for a
185
- background run when you want another agent to take it independently. If you explicitly say
186
- which way, that wins.
187
-
188
- A change to a card a run is already working on is refused, and the refusal names the card
189
- and what that run is doing — the same rule that keeps two runs off one card.
163
+ Chat is the kanban skill in a persistent agent session the first prompt is only the skill
164
+ invocation and your message, and the skill reads the current board itself. It prints the
165
+ board-specific flow and does the work in the conversation by default; ask for a background run
166
+ when you want another agent to take it independently.
190
167
 
191
- A chat is still not a run: it never shows in `akb runs`, never holds a card, and never keeps
192
- a run off the card it is about.
168
+ Every message is its own command, so a conversation is picked up from any terminal and
169
+ survives closing one. The board's conversation and each card's are separate, both under
170
+ `docs/kanban/.chats/`, on your machine and out of git.
193
171
 
194
- Only an agent whose command can take a second message into its own session can hold a
195
- conversation. On any other one, chat says so and names the agents that can.
172
+ A chat is not a run: it never shows in `akb runs` and never holds a card. A change to a card a
173
+ run is already working on is refused, and the refusal names the card and what that run is
174
+ doing. Only an agent whose command can take a second message into its own session can hold a
175
+ conversation; on any other, chat says so and names the agents that can.
196
176
 
197
177
  ## The manual
198
178
 
@@ -205,19 +185,17 @@ The flows are `akb guide`:
205
185
  ```bash
206
186
  akb guide # every flow, one line each
207
187
  akb guide board # how the board works: card format, layout, memory
208
- akb guide refine # one card, vague to ready
188
+ akb guide qa-loop # settle one card's planning gaps
189
+ akb guide qa-lightweight # short check for clear, localized work
209
190
  akb guide plan-release # fill a release from its goal
210
191
  ```
211
192
 
212
- A printed flow already carries the ones its action needs, in full, so this is for the
213
- rest.
193
+ A printed flow already carries the ones its action needs, in full, so this is for the rest.
214
194
 
215
- A run that writes or changes a card is followed by `akb refine` on that card, started as a
216
- run of its own once the first one ends — so `akb create "…"`, `akb revise`, `akb resolve`,
217
- `akb propose` and `akb plan-release` all come back with their cards refined. Archiving or
218
- rejecting a card does the same for every card it was blocking that now has nothing left in
219
- its way. Each one is an ordinary run: it shows in `akb runs`, has its own log, and
220
- `akb stop` ends it.
195
+ A run that writes or changes a card is followed by `akb refine` on that card, as a run of its
196
+ own — so `akb create`, `akb revise`, `akb resolve`, `akb propose` and `akb plan-release` all
197
+ come back with their cards refined. Archiving or rejecting a card does the same for every card
198
+ it was blocking that now has nothing left in its way.
221
199
 
222
200
  ## What it won't do
223
201
 
package/bin/ai4kanban.mjs CHANGED
@@ -188,6 +188,13 @@ async function placeSkill(root, mode) {
188
188
  const result = installSkill(root, mode === 'update' ? 'present' : undefined, PROGRAM)
189
189
  for (const w of result.wrote) did.push(`${w.refreshed ? 'refreshed' : 'wrote'} ${w.path}/ — ${w.files} (${w.agent})`)
190
190
  for (const s of result.skipped) notes.push(`${s.path} — ${s.why}`)
191
+ // The commit guard (#324), which goes in wherever the skill does. The FIRST write says
192
+ // so, so a user who ran `akb update` for something else learns it is there before a
193
+ // commit refuses; a rewrite of the board's own copy is silent, the way a refresh is.
194
+ if (result.hook?.wrote && !result.hook.wrote.refreshed) {
195
+ did.push(`wrote ${result.hook.wrote.path} — refuses a commit on the branch a delivery is landing on (\`--no-verify\` gets past it)`)
196
+ }
197
+ if (result.hook?.note) notes.push(result.hook.note)
191
198
  // A project that has one agent's folder but not the other's. Update never writes a folder
192
199
  // that isn't there — a plugin install keeps the skill in a read-only cache, and a board
193
200
  // installed today has no folder at all until someone asks for one. Say the line that adds
@@ -227,14 +234,36 @@ function rescueSkillConfig(root, skillDir) {
227
234
 
228
235
  // ---- the board -------------------------------------------------------------
229
236
 
237
+ // Run one board move against `root`.
238
+ //
239
+ // `--dir` is not optional here, even though the process already runs in that folder: with
240
+ // nothing named, the rules WALK UP from the working directory to the nearest docs/kanban/
241
+ // and work on that one. In a folder with no board of its own — every folder an install is
242
+ // pointed at — the nearest board can be anywhere above it, up to the user's home. Naming
243
+ // the folder is what keeps `install --dir X` from repairing somebody else's board and
244
+ // leaving X untouched.
230
245
  function runKanban(rulesFile, root, args) {
231
- const result = spawnSync(process.execPath, [rulesFile, ...args], {
246
+ const [move, ...rest] = args
247
+ const result = spawnSync(process.execPath, [rulesFile, move, '--dir', root, ...rest], {
232
248
  cwd: root,
233
249
  stdio: 'inherit',
234
250
  })
235
251
  if (result.status !== 0) fail(`\`kanban.mjs ${args.join(' ')}\` failed — nothing else was changed`)
236
252
  }
237
253
 
254
+ // The nearest board strictly ABOVE `root`, when there is one. A second board underneath an
255
+ // existing one is legal and occasionally meant, but it is almost never what someone who ran
256
+ // `install` in a subfolder wanted, so it is said out loud.
257
+ function boardAbove(root) {
258
+ let at = path.dirname(path.resolve(root))
259
+ for (;;) {
260
+ if (fs.existsSync(path.join(at, 'docs', 'kanban'))) return at
261
+ const up = path.dirname(at)
262
+ if (up === at) return null
263
+ at = up
264
+ }
265
+ }
266
+
238
267
  // The repair steps an update has to run on a board written by an older version. Each one is
239
268
  // mechanical; anything with a choice in it becomes a note instead.
240
269
  async function repairBoard(rulesFile, root) {
@@ -332,12 +361,17 @@ function checkModules(board) {
332
361
  function cmdInstall(root, tracks) {
333
362
  say(`ai4kanban ${VERSION} — installing into ${root}`)
334
363
  say('')
364
+ const above = fs.existsSync(path.join(root, 'docs', 'kanban')) ? null : boardAbove(root)
365
+ if (above) {
366
+ notes.push(`there is already a board at ${above} — this makes a second one, and commands run here will find this one`)
367
+ }
335
368
  runKanban(builtRules(), root, ['init', ...tracks])
336
369
  sayNotes()
337
370
  say('')
338
371
  // Say what landed, so nobody goes looking for the flows in the repo. They ship with the
339
372
  // command; a project holds its own board and nothing else.
340
- say('That is the board. Nothing was written outside docs/kanban/.')
373
+ say('That is the board, under docs/kanban/. The one line written outside it is `.akb/` in')
374
+ say('.gitignore, which keeps the folders a delivery works in out of git.')
341
375
  say('')
342
376
  say('To drive this board from your coding agent, add the skill — from the button in the')
343
377
  say('board UI (Configuration → Agent setup), or here:')
@@ -370,6 +404,7 @@ async function cmdSkill(root, mode) {
370
404
  say(`ai4kanban ${VERSION} — the coding agent skill in ${root}`)
371
405
  say('')
372
406
  for (const folder of state.folders) say(` ${folder.path}/ — ${sayFolder(folder)} (${folder.agent})`)
407
+ await sayHookState(root)
373
408
  say('')
374
409
  if (!state.installed) say(`Not installed. \`${PROGRAM} skill install\` writes it, and so does the board UI's button.`)
375
410
  else if (state.outdated) say(`Older than this command. \`${PROGRAM} skill install\` brings it up to date.`)
@@ -411,6 +446,16 @@ async function sayPathState() {
411
446
  say(` ${GET_LINE}`)
412
447
  }
413
448
 
449
+ // Where the commit guard stands (#324), said next to the folders an agent reads. A project
450
+ // that is not a git repository has no hook to have, and gets no line about one.
451
+ async function sayHookState(root) {
452
+ const { readCommitHook, sayCommitHook } = await rules()
453
+ if (typeof readCommitHook !== 'function' || typeof sayCommitHook !== 'function') return
454
+ const hook = readCommitHook(root)
455
+ if (hook.state === 'no-git') return
456
+ say(` ${hook.path} — ${sayCommitHook(hook.state)}`)
457
+ }
458
+
414
459
  function sayFolder(folder) {
415
460
  if (folder.state === 'absent') return 'not installed'
416
461
  if (folder.state === 'linked') return 'a symlink into a source checkout — never written over'
@@ -534,7 +579,8 @@ ${INTRO}
534
579
  akb install [--tracks a,b,c] scaffold docs/kanban/ — the board, and nothing else
535
580
  akb skill whether a coding agent can drive this board
536
581
  akb skill install add the skill: SKILL.md into .claude/skills/kanban/
537
- and .agents/skills/kanban/
582
+ and .agents/skills/kanban/, plus the commit guard in
583
+ .git/hooks/pre-commit
538
584
  akb skill refresh rewrite a skill that is already here, and write none
539
585
  that isn't — how the note learns a new spelling of the
540
586
  command
@@ -568,8 +614,8 @@ Put an agent to work on the board:
568
614
  akb agent which agent runs them, and how it is set up
569
615
 
570
616
  A run keeps working after the command returns. Add \`--print\` to any of the first four and
571
- nothing starts: it prints what to do instead, filled in for this board — which is how an
572
- agent already in a session does the job itself rather than starting a second one.
617
+ nothing starts: it prints what to do instead, filled in for this board — which is how the
618
+ agent you are already talking to does the job itself rather than starting a run of its own.
573
619
 
574
620
  \`akb help runs\` is the whole of it — every command a coding agent may call, and when.
575
621
  \`akb agent\` is where you pick the agent, its model and its key.
@@ -626,6 +672,10 @@ async function cmdBoard(args) {
626
672
  // command line is the command's own.
627
673
  const RUN_COMMANDS = new Set([
628
674
  'implement',
675
+ // The two runs a delivery makes after its build (#302). The board starts each itself;
676
+ // typed by hand they put a stopped delivery back in motion.
677
+ 'review',
678
+ 'correct',
629
679
  'run',
630
680
  'refine',
631
681
  'resolve',
@@ -633,6 +683,9 @@ const RUN_COMMANDS = new Set([
633
683
  'create',
634
684
  'propose',
635
685
  'plan-release',
686
+ // Write a closed version's changelog into its summary file (#232) — the run the board
687
+ // UI's close starts, and the one a terminal close names.
688
+ 'changelog',
636
689
  // Finish setting the board up (#173) — the steps that read the repo and think, as one
637
690
  // run. It is a run like the rest: the board UI's button starts exactly this.
638
691
  'setup',
@@ -647,7 +700,19 @@ const RUN_COMMANDS = new Set([
647
700
  'log',
648
701
  'stop',
649
702
  'resume',
703
+ // End the DELIVERY in flight on a card and hand the card back (#301). `stop` ends one
704
+ // run of it; this ends the job.
705
+ 'cancel',
706
+ // Throw a delivery's worktree and branch away (#303). Cancel leaves them where they are;
707
+ // this is the only thing that removes one.
708
+ 'discard',
709
+ // Sign off the tree a delivery would land (#308), on a board that requires it. It ends
710
+ // nothing and starts nothing — it lets a delivery already waiting carry on.
711
+ 'approve',
650
712
  'agent',
713
+ // Which account this MACHINE is signed in to Cloud as (#326). Like `guide`, it needs no
714
+ // board: the sign-in belongs to the machine, not to any one project.
715
+ 'cloud',
651
716
  // The board's flows, shipped with this command rather than copied into each project.
652
717
  'guide',
653
718
  // What a started run's watcher is spawned as. Never typed by a person.