@polderlabs/openkan 0.4.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +226 -0
  2. package/LICENSE +21 -0
  3. package/README.md +318 -0
  4. package/agents/openkan.md +254 -0
  5. package/bin/install-agent.mjs +63 -0
  6. package/bin/ok.mjs +17 -0
  7. package/bin/openkan.mjs +10 -0
  8. package/dist/.claude/skills/ok-planning/SKILL.md +285 -0
  9. package/dist/.claude/skills/ok-planning/references/integration.md +153 -0
  10. package/dist/.claude/skills/ok-planning/references/schemas.md +270 -0
  11. package/dist/.claude/skills/ok-planning/references/workflows.md +185 -0
  12. package/dist/.claude/skills/ok-planning/scripts/ok-init.sh +14 -0
  13. package/dist/.claude/skills/ok-planning/scripts/ok-resume.sh +38 -0
  14. package/dist/.claude/skills/ok-planning/scripts/ok-status.sh +24 -0
  15. package/dist/agents/openkan.md +254 -0
  16. package/dist/bin/install-agent.mjs +76 -0
  17. package/dist/bin/ok-install.js +58 -0
  18. package/dist/bin/ok.js +138 -0
  19. package/dist/bin/openkan.js +804 -0
  20. package/dist/commands/organize.md +15 -0
  21. package/dist/kanban/agent-profile.js +8 -0
  22. package/dist/kanban/archive.js +49 -0
  23. package/dist/kanban/bizar.js +242 -0
  24. package/dist/kanban/board.js +367 -0
  25. package/dist/kanban/bulk.js +139 -0
  26. package/dist/kanban/changelog.js +186 -0
  27. package/dist/kanban/chat.js +1280 -0
  28. package/dist/kanban/claude-state.js +974 -0
  29. package/dist/kanban/comments.js +80 -0
  30. package/dist/kanban/docs.js +144 -0
  31. package/dist/kanban/fs.js +163 -0
  32. package/dist/kanban/git.js +196 -0
  33. package/dist/kanban/images.js +140 -0
  34. package/dist/kanban/import.js +295 -0
  35. package/dist/kanban/inputs.js +94 -0
  36. package/dist/kanban/insights.js +140 -0
  37. package/dist/kanban/io.js +75 -0
  38. package/dist/kanban/mdx-render.js +348 -0
  39. package/dist/kanban/mdx.js +231 -0
  40. package/dist/kanban/projects.js +545 -0
  41. package/dist/kanban/search.js +121 -0
  42. package/dist/kanban/server.js +3296 -0
  43. package/dist/kanban/tags.js +124 -0
  44. package/dist/kanban/template.js +145 -0
  45. package/dist/kanban/tsx-sandbox.js +187 -0
  46. package/dist/kanban/watcher.js +270 -0
  47. package/dist/ok/commands/goal.js +65 -0
  48. package/dist/ok/commands/index.js +87 -0
  49. package/dist/ok/commands/init.js +15 -0
  50. package/dist/ok/commands/plan.js +155 -0
  51. package/dist/ok/commands/prd.js +202 -0
  52. package/dist/ok/commands/progress.js +31 -0
  53. package/dist/ok/commands/task.js +377 -0
  54. package/dist/ok/ids.js +98 -0
  55. package/dist/ok/lock.js +156 -0
  56. package/dist/ok/migrate.js +197 -0
  57. package/dist/ok/schemas.js +402 -0
  58. package/dist/ok/storage.js +222 -0
  59. package/dist/skills/openkan/SKILL.md +111 -0
  60. package/dist/skills/openkan/agents/openai.yaml +4 -0
  61. package/dist/skills/openkan/examples/simple-task.mdx +34 -0
  62. package/dist/skills/openkan/examples/with-ask.mdx +32 -0
  63. package/dist/skills/openkan/examples/with-choice.mdx +51 -0
  64. package/dist/skills/openkan/examples/with-preview.mdx +54 -0
  65. package/dist/skills/openkan/references/api.md +169 -0
  66. package/dist/skills/openkan/templates/task.mdx +46 -0
  67. package/dist/web/api.js +257 -0
  68. package/dist/web/app.js +4251 -0
  69. package/dist/web/bizar.js +39 -0
  70. package/dist/web/brand/agent-activity-sprite.svg +1 -0
  71. package/dist/web/brand/banner-docs.svg +24 -0
  72. package/dist/web/brand/banner.svg +32 -0
  73. package/dist/web/brand/empty-sessions.svg +17 -0
  74. package/dist/web/brand/empty-tasks.svg +17 -0
  75. package/dist/web/brand/favicon.svg +9 -0
  76. package/dist/web/brand/infinity-loader-animated.svg +220 -0
  77. package/dist/web/brand/infinity-loader-spritesheet.svg +230 -0
  78. package/dist/web/brand/logo-wordmark.svg +10 -0
  79. package/dist/web/brand/logo.svg +9 -0
  80. package/dist/web/brand/pixel-infinity-track.svg +1 -0
  81. package/dist/web/brand/social-card.svg +26 -0
  82. package/dist/web/changelog-view.js +456 -0
  83. package/dist/web/charts.js +269 -0
  84. package/dist/web/chat-sidebar.js +2397 -0
  85. package/dist/web/chat-status-motion.js +154 -0
  86. package/dist/web/claude-pane.js +820 -0
  87. package/dist/web/command-palette.js +381 -0
  88. package/dist/web/contributors-view.js +317 -0
  89. package/dist/web/cross-tab.js +102 -0
  90. package/dist/web/docs-view.js +168 -0
  91. package/dist/web/experience.css +165 -0
  92. package/dist/web/goals-view.js +45 -0
  93. package/dist/web/home-view.js +113 -0
  94. package/dist/web/images.js +311 -0
  95. package/dist/web/index.html +485 -0
  96. package/dist/web/insights.js +217 -0
  97. package/dist/web/keyboard.js +446 -0
  98. package/dist/web/mdx-viewer.js +600 -0
  99. package/dist/web/path-picker.js +787 -0
  100. package/dist/web/preview-frame.html +187 -0
  101. package/dist/web/settings.js +582 -0
  102. package/dist/web/style.css +8545 -0
  103. package/dist/web/task-view.js +1759 -0
  104. package/dist/web/vendor/gsap.min.js +11 -0
  105. package/dist/web/workspace.css +1513 -0
  106. package/package.json +71 -0
  107. package/skills/openkan/SKILL.md +111 -0
  108. package/skills/openkan/agents/openai.yaml +4 -0
  109. package/skills/openkan/examples/simple-task.mdx +34 -0
  110. package/skills/openkan/examples/with-ask.mdx +32 -0
  111. package/skills/openkan/examples/with-choice.mdx +51 -0
  112. package/skills/openkan/examples/with-preview.mdx +54 -0
  113. package/skills/openkan/references/api.md +169 -0
  114. package/skills/openkan/templates/task.mdx +46 -0
