@pi-unipi/unipi 3.0.0-alpha.11 → 3.0.0-alpha.13

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +21 -21
  3. package/packages/ask-user/package.json +2 -2
  4. package/packages/autocomplete/package.json +1 -1
  5. package/packages/background-tasks/package.json +2 -2
  6. package/packages/btw/package.json +2 -2
  7. package/packages/compactor/package.json +3 -3
  8. package/packages/core/package.json +1 -1
  9. package/packages/footer/package.json +3 -3
  10. package/packages/footer/src/glance-editor.ts +8 -6
  11. package/packages/fusion/package.json +3 -3
  12. package/packages/info-screen/package.json +2 -2
  13. package/packages/input-shortcuts/package.json +2 -2
  14. package/packages/kanboard/README.md +1 -0
  15. package/packages/kanboard/index.ts +35 -4
  16. package/packages/kanboard/package.json +7 -7
  17. package/packages/kanboard/skills/kanboard/SKILL.md +21 -10
  18. package/packages/kanboard/src/commands.ts +1 -1
  19. package/packages/kanboard/src/guard.ts +14 -2
  20. package/packages/kanboard/src/reminders.ts +284 -0
  21. package/packages/kanboard/src/settings.ts +11 -0
  22. package/packages/kanboard/src/shapes.ts +2 -0
  23. package/packages/long-horizon/package.json +2 -2
  24. package/packages/mcp/package.json +2 -2
  25. package/packages/memory/package.json +3 -3
  26. package/packages/notify/package.json +2 -2
  27. package/packages/skill-registry/package.json +2 -2
  28. package/packages/subagents/package.json +2 -2
  29. package/packages/unipi/bundled.js +278 -24
  30. package/packages/updater/package.json +2 -2
  31. package/packages/utility/README.md +1 -1
  32. package/packages/utility/package.json +2 -2
  33. package/packages/utility/src/render/simple.ts +25 -8
  34. package/packages/utility/src/settings.ts +1 -1
  35. package/packages/watchdog/package.json +3 -3
  36. package/packages/web-api/package.json +2 -2
  37. package/packages/workflow/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -6,6 +6,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.0.0-alpha.13] — 2026-09-29
10
+
11
+ ### Fixed
12
+ - utility: typing in the input box lagged badly in long sessions with the simple render style — every keystroke re-planned and re-truncated each tool group once per row (O(n²)). Non-last rows now return early and the group paint is memoized by width + call state.
13
+
14
+ ## [3.0.0-alpha.12] — 2026-09-29
15
+
16
+ ### Added
17
+ - `kanboard`: **agent `start` / `finish`** — an agent working board tasks by hand ("do UNI-5 and UNI-8") now moves them itself: `start <ID>` (todo → in_progress, self-claimed for the session; deps satisfied, not already claimed, per-project session cap) and `finish <ID> --comment "<summary>"` (in_progress → in_review; only a task this session `start`ed — another session's or a runner claim is refused; summary required). Both are free (no write credit) and need no `/unipi:kanboard-do`. A session may have several tasks started. Agent claims carry `run.owner: agent` (runner claims are unchanged on disk) and belong to the pi process (`UNIPI_KANBOARD_PID`), so the stale-claim reaper releases them to Todo when the session dies. `move` as an agent points at `start`/`finish` for those two transitions.
18
+ - `kanboard`: **progress reminders** (setting `kanboard.reminders`, default on; no LLM, never blocking) — R1: on the first file-changing tool call of a turn, while a task named in the prompt (or `show`n) is still Todo and nothing is started, a steer is appended to that tool result; R2: at the end of a turn with a started task still In Progress, a follow-up asks to `finish` it or say what remains / block it (at most 2 per task each). Silent in runner-owned runs.
19
+
20
+ ### Changed
21
+ - `kanboard`: transition table — `todo → in_progress` and `in_progress → in_review` allow the agent actor (via `start`/`finish`) besides the runner; in_review → done/todo stays user-only. The kanboard skill and the `/unipi:kanboard-do` prompt now say "`start` a task before working on it, `finish` it with a summary when done".
22
+ - `kanboard` web UI: claimed cards distinguish an agent claim (`start`ed by a session) from a runner claim.
23
+ - `footer`: the glance input frame is open-sided — `GlanceEditor` body rows drop the `│` rails; only the rounded corners on the top/bottom borders frame the prompt (content keeps its column via a one-space indent, rows are truncated to the inner width).
24
+
25
+ ### Fixed
26
+ - `utility`: the Response formatting → Style description no longer claims the change applies "in a new session" — tool renderers are registered once at extension load, so only a restart or `/reload` applies it. The setting now reads "applies after /reload" (utility README updated to match).
27
+
9
28
  ## [3.0.0-alpha.11] — 2026-09-29
10
29
 
11
30
  ### Removed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/unipi",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "All-in-one extension suite for Pi coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -82,26 +82,26 @@
82
82
  "typebox": "^1.1.38"
83
83
  },
84
84
  "dependencies": {
85
- "@pi-unipi/ask-user": "3.0.0-alpha.11",
86
- "@pi-unipi/background-tasks": "3.0.0-alpha.11",
87
- "@pi-unipi/btw": "3.0.0-alpha.11",
88
- "@pi-unipi/command-enchantment": "3.0.0-alpha.11",
89
- "@pi-unipi/compactor": "3.0.0-alpha.11",
90
- "@pi-unipi/core": "3.0.0-alpha.11",
91
- "@pi-unipi/footer": "3.0.0-alpha.11",
92
- "@pi-unipi/fusion": "3.0.0-alpha.11",
93
- "@pi-unipi/info-screen": "3.0.0-alpha.11",
94
- "@pi-unipi/input-shortcuts": "3.0.0-alpha.11",
95
- "@pi-unipi/kanboard": "3.0.0-alpha.11",
96
- "@pi-unipi/mcp": "3.0.0-alpha.11",
97
- "@pi-unipi/memory": "3.0.0-alpha.11",
98
- "@pi-unipi/notify": "3.0.0-alpha.11",
99
- "@pi-unipi/skill-registry": "3.0.0-alpha.11",
100
- "@pi-unipi/subagents": "3.0.0-alpha.11",
101
- "@pi-unipi/updater": "3.0.0-alpha.11",
102
- "@pi-unipi/utility": "3.0.0-alpha.11",
103
- "@pi-unipi/web-api": "3.0.0-alpha.11",
104
- "@pi-unipi/workflow": "3.0.0-alpha.11"
85
+ "@pi-unipi/ask-user": "3.0.0-alpha.13",
86
+ "@pi-unipi/background-tasks": "3.0.0-alpha.13",
87
+ "@pi-unipi/btw": "3.0.0-alpha.13",
88
+ "@pi-unipi/command-enchantment": "3.0.0-alpha.13",
89
+ "@pi-unipi/compactor": "3.0.0-alpha.13",
90
+ "@pi-unipi/core": "3.0.0-alpha.13",
91
+ "@pi-unipi/footer": "3.0.0-alpha.13",
92
+ "@pi-unipi/fusion": "3.0.0-alpha.13",
93
+ "@pi-unipi/info-screen": "3.0.0-alpha.13",
94
+ "@pi-unipi/input-shortcuts": "3.0.0-alpha.13",
95
+ "@pi-unipi/kanboard": "3.0.0-alpha.13",
96
+ "@pi-unipi/mcp": "3.0.0-alpha.13",
97
+ "@pi-unipi/memory": "3.0.0-alpha.13",
98
+ "@pi-unipi/notify": "3.0.0-alpha.13",
99
+ "@pi-unipi/skill-registry": "3.0.0-alpha.13",
100
+ "@pi-unipi/subagents": "3.0.0-alpha.13",
101
+ "@pi-unipi/updater": "3.0.0-alpha.13",
102
+ "@pi-unipi/utility": "3.0.0-alpha.13",
103
+ "@pi-unipi/web-api": "3.0.0-alpha.13",
104
+ "@pi-unipi/workflow": "3.0.0-alpha.13"
105
105
  },
106
106
  "devDependencies": {
107
107
  "@earendil-works/pi-agent-core": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/ask-user",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Structured user input tool for Pi coding agent — single-select, multi-select, freeform",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -40,7 +40,7 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@pi-unipi/core": "3.0.0-alpha.11"
43
+ "@pi-unipi/core": "3.0.0-alpha.13"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/command-enchantment",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Enhanced TUI autocomplete for /unipi:* commands — colored, sorted, and grouped by package",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/background-tasks",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Background tasks for UniPi — durable shell jobs and delegated background agents with a footer dock",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@earendil-works/pi-ai": "^0.87.1",
13
- "@pi-unipi/core": "3.0.0-alpha.11",
13
+ "@pi-unipi/core": "3.0.0-alpha.13",
14
14
  "turndown": "^7.2.4"
15
15
  },