@@ -0,0 +1,153 @@
1
+ # Integration — how the pieces fit
2
+
3
+ ```
4
+ ┌─────────────────────────────────────────────────────────────────┐
5
+ │ Claude Code │
6
+ │ │
7
+ │ ┌─────────────┐ SessionStart ┌──────────────┐ │
8
+ │ │ ok-init.mjs │ ───────────────▶│ bin/ok.ts │ │
9
+ │ │ (hook) │ │ (CLI entry) │ │
10
+ │ └─────────────┘ └──────┬───────┘ │
11
+ │ │ │
12
+ │ ▼ │
13
+ │ ┌─────────────────────┐ │
14
+ │ │ ok/commands/*.ts │ │
15
+ │ │ task / plan / prd │ │
16
+ │ │ index / doctor │ │
17
+ │ └──────────┬──────────┘ │
18
+ │ │ │
19
+ │ ▼ │
20
+ │ ┌─────────────────────┐ │
21
+ │ │ ok/storage.ts │ │
22
+ │ │ ok/lock.ts │ │
23
+ │ │ ok/schemas.ts │ │
24
+ │ └──────────┬──────────┘ │
25
+ └─────────────────────────────────────────┼────────────────────────┘
26
+
27
+
28
+ ┌─────────────────┐
29
+ │ .ok/ │
30
+ │ config.json │
31
+ │ index.json │
32
+ │ tasks/<id>.json │
33
+ │ plans/<id>.json │
34
+ │ prds/<id>.json │
35
+ │ locks/<id>.lock │
36
+ └────────┬────────┘
37
+
38
+ dual-write (every board persist)
39
+
40
+
41
+ ┌─────────────────┐
42
+ │ kanban/board.ts │
43
+ │ OpenKan engine │
44
+ └─────────────────┘
45
+ ```
46
+
47
+ ## Pieces
48
+
49
+ ### 1. `bin/ok.ts` (CLI entry)
50
+
51
+ Dispatches to subcommands. Run via `node --experimental-strip-types
52
+ bin/ok.ts …` or through `bin/ok.mjs` which is a small Node launcher.
53
+
54
+ ### 2. `ok/commands/*.ts` (subcommands)
55
+
56
+ Each file exports a `runX(args)` function and optionally runs as a
57
+ subprocess via the bottom-of-file `if (import.meta.url === …)` block.
58
+
59
+ - `task.ts` — `ok task add|list|show|update|claim|heartbeat|complete|cancel|release`
60
+ - `plan.ts` — `ok plan add|list|show|update`
61
+ - `prd.ts` — `ok prd add|list|show|update`
62
+ - `index.ts` — `ok index` and `ok doctor`
63
+ - `init.ts` — `ok init`
64
+
65
+ ### 3. `ok/storage.ts` (storage layer)
66
+
67
+ Async JSON I/O with atomic writes. Path helpers (`paths(root)`) resolve
68
+ every well-known file/dir under `.ok/`. The core operations are
69
+ typed: `readTask`, `writeTask`, `listTasks`, etc.
70
+
71
+ ### 4. `ok/lock.ts` (claim/heartbeat/release)
72
+
73
+ Advisory JSON locks under `.ok/locks/`. Rejects concurrent writes from
74
+ different owners; leases expire after `--lease-ms` (default 1h).
75
+
76
+ ### 5. `ok/schemas.ts` (validation)
77
+
78
+ TypeScript types and runtime validation. `ok doctor` runs every file
79
+ through the corresponding validator.
80
+
81
+ ### 6. `ok/migrate.ts` (legacy import)
82
+
83
+ One-shot import of `.openkan/tasks.json` and `.openkan/board.json` into
84
+ `.ok/tasks/<id>.json`. Idempotent; second run is a no-op.
85
+
86
+ ### 7. `.claude/hooks/ok-init.mjs` (SessionStart hook)
87
+
88
+ Reads `process.env.CLAUDE_PROJECT_DIR` and runs `ok init` if `.ok/`
89
+ doesn't exist. Always exits 0 (hooks never block Claude).
90
+
91
+ ### 8. `kanban/board.ts` (OpenKan engine)
92
+
93
+ Persists the OpenKan board to `.ok/board.json` AND mirrors each task
94
+ into `.ok/tasks/<id>.json` (via `mirrorToOkStore`). This is the
95
+ integration point: every board write becomes a planning-system write.
96
+
97
+ ### 9. `.claude/skills/ok-planning/` (this skill)
98
+
99
+ The agent-facing surface. Self-contained: a Claude Code agent that loads
100
+ the skill gets everything needed to plan, track, and recover work.
101
+
102
+ ## Adding a new subcommand
103
+
104
+ 1. Create `ok/commands/<name>.ts` exporting `run<X>(args)` that
105
+ returns `{ code: number }`.
106
+ 2. Register it in `bin/ok.ts` under the main switch.
107
+ 3. Add a test in `tests/ok-<name>.test.mts` exercising the happy path
108
+ and the most common failures (parse errors, lock contention, schema
109
+ drift).
110
+ 4. Mention the subcommand in the skill body and in `docs/OK-PLANNING.md`.
111
+
112
+ Keep one logical operation per commit: the subcommand, its tests, and
113
+ its docs land together.
114
+
115
+ ## Why dual-write?
116
+
117
+ The OpenKan engine's existing API surface (`withWrite`, `persist`) is
118
+ unchanged. The mirror write in `mirrorToOkStore` adds a side-effect
119
+ that materialises the planning-system JSON files. Two paths write the
120
+ same data:
121
+
122
+ - `ok task add` → writes `.ok/tasks/<id>.json` directly.
123
+ - OpenKan UI → `kanban/board.ts:persist()` → mirror writes each task.
124
+
125
+ Both paths produce identical `.ok/tasks/<id>.json` content. The mirror
126
+ write is idempotent and safe to call repeatedly.
127
+
128
+ ## What if the mirror write fails?
129
+
130
+ The board persist still succeeds; the mirror write is wrapped in
131
+ try/catch and never aborts the engine. If the mirror fails (disk full,
132
+ permission error), the next `ok index` will notice the missing file
133
+ and surface it via `ok doctor`.
134
+
135
+ ## Why no SQLite / no central DB?
136
+
137
+ - JSON files are diffable in PRs.
138
+ - One file per entity scales to thousands of tasks per project.
139
+ - No native bindings → runs anywhere Node runs.
140
+ - The `ok doctor` + `ok index` pair gives you DB-equivalent consistency
141
+ checks without the runtime.
142
+
143
+ ## Limits
144
+
145
+ The `.ok/` layout assumes:
146
+
147
+ - A single project per directory (the workspace is project-scoped).
148
+ - Trust between writers (advisory locks, not fcntl).
149
+ - File-system atomic rename (every supported platform).
150
+ - Node ≥ 22 (for `--experimental-strip-types`).
151
+
152
+ If any of these assumptions breaks in your environment, the planning
153
+ system is the wrong tool — use a database.
@@ -0,0 +1,270 @@
1
+ # Full schema reference — `ok` planning layer
2
+
3
+ This document expands the abridged schemas in `SKILL.md` with field-level
4
+ descriptions, validation rules, and worked examples.
5
+
6
+ All entities follow the same pattern:
7
+
8
+ ```jsonc
9
+ {
10
+ "schema": "ok.<entity>.v1",
11
+ // ... entity-specific fields ...
12
+ }
13
+ ```
14
+
15
+ The `schema` discriminator is the only identity you should rely on for
16
+ parsing. `ok doctor` checks it before any other validation.
17
+
18
+ ---
19
+
20
+ ## Task — `ok.task.v1`
21
+
22
+ An atomic unit of work. Atomicity is intentional: every task should be
23
+ representable in a single commit; multi-commit work is decomposed into
24
+ multiple tasks or promoted to a Plan.
25
+
26
+ ```ts
27
+ {
28
+ schema: "ok.task.v1",
29
+ id: string, // "tsk-<nanoid-8>"
30
+ title: string, // 1..200 chars
31
+ description?: string, // optional markdown-lite
32
+ owner?: string, // agent/user; free-form
33
+ status: "pending" | "in_progress" | "review" | "done" | "cancelled",
34
+ priority?: "p0" | "p1" | "p2" | "p3",
35
+ plan?: string, // "pln-<id>"
36
+ prd?: string, // "prd-<id>"
37
+ scopes?: string[], // tags / paths / identifiers
38
+ deps?: string[], // task ids this depends on
39
+ createdAt: string, // ISO
40
+ updatedAt: string, // ISO
41
+ startedAt?: string, // ISO; set on first in_progress
42
+ completedAt?: string, // ISO; set on done/cancelled
43
+ evidence?: string[], // commit shas, file:line, URLs
44
+ acceptance?: string[], // definition-of-done bullets
45
+ }
46
+ ```
47
+
48
+ ### Status transitions
49
+
50
+ ```
51
+ pending ──claim──▶ in_progress ──update──▶ review ──update──▶ done
52
+ │ │ │
53
+ └────cancel──────────┴──────────────────────┘
54
+ ```
55
+
56
+ - `claim` transitions `pending → in_progress` and writes a lock.
57
+ - `update --status review` moves an in-progress task into review.
58
+ - `complete` is the only transition to `done`; it requires `--evidence`.
59
+ - `cancel` is terminal; it requires `--reason` (recorded as evidence).
60
+
61
+ The status enum is the canonical lifecycle indicator. Column placement
62
+ in OpenKan's UI is a presentation concern and is mapped back to `status`
63
+ on read.
64
+
65
+ ### Example
66
+
67
+ ```json
68
+ {
69
+ "schema": "ok.task.v1",
70
+ "id": "tsk-9brjCkWa",
71
+ "title": "Implement claim helper",
72
+ "description": "Cover happy path, expired lease, and double-claim.",
73
+ "owner": "alice",
74
+ "status": "in_progress",
75
+ "priority": "p1",
76
+ "plan": "pln-7Hg2Vu3W",
77
+ "prd": "prd-T6g9Pz_X",
78
+ "scopes": ["ok/lock.ts", "tests/ok-lock.test.mts"],
79
+ "deps": [],
80
+ "createdAt": "2026-09-04T10:00:00.000Z",
81
+ "updatedAt": "2026-09-04T10:01:30.000Z",
82
+ "startedAt": "2026-09-04T10:01:30.000Z",
83
+ "acceptance": ["two test cases per branch", "no fcntl dependency"]
84
+ }
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Plan — `ok.plan.v1`
90
+
91
+ A medium-lived container for a cohesive set of tasks.
92
+
93
+ ```ts
94
+ {
95
+ schema: "ok.plan.v1",
96
+ id: string, // "pln-<nanoid-8>"
97
+ title: string,
98
+ summary: string, // 1-2 sentence elevator pitch
99
+ prd?: string, // parent PRD id
100
+ phase?: string, // current phase label (free-form)
101
+ status: "draft" | "active" | "blocked" | "complete" | "abandoned",
102
+ tasks: string[], // ordered task ids
103
+ acceptance: string[], // plan-level DoD
104
+ createdAt: string, // ISO
105
+ updatedAt: string, // ISO
106
+ }
107
+ ```
108
+
109
+ ### Status transitions
110
+
111
+ ```
112
+ draft ──update──▶ active ──update──▶ complete
113
+ │ │
114
+ └─update─────────┴──update──▶ abandoned
115
+
116
+ └─update──▶ blocked ──update──▶ active
117
+ ```
118
+
119
+ - `draft` is the only state in which a plan can be edited without
120
+ justification (acceptance bullets, task list, phase label).
121
+ - `active` plans show up in `ok plan list` defaults.
122
+ - `complete` is terminal.
123
+
124
+ ### Example
125
+
126
+ ```json
127
+ {
128
+ "schema": "ok.plan.v1",
129
+ "id": "pln-7Hg2Vu3W",
130
+ "title": "v0.1: schemas + storage",
131
+ "summary": "Ship the .ok/ storage layer end-to-end.",
132
+ "prd": "prd-T6g9Pz_X",
133
+ "phase": "M2",
134
+ "status": "active",
135
+ "tasks": ["tsk-9brjCkWa", "tsk-AbCdEfGh", "tsk-IjKlMnOp"],
136
+ "acceptance": ["all schemas validate", "tests green", "doctor returns 0 issues"],
137
+ "createdAt": "2026-09-04T09:55:00.000Z",
138
+ "updatedAt": "2026-09-04T10:01:30.000Z"
139
+ }
140
+ ```
141
+
142
+ ---
143
+
144
+ ## PRD — `ok.prd.v1`
145
+
146
+ A long-horizon Product Requirements Document.
147
+
148
+ ```ts
149
+ {
150
+ schema: "ok.prd.v1",
151
+ id: string, // "prd-<nanoid-8>"
152
+ title: string,
153
+ vision: string, // one paragraph
154
+ goals: PrdGoal[], // see below
155
+ nonGoals: string[],
156
+ successMetrics: PrdSuccessMetric[], // see below
157
+ milestones: PrdMilestone[], // see below
158
+ risks: PrdRisk[], // see below
159
+ plans: string[], // plan ids that contribute
160
+ owners: string[], // agents/users
161
+ reviewCadence?: string, // "weekly", "monthly", etc.
162
+ status: "draft" | "active" | "shipped" | "abandoned",
163
+ createdAt: string,
164
+ updatedAt: string,
165
+ nextReviewAt?: string, // ISO
166
+ }
167
+ ```
168
+
169
+ ### Sub-shapes
170
+
171
+ ```ts
172
+ type PrdGoal = { id: string; text: string; status: "open" | "in_progress" | "met" | "dropped" };
173
+ type PrdSuccessMetric = { name: string; target: string; current?: string };
174
+ type PrdMilestone = { id: string; title: string; dueBy?: string; status: "open" | "hit" | "missed" | "dropped" };
175
+ type PrdRisk = { id: string; text: string; severity: "low" | "med" | "high"; mitigation?: string };
176
+ ```
177
+
178
+ ### Goal / milestone ids
179
+
180
+ Goal ids default to `g1`, `g2`, … in creation order. Milestone ids
181
+ default to `m1`, `m2`, …. Risk ids are auto-assigned by `ok doctor` if
182
+ you write the file by hand.
183
+
184
+ ### Example
185
+
186
+ ```json
187
+ {
188
+ "schema": "ok.prd.v1",
189
+ "id": "prd-T6g9Pz_X",
190
+ "title": "Self-contained planning workspace",
191
+ "vision": "Every project ships with .ok/ for tasks, plans, and PRDs.",
192
+ "goals": [
193
+ { "id": "g1", "text": "ship CLI", "status": "met" },
194
+ { "id": "g2", "text": "ship skill", "status": "open" },
195
+ { "id": "g3", "text": "ship auto-init", "status": "open" }
196
+ ],
197
+ "nonGoals": ["Windows support", "TUI"],
198
+ "successMetrics": [
199
+ { "name": "active planning workspaces", "target": "20", "current": "0" },
200
+ { "name": "p50 session bootstrap", "target": "< 200ms", "current": "n/a" }
201
+ ],
202
+ "milestones": [
203
+ { "id": "m1", "title": "v0.1 schema", "dueBy": "2026-10-01T00:00:00Z", "status": "open" },
204
+ { "id": "m2", "title": "v1.0 launch", "dueBy": "2026-12-15T00:00:00Z", "status": "open" }
205
+ ],
206
+ "risks": [
207
+ { "id": "r1", "text": "agent role confusion", "severity": "med", "mitigation": "skill body disambiguates triggers" }
208
+ ],
209
+ "plans": ["pln-7Hg2Vu3W"],
210
+ "owners": ["karen", "todd"],
211
+ "reviewCadence": "weekly",
212
+ "status": "active",
213
+ "createdAt": "2026-09-04T09:00:00.000Z",
214
+ "updatedAt": "2026-09-04T10:00:00.000Z",
215
+ "nextReviewAt": "2026-09-11T09:00:00Z"
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Config — `ok.config.v1`
222
+
223
+ Workspace metadata. One per project. Never carries entity data.
224
+
225
+ ```ts
226
+ {
227
+ schema: "ok.config.v1",
228
+ version: 1,
229
+ defaultOwner?: string,
230
+ createdAt: string,
231
+ updatedAt: string,
232
+ }
233
+ ```
234
+
235
+ `defaultOwner` is applied to new tasks that omit `--owner`. Useful for
236
+ single-operator projects.
237
+
238
+ ---
239
+
240
+ ## Index — `ok.index.v1`
241
+
242
+ A compact pointer file for fast listings. Rebuilt via `ok index`.
243
+
244
+ ```ts
245
+ {
246
+ schema: "ok.index.v1",
247
+ tasks: IndexEntry[], // {id, status, title, updatedAt}
248
+ plans: IndexEntry[],
249
+ prds: IndexEntry[],
250
+ updatedAt: string,
251
+ }
252
+ ```
253
+
254
+ Each entry is sorted by `updatedAt` descending. Agents that just want
255
+ "what is open?" can read this file and skip the per-task JSONs.
256
+
257
+ ---
258
+
259
+ ## Validation rules summary
260
+
261
+ - All ids must match their kind's regex (`tsk-…`, `pln-…`, `prd-…`).
262
+ - `title` on a Task must be 1..200 chars.
263
+ - Status enums are exact-match; arbitrary strings are rejected.
264
+ - `createdAt` / `updatedAt` must be ISO timestamps (`Date.parse` works).
265
+ - Array fields must be string arrays when present.
266
+ - Unknown fields are ignored (forward-compat); missing required fields
267
+ are rejected.
268
+
269
+ If you write the file by hand and want validation feedback, run
270
+ `ok doctor` after writing.
@@ -0,0 +1,185 @@
1
+ # Workflows — six end-to-end agent flows
2
+
3
+ Each workflow shows the goal, the `ok` commands, and what the agent
4
+ should look for in the output. Run them in any order; each is
5
+ self-contained.
6
+
7
+ ---
8
+
9
+ ## 1. Start a session and claim work
10
+
11
+ Goal: discover open tasks, take ownership of one before starting.
12
+
13
+ ```sh
14
+ # 1. Ensure the workspace exists
15
+ ok init
16
+
17
+ # 2. Find work
18
+ ok task list --status pending --json
19
+ ok task list --status in_progress --json # avoid collisions
20
+
21
+ # 3. Read the chosen task
22
+ ok task show <id> --json
23
+
24
+ # 4. Claim it (writes a lock for 1h default)
25
+ ok task claim <id> --owner <self>
26
+ ```
27
+
28
+ What to watch for:
29
+
30
+ - If `ok task claim` prints `locked by …`, the lock is held by another
31
+ agent. Coordinate or wait for the lease to expire (default 1h).
32
+ - `--lease-ms` lets you claim for longer if you know the work is big:
33
+ `ok task claim <id> --owner <self> --lease-ms 3600000`.
34
+
35
+ ---
36
+
37
+ ## 2. End a session with concrete evidence
38
+
39
+ Goal: leave the workspace in a state the next agent can pick up.
40
+
41
+ ```sh
42
+ # Did you finish?
43
+ ok task complete <id> --owner <self> --evidence "<sha-or-path-or-summary>"
44
+ # or, did you decide to drop?
45
+ ok task cancel <id> --owner <self> --reason "<why>"
46
+ # or, did you just stop without finishing?
47
+ ok task release <id> --owner <self>
48
+
49
+ # Always refresh the index so the next agent sees fresh state
50
+ ok index
51
+ ```
52
+
53
+ Evidence expectations:
54
+
55
+ - A commit sha (`abc1234`)
56
+ - A `path:line` reference (`ok/lock.ts:60-105`)
57
+ - A URL (`https://…`)
58
+ - A one-line summary of what shipped
59
+
60
+ Anything that lets the next agent (or the user) verify the work without
61
+ chatting with you.
62
+
63
+ ---
64
+
65
+ ## 3. Scope a feature as PRD → Plan → Tasks
66
+
67
+ Goal: capture a long-horizon goal, group it into a milestone, and break
68
+ that into atomic tasks.
69
+
70
+ ```sh
71
+ # 1. Define the north star
72
+ ok prd add "<short title>" \
73
+ --vision "<one paragraph north star>" \
74
+ --goals "g1|g2|g3" \
75
+ --milestones "v0.1|v1.0" \
76
+ --non-goals "X|Y" \
77
+ --owners "<agent1>,<agent2>" \
78
+ --review-cadence weekly
79
+ # → prd-AbCdEfGh
80
+
81
+ # 2. Group tasks under the PRD
82
+ ok plan add "v0.1: <milestone>" \
83
+ --prd prd-AbCdEfGh \
84
+ --summary "<elevator pitch>" \
85
+ --acceptance "ship a" "ship b" \
86
+ --tasks tsk-…,tsk-…
87
+ # → pln-XyZ12345
88
+
89
+ # 3. Add tasks with back-link to the plan (optional)
90
+ ok task add "<task>" --plan pln-XyZ12345 --owner <self>
91
+ ok task add "<task>" --prd prd-AbCdEfGh --owner <self>
92
+ ```
93
+
94
+ Tip: keep PRDs stable across many sessions. Plans are short-lived;
95
+ don't promote plans to PRDs unless the work spans weeks.
96
+
97
+ ---
98
+
99
+ ## 4. Recover from drift or corruption
100
+
101
+ Goal: bring a `.ok/` tree back to a known-good state.
102
+
103
+ ```sh
104
+ # 1. Diagnose
105
+ ok doctor
106
+
107
+ # 2. If the index is stale, rebuild
108
+ ok index
109
+
110
+ # 3. If a single file is corrupt, fix or remove it
111
+ rm .ok/tasks/tsk-bad.json
112
+ ok index
113
+ ok doctor
114
+ ```
115
+
116
+ Common drift scenarios:
117
+
118
+ - **Stale lock** — `ok task claim <id> --owner <self>` after the lease
119
+ expires, or `ok task release <id> --owner <stale-owner>` if you know
120
+ the owner.
121
+ - **Index out of sync** — `ok index` rebuilds it from the filesystem.
122
+ - **Schema version mismatch** — bump the schema field and add a
123
+ migration in `ok/storage.ts`; never silently drop fields.
124
+ - **Partial write leftover** — `.tmp-<pid>-<ts>` files are safe to
125
+ delete; `ok init` will recreate them as needed.
126
+
127
+ ---
128
+
129
+ ## 5. Hand off to another agent
130
+
131
+ Goal: pass ownership cleanly without losing the lock or the work.
132
+
133
+ ```sh
134
+ # Releasing agent
135
+ ok task update <id> --evidence "handoff to <new-agent>: <summary of state>"
136
+ ok task release <id> --owner <self>
137
+
138
+ # Picking-up agent
139
+ ok task claim <id> --owner <new-agent>
140
+ ```
141
+
142
+ If the handover is bigger than a task (a whole plan or PRD), use
143
+ `--append-plan` on the PRD to record the new plan, and update
144
+ `prd.owners` via a JSON edit (or wait for the `ok prd update --owners`
145
+ flag to land).
146
+
147
+ ---
148
+
149
+ ## 6. Migrate from a legacy `.openkan/` workspace
150
+
151
+ Goal: bring an existing OpenKan board under the new `.ok/` planning
152
+ layer.
153
+
154
+ ```sh
155
+ ok migrate-from-openkan # one-shot, idempotent
156
+ ok doctor # validate the result
157
+ ok index # rebuild the index
158
+ ```
159
+
160
+ Status mapping (legacy → planning):
161
+
162
+ | Legacy state | Planning status |
163
+ |--------------|-----------------|
164
+ | `done` | `done` |
165
+ | `running`, `waiting-for-input` | `in_progress` |
166
+ | `cancelled`, `failed` | `cancelled` |
167
+ | column `review` (state idle) | `review` |
168
+ | column `doing` (state idle) | `in_progress` |
169
+ | otherwise | `pending` |
170
+
171
+ Archived tasks become `cancelled`. Priority `urgent` → `p0`,
172
+ `normal` → `p2`, `low` → `p3`.
173
+
174
+ If a task has both a `tasks.json` and a `board.json` entry, the
175
+ `tasks.json` version wins (it's the older source of truth).
176
+
177
+ ---
178
+
179
+ ## Diagnostic commands
180
+
181
+ - `ok help` — usage summary.
182
+ - `ok doctor` — schema validation across the tree.
183
+ - `ok index` — rebuild `.ok/index.json` from the filesystem.
184
+ - `ok task list --json | jq '. | length'` — quick counts.
185
+ - `ok task show <id> --json` — full record.
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bash
2
+ # ok-init.sh — bash wrapper that runs `ok init` and prints the layout.
3
+ #
4
+ # Usage: ok-init.sh [project-root]
5
+ # (defaults to the current directory)
6
+
7
+ set -euo pipefail
8
+
9
+ ROOT="${1:-$(pwd)}"
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ # Resolve the repo root (the directory that contains bin/ok.ts).
12
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
13
+
14
+ ( cd "$ROOT" && node --experimental-strip-types "$REPO_ROOT/bin/ok.ts" init )
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ # ok-resume.sh — bash wrapper that prints an at-a-glance summary of what's
3
+ # open, in progress, and shippable.
4
+ #
5
+ # Reads .ok/index.json if it exists, else rebuilds it on the fly.
6
+ # Sorts each section by `updatedAt` descending.
7
+
8
+ set -euo pipefail
9
+
10
+ ROOT="${1:-$(pwd)}"
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
13
+
14
+ cd "$ROOT"
15
+
16
+ INDEX=".ok/index.json"
17
+ if [[ ! -f "$INDEX" ]]; then
18
+ node --experimental-strip-types "$REPO_ROOT/bin/ok.ts" index >/dev/null
19
+ fi
20
+
21
+ if command -v jq >/dev/null 2>&1; then
22
+ tasks_total=$(jq '.tasks | length' "$INDEX")
23
+ plans_total=$(jq '.plans | length' "$INDEX")
24
+ prds_total=$(jq '.prds | length' "$INDEX")
25
+ tasks_open=$(jq '[.tasks[] | select(.status == "pending" or .status == "in_progress" or .status == "review")] | length' "$INDEX")
26
+ plans_active=$(jq '[.plans[] | select(.status == "active")] | length' "$INDEX")
27
+ prds_active=$(jq '[.prds[] | select(.status == "active")] | length' "$INDEX")
28
+
29
+ echo "tasks: $tasks_open open / $tasks_total total"
30
+ echo "plans: $plans_active active / $plans_total total"
31
+ echo "prds: $prds_active active / $prds_total total"
32
+ echo "---"
33
+ echo "most-recently-updated items:"
34
+ jq -r '((.tasks + .plans + .prds) | sort_by(-.updatedAt) | .[0:5] | .[] | " [\(.status)] \(.id) \(.title)")' "$INDEX"
35
+ else
36
+ echo "open tasks: $(node --experimental-strip-types "$REPO_ROOT/bin/ok.ts" task list --status pending --json | wc -l) bytes of JSON"
37
+ echo "(install jq for the full breakdown)"
38
+ fi
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bash
2
+ # ok-status.sh — bash wrapper that prints a quick health summary.
3
+ #
4
+ # Runs `ok doctor && ok task list --status pending --json | jq '. | length'`.
5
+ # Falls back gracefully when `jq` is not installed.
6
+
7
+ set -euo pipefail
8
+
9
+ ROOT="${1:-$(pwd)}"
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
12
+
13
+ cd "$ROOT"
14
+
15
+ node --experimental-strip-types "$REPO_ROOT/bin/ok.ts" doctor
16
+
17
+ if command -v jq >/dev/null 2>&1; then
18
+ open=$(node --experimental-strip-types "$REPO_ROOT/bin/ok.ts" task list --status pending --json | jq 'length')
19
+ in_progress=$(node --experimental-strip-types "$REPO_ROOT/bin/ok.ts" task list --status in_progress --json | jq 'length')
20
+ review=$(node --experimental-strip-types "$REPO_ROOT/bin/ok.ts" task list --status review --json | jq 'length')
21
+ echo "open tasks: $open in progress: $in_progress in review: $review"
22
+ else
23
+ echo "(install jq for full counts; `ok task list --status pending --json` returns the array)"
24
+ fi