16
16
  "devDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/btw",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "A pi extension for parallel side conversations with /unipi:btw — part of the Unipi suite",
5
5
  "type": "module",
6
6
  "main": "extensions/btw.ts",
@@ -37,7 +37,7 @@
37
37
  "@earendil-works/pi-tui": "^0.87.1"
38
38
  },
39
39
  "dependencies": {
40
- "@pi-unipi/core": "3.0.0-alpha.11"
40
+ "@pi-unipi/core": "3.0.0-alpha.13"
41
41
  },
42
42
  "pi": {
43
43
  "extensions": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/compactor",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Compaction for Pi — lossless zero-LLM or model summaries, rebuilt from full history, with session recall",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -33,8 +33,8 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "3.0.0-alpha.11",
37
- "@pi-unipi/info-screen": "3.0.0-alpha.11",
36
+ "@pi-unipi/core": "3.0.0-alpha.13",
37
+ "@pi-unipi/info-screen": "3.0.0-alpha.13",
38
38
  "@earendil-works/pi-agent-core": "^0.87.1"
39
39
  },
40
40
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/core",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Shared utilities, event types, and constants for Unipi extension suite",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/footer",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Persistent status bar for Unipi — subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "3.0.0-alpha.11",
36
- "@pi-unipi/background-tasks": "3.0.0-alpha.11"
35
+ "@pi-unipi/core": "3.0.0-alpha.13",
36
+ "@pi-unipi/background-tasks": "3.0.0-alpha.13"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -5,12 +5,14 @@
5
5
  * subclass CustomEditor, use super.render() ONLY to obtain editor content
6
6
  * lines, then compose our own rounded frame. Layout per the v3 design:
7
7
  *
8
- * ╭─UNIPI │ feat/footer-default-v2 │ ─────────────────────╮
9
- * │ Type your prompt here... │
8
+ * ╭─UNIPI │ feat/footer-default-v2 ─────────────────────╮
9
+ * Type your prompt here...
10
10
  * ╰─ unipi ────────── 42%/1.0M │ Claude Opus 4.5 │ thinking:high ╯
11
11
  *
12
12
  * Top border carries the UNIPI brand + git branch. Bottom border right side
13
13
  * carries workspace · context%/window · model · thinking level; left filler.
14
+ * The body is open-sided: no vertical rails — the rounded corners are the
15
+ * only frame marks (content keeps its column via a one-space indent).
14
16
  * All keybindings/autocomplete/history/paste behavior inherited.
15
17
  */
16
18
 
@@ -296,10 +298,10 @@ export class GlanceEditor extends CustomEditor {
296
298
  topCluster +
297
299
  border(BORDER.topRight);
298
300
 
299
- // ── Body rows: │ content │ ──
300
- const bodyRows = contentLines.map(row =>
301
- border(BORDER.vertical) + padLine(row, inner) + border(BORDER.vertical),
302
- );
301
+ // ── Body rows: open sides — the corner curves are the only frame marks.
302
+ // One-space indent keeps content in the column it had between the old
303
+ // rails; no trailing padding (rows may end short of the frame width).
304
+ const bodyRows = contentLines.map(row => " " + truncateToWidth(row, inner, ""));
303
305
 
304
306
  // ── Bottom frame: ╰─ unipi ─────── [RIGHT CLUSTER] ─╯ ──
305
307
  // Right cluster: workspace · pct%/window │ model │ thinking:level
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/fusion",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Devin-style model picker, fusion presets (lead + sidekick), and Local Fusion runtime for UniPi",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "3.0.0-alpha.11",
36
- "@pi-unipi/subagents": "3.0.0-alpha.11"
35
+ "@pi-unipi/core": "3.0.0-alpha.13",
36
+ "@pi-unipi/subagents": "3.0.0-alpha.13"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-ai": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/info-screen",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Dashboard and module registry for Unipi — configurable info overlay with tabbed groups",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "3.0.0-alpha.11"
35
+ "@pi-unipi/core": "3.0.0-alpha.13"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/input-shortcuts",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle — chord-based overlay system",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "3.0.0-alpha.11"
36
+ "@pi-unipi/core": "3.0.0-alpha.13"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -91,6 +91,7 @@ resume it or releases it to Todo.
91
91
  | `queueMax` | `10` | Tasks a session may queue (0 = unlimited); passed to the CLI as `UNIPI_KANBOARD_QUEUE_MAX` |
92
92
  | `maxSessions` | `2` | Distinct sessions running tasks per project (`UNIPI_KANBOARD_MAX_SESSIONS`) |
93
93
  | `turnAddLimit` | `20` | `add` calls allowed per -do turn or runner task (0 = unlimited) |
94
+ | `reminders` | `true` | Progress reminders for hand-worked tasks: a steer on the first file-changing call while a mentioned task is still Todo (R1), and a follow-up at turn end while a started task is still In Progress (R2, max 2 per task). Text only, silent in runner runs |
94
95
  | *actions* | | `Open board…`, `Stop daemon`, `Summary agent command…`, `Rotate access token` |
95
96
 
96
97
  `Summary agent command…` writes through `settings set agent-command` and
@@ -5,7 +5,9 @@
5
5
  * status/doctor — bare lists the commands), `/unipi:kanboard-add`,
6
6
  * `/unipi:kanboard-do` (opens the board-write window for one turn),
7
7
  * `/unipi:kanboard-autowork` (the runner loop: queue first, then claim-next).
8
- * The runner owns claim → In Progress and run-end → In Review. The board itself
8
+ * The runner owns claim → In Progress and run-end → In Review for queued work;
9
+ * an agent working a task by hand uses `start`/`finish` (free), nudged by the
10
+ * progress reminders (src/reminders.ts). The board itself
9
11
  * is written by the Rust binary (`crates/kanboard`); this extension never edits
10
12
  * task files. Bash calls into the binary are gated by the write window
11
13
  * (src/guard.ts): reads always pass, writes need a -do turn or a running task.
@@ -38,6 +40,8 @@ import {
38
40
  type CommandDeps,
39
41
  } from "./src/commands.js";
40
42
  import { createDebugLog, createRunner, registerPlanEventListener, type Runner } from "./src/runner.js";
43
+ import { createProgressTracker, registerProgressReminders, sendReminder } from "./src/reminders.js";
44
+ import { asTaskList } from "./src/shapes.js";
41
45
  import {
42
46
  ACTION_OPEN,
43
47
  ACTION_STOP_DAEMON,
@@ -56,6 +60,9 @@ export const KANBOARD_SKILL = "kanboard";
56
60
  export default function (pi: ExtensionAPI) {
57
61
  // One session id shared by the runner and the agent's bash calls.
58
62
  process.env.UNIPI_KANBOARD_SESSION ??= `pi-${process.pid}`;
63
+ // `start` claims belong to this pi process: the stale-claim reaper releases
64
+ // them to Todo when it dies (the agent's bash inherits the env).
65
+ process.env.UNIPI_KANBOARD_PID ??= String(process.pid);
59
66
  // Limits travel through the environment; refresh on load and before every
60
67
  // tool_call (see the guard registration in commands.ts).
61
68
  applyLimitEnv(readKanboardSettings());
@@ -140,6 +147,26 @@ export default function (pi: ExtensionAPI) {
140
147
  registerProgressRenderer(pi);
141
148
  registerKanboardCommands(pi, buildDeps());
142
149
 
150
+ // R1/R2 progress reminders for hand-worked tasks (silent in runner runs).
151
+ const reminders = registerProgressReminders(
152
+ pi,
153
+ createProgressTracker({
154
+ enabled: () => readKanboardSettings().reminders,
155
+ runnerOwned: () => (runner?.status().phase ?? "idle") !== "idle",
156
+ session: sessionId,
157
+ list: async () => {
158
+ const slug = projectSlug();
159
+ if (!cli || !slug) return [];
160
+ return asTaskList(await cli.run<unknown>(["list"], { extraEnv: { UNIPI_KANBOARD_PROJECT: slug } })).tasks;
161
+ },
162
+ cliPrefix: () => {
163
+ const slug = projectSlug();
164
+ return cli && slug ? `${cli.binary.path} --actor agent --project ${slug}` : null;
165
+ },
166
+ debug,
167
+ }),
168
+ );
169
+
143
170
  registerCommandRunner(ACTION_OPEN, async (ctx) => {
144
171
  const context = ctx as ExtensionContext | undefined;
145
172
  if (!context?.ui) return;
@@ -211,9 +238,13 @@ export default function (pi: ExtensionAPI) {
211
238
  });
212
239
 
213
240
  pi.on("agent_settled", async (_event, ctx) => {
214
- if (!drainPending) return;
215
- drainPending = false;
216
- await drainQueueAfterDo(buildDeps(), ctx as unknown as ExtensionContext);
241
+ const reminder = reminders.takePending();
242
+ if (drainPending) {
243
+ drainPending = false;
244
+ await drainQueueAfterDo(buildDeps(), ctx as unknown as ExtensionContext);
245
+ }
246
+ // A drained queue hands the session to the runner: the reminder is moot.
247
+ if (reminder && (runner?.status().phase ?? "idle") === "idle") sendReminder(pi, reminder);
217
248
  });
218
249
 
219
250
  pi.on("session_shutdown", async (_event, ctx) => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/kanboard",
3
- "version": "3.0.0-alpha.11",
3
+ "version": "3.0.0-alpha.13",
4
4
  "description": "Kanboard v3 — deferred-work board: CLI/daemon bridge, task runner and skill",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -31,7 +31,7 @@
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
- "@pi-unipi/core": "3.0.0-alpha.11"
34
+ "@pi-unipi/core": "3.0.0-alpha.13"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -48,10 +48,10 @@
48
48
  "themes": []
49
49
  },
50
50
  "optionalDependencies": {
51
- "@pi-unipi/kanboard-linux-x64": "3.0.0-alpha.11",
52
- "@pi-unipi/kanboard-linux-arm64": "3.0.0-alpha.11",
53
- "@pi-unipi/kanboard-darwin-x64": "3.0.0-alpha.11",
54
- "@pi-unipi/kanboard-darwin-arm64": "3.0.0-alpha.11",
55
- "@pi-unipi/kanboard-win32-x64": "3.0.0-alpha.11"
51
+ "@pi-unipi/kanboard-linux-x64": "3.0.0-alpha.13",
52
+ "@pi-unipi/kanboard-linux-arm64": "3.0.0-alpha.13",
53
+ "@pi-unipi/kanboard-darwin-x64": "3.0.0-alpha.13",
54
+ "@pi-unipi/kanboard-darwin-arm64": "3.0.0-alpha.13",
55
+ "@pi-unipi/kanboard-win32-x64": "3.0.0-alpha.13"
56
56
  }
57
57
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: kanboard
3
- description: "Kanboard — the project's deferred-work board. Use when the user asks to note a task for later, to see what is on the board, or while working a board task: read it with `unipi-kanboard show`, add notes, block with a question, or file follow-up work."
3
+ description: "Kanboard — the project's deferred-work board. Use when the user asks to note a task for later, to see what is on the board, or to work board tasks (e.g. do UNI-5): `start` a task before working on it and `finish` it with a summary when done; while working a board task: read it with `unipi-kanboard show`, add notes, block with a question, or file follow-up work."
4
4
  ---
5
5
 
6
6
  # Kanboard
@@ -28,6 +28,8 @@ be on `PATH`):
28
28
  <binary> --actor agent --project <slug> edit <ID> --title|--body|--labels … # only tasks you created, while in backlog/todo
29
29
  <binary> --actor agent --project <slug> edit <ID> --strategy none|goal|ralph|swarm|graph|auto # how the runner works it (auto/unset = jev decides)
30
30
  <binary> --actor agent --project <slug> edit <ID> --plan yes|no|auto # plan+approve first (auto/unset = jev decides)
31
+ <binary> --actor agent --project <slug> start <ID> # todo → in progress, claimed for your session (free)
32
+ <binary> --actor agent --project <slug> finish <ID> --comment "<summary>" # in progress → in review, only a task you started (free)
31
33
  <binary> --actor agent --project <slug> move <ID> blocked --comment "<what you need>"
32
34
  <binary> --actor agent --project <slug> link <ID> --after <DEP>
33
35
  <binary> --actor agent --project <slug> unlink <ID> --after <DEP>
@@ -50,9 +52,9 @@ and `rotate-token` are user-only — the agent is refused.
50
52
  | Move | Who |
51
53
  |---|---|
52
54
  | backlog ↔ todo | user, agent |
53
- | todo → in progress | **the runner only** (`claim-next`) |
55
+ | todo → in progress | the runner (`claim-next`), or the agent with `start <ID>` (claims it for its session) |
54
56
  | edit a task | agent — only tasks it created, and only in backlog/todo |
55
- | in progress → in review | **the runner only** (when your turn ends) |
57
+ | in progress → in review | the runner (when a runner task's turn ends), or the agent with `finish <ID> --comment` — only a task its own session `start`ed |
56
58
  | in progress → blocked | agent, system — **comment required** (what you need) |
57
59
  | blocked → todo | user only — comment required (the answer) |
58
60
  | in review → done | user only |
@@ -70,8 +72,15 @@ lists them — read the files there directly if you need one.
70
72
 
71
73
  1. **Never pass `--actor user`.** That is an honour system: pretending to be the
72
74
  user to cancel a task or mark it done breaks the board's whole contract.
73
- 2. **Never move a task to `in_review` or `done`.** The runner writes those when
74
- your turn ends; claiming them yourself loses the summary and the review step.
75
+ 2. **Working a task by hand** (the user says "do UNI-5"): **`start` a task
76
+ before working on it, `finish` it with a summary when done** —
77
+ `start <ID>` before your first edit, `finish <ID> --comment "<what you did>"`
78
+ before your turn ends (or `move <ID> blocked --comment "<what you need>"` if
79
+ you cannot). Both are free and need no `/unipi:kanboard-do`. In Review means
80
+ "the agent did the work, a human reviews" — never leave a task you worked in
81
+ Todo or In Progress. You may have several tasks started. **Never move a task
82
+ to `done`**, and never `finish` a task the runner gave you: the runner writes
83
+ in_review for its own tasks when your turn ends (`finish` refuses them).
75
84
  3. **Never cancel.** If a task should be dropped, block it with
76
85
  `move <ID> blocked --comment "suggest cancel: <why>"` and let the user decide.
77
86
  4. **Follow the blocking rule in your task prompt**: by default work
@@ -85,9 +94,10 @@ lists them — read the files there directly if you need one.
85
94
  why. You may
86
95
  block only the task your own session is running (`move <ID> blocked` checks
87
96
  `--session`/`UNIPI_KANBOARD_SESSION` against the claim).
88
- 6. **To have tasks worked during a `/unipi:kanboard-do` turn, queue them** with
89
- `queue <IDs>` (Todo tasks, up to the queue limit — setting `queueMax`, default 10) — the runner starts them one by one
90
- after the turn ends. Never claim or start them yourself.
97
+ 6. **To have tasks worked by the runner after a `/unipi:kanboard-do` turn, queue
98
+ them** with `queue <IDs>` (Todo tasks, up to the queue limit — setting
99
+ `queueMax`, default 10) — the runner starts them one by one after the turn
100
+ ends. Never `claim-next` yourself, and don't `start` a task you queued.
91
101
  7. Use `note <ID> "<text>"` for progress worth remembering (decisions, what you
92
102
  verified, what you left undone) — it is the activity log the next reader sees.
93
103
  8. Dependencies form a DAG: a task is ready only when every dep reached the chain
@@ -98,8 +108,9 @@ lists them — read the files there directly if you need one.
98
108
  ## Terminal-only execution
99
109
 
100
110
  The web UI can create, edit, reorder, link and move tasks, but it **never runs a
101
- task** — there is no run button. Work starts only from a terminal with
102
- `/unipi:kanboard-autowork start` (or the queue after a `/unipi:kanboard-do`). (The Done column's "Summarize & archive" does call the
111
+ task** — there is no run button. Work starts only from a terminal: the runner
112
+ (`/unipi:kanboard-autowork start`, or the queue after a `/unipi:kanboard-do`), or
113
+ an agent that `start`s a task the user asked it to do. (The Done column's "Summarize & archive" does call the
103
114
  agent command set in the board's Settings, but only to write a summary.)
104
115
 
105
116
  ## Attachments
@@ -42,7 +42,7 @@ Priority -p: 1 none · 2 low · 3 medium · 4 high · 5 urgent`;
42
42
 
43
43
  export function doText(slug: string, cli: string, request: string, queueMax = 10, credits = 0): string {
44
44
  const limit = queueMax === 0 ? "Todo tasks" : `Todo tasks, at most ${queueMax}`;
45
- return `[kanboard] For this request you may use the kanboard skill on project ${slug} (CLI: \`${cli} --actor agent --project ${slug} …\`). You have ${credits} write credit${credits === 1 ? "" : "s"} remaining this session — each board write (add, move, edit, note, link, order, queue) costs 1, reads are free; /unipi:kanboard-do tops the credits back up. You can add tasks, move them between backlog and todo, link, order, note, and edit tasks you created. To have tasks worked, queue them in order with \`queue <IDs>\` (${limit}); the runner starts them one by one after this turn, so do not start the work yourself. Read a task with \`show <ID>\` before editing, linking or queueing it — \`list\` only shows titles and a one-line excerpt. To choose how a task is worked, label it with \`edit <ID> --strategy none|goal|ralph|swarm|graph\` and \`--plan yes|no\`; leave it unset to let the runner decide. If the request is unclear, ask me instead of guessing.
45
+ return `[kanboard] For this request you may use the kanboard skill on project ${slug} (CLI: \`${cli} --actor agent --project ${slug} …\`). You have ${credits} write credit${credits === 1 ? "" : "s"} remaining this session — each board write (add, move, edit, note, link, order, queue) costs 1, reads are free; /unipi:kanboard-do tops the credits back up. You can add tasks, move them between backlog and todo, link, order, note, and edit tasks you created. To have tasks worked by the runner, queue them in order with \`queue <IDs>\` (${limit}); the runner starts them one by one after this turn. If you work a task yourself in this turn instead, \`start <ID>\` it before working on it and \`finish <ID> --comment "<summary>"\` it when done (both free) — never leave a task you worked in Todo or In Progress. Read a task with \`show <ID>\` before editing, linking or queueing it — \`list\` only shows titles and a one-line excerpt. To choose how a task is worked, label it with \`edit <ID> --strategy none|goal|ralph|swarm|graph\` and \`--plan yes|no\`; leave it unset to let the runner decide. If the request is unclear, ask me instead of guessing.
46
46
 
47
47
  Request: ${request}`;
48
48
  }
@@ -19,6 +19,13 @@ export const ADD_CAP_REASON = addCapReason(ADD_CAP);
19
19
  /** Subcommands that never write to the board. */
20
20
  const READONLY = new Set(["list", "show", "attachments", "next", "chain", "search", "status"]);
21
21
 
22
+ /**
23
+ * Writes that cost nothing and need no -do window: `start`/`finish` only touch
24
+ * tasks the session claims itself (the binary enforces ownership), and the
25
+ * board should always show what is being worked.
26
+ */
27
+ const FREE_WRITES = new Set(["start", "finish"]);
28
+
22
29
  /** Global flags that take a value; `--json` is the only valueless one. */
23
30
  const GLOBAL_VALUE_FLAGS = new Set(["--actor", "--project", "--gate", "--session"]);
24
31
 
@@ -60,6 +67,11 @@ export function kanboardInvocations(command: string): KanboardInvocation[] {
60
67
  return out;
61
68
  }
62
69
 
70
+ /** A write that is free and allowed without a -do window (`start`, `finish`). */
71
+ export function isFreeWrite(invocation: KanboardInvocation): boolean {
72
+ return FREE_WRITES.has(invocation.sub);
73
+ }
74
+
63
75
  /** Read-only means: no writes, and the board does not change. */
64
76
  export function isReadonly(invocation: KanboardInvocation): boolean {
65
77
  if (READONLY.has(invocation.sub)) return true;
@@ -96,7 +108,7 @@ export interface WriteGuard {
96
108
 
97
109
  /**
98
110
  * Writes cost session credits (one per write subcommand in the command line);
99
- * reads are free and never blocked. A runner task keeps unlimited access
111
+ * reads and `start`/`finish` are free and never blocked. A runner task keeps unlimited access
100
112
  * (still add-capped). Credits persist across turns and follow-up questions
101
113
  * until spent; /unipi:kanboard-do tops up to N without stacking past N.
102
114
  */
@@ -149,7 +161,7 @@ export function createWriteGuard(
149
161
  lastTask = task;
150
162
  }
151
163
  for (const invocation of invocations) {
152
- if (isReadonly(invocation)) continue;
164
+ if (isReadonly(invocation) || isFreeWrite(invocation)) continue;
153
165
  if (task !== null) {
154
166
  const cap = countAdd(invocation);
155
167
  if (cap) return cap;