runlist 0.0.0 → 0.94.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.
Files changed (166) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1114 -6
  3. package/assets/app/app.css +283 -0
  4. package/assets/app/app.mjs +381 -0
  5. package/assets/app/block-editor.mjs +182 -0
  6. package/assets/app/block-model.mjs +52 -0
  7. package/assets/app/document-create.mjs +86 -0
  8. package/assets/app/document-lifecycle.mjs +36 -0
  9. package/assets/app/document-stages.mjs +22 -0
  10. package/assets/app/document-views.mjs +33 -0
  11. package/assets/app/document-yardstick.mjs +258 -0
  12. package/assets/app/editor-navigation.mjs +51 -0
  13. package/assets/app/filing-navigation.mjs +138 -0
  14. package/assets/app/git-changes.mjs +80 -0
  15. package/assets/app/git-commit.mjs +46 -0
  16. package/assets/app/index.html +70 -0
  17. package/assets/app/library-navigation.mjs +93 -0
  18. package/assets/app/outline.mjs +18 -0
  19. package/assets/app/quick-navigation.mjs +52 -0
  20. package/assets/app/record-navigation.mjs +78 -0
  21. package/assets/app/recovery-center.mjs +53 -0
  22. package/assets/app/semantic-search.mjs +14 -0
  23. package/assets/app/settings.mjs +15 -0
  24. package/assets/app/shared.mjs +104 -0
  25. package/assets/app/stage-source.mjs +75 -0
  26. package/assets/app/template-editor.mjs +47 -0
  27. package/assets/app/theme.mjs +25 -0
  28. package/assets/app/transport.mjs +43 -0
  29. package/assets/contracts/source-editing-v1.md +232 -0
  30. package/assets/opencode/plugin.js +162 -0
  31. package/assets/schemas/runlist-record-v1.schema.json +912 -0
  32. package/bin/dotmd.mjs +5 -0
  33. package/bin/runlist.mjs +2714 -0
  34. package/package.json +53 -6
  35. package/plugins/runlist-codex/.codex-plugin/plugin.json +18 -0
  36. package/plugins/runlist-codex/bin/runlist-hook +86 -0
  37. package/plugins/runlist-codex/hooks/hooks.json +16 -0
  38. package/plugins/runlist-codex/skills/runlist/SKILL.md +25 -0
  39. package/runlist.config.example.mjs +370 -0
  40. package/scripts/postinstall.mjs +56 -0
  41. package/src/agent-context.mjs +201 -0
  42. package/src/ai.mjs +30 -0
  43. package/src/app-create.mjs +169 -0
  44. package/src/app-filing.mjs +139 -0
  45. package/src/app-git-commits.mjs +48 -0
  46. package/src/app-git.mjs +180 -0
  47. package/src/app-library.mjs +152 -0
  48. package/src/app-lifecycle-worker.mjs +12 -0
  49. package/src/app-lifecycle.mjs +79 -0
  50. package/src/app-records.mjs +134 -0
  51. package/src/app-search.mjs +80 -0
  52. package/src/app-semantic-search.mjs +105 -0
  53. package/src/app-service.mjs +208 -0
  54. package/src/app-yardstick.mjs +269 -0
  55. package/src/app.mjs +102 -0
  56. package/src/atomic-mutation.mjs +1736 -0
  57. package/src/baton.mjs +435 -0
  58. package/src/body-link.mjs +48 -0
  59. package/src/bulk-tag.mjs +174 -0
  60. package/src/check-collapse.mjs +75 -0
  61. package/src/claude-commands.mjs +75 -0
  62. package/src/cli-editor.mjs +8 -0
  63. package/src/code-refs.mjs +545 -0
  64. package/src/codex-integration.mjs +81 -0
  65. package/src/color.mjs +14 -0
  66. package/src/commands.mjs +374 -0
  67. package/src/completions.mjs +93 -0
  68. package/src/config-edit.mjs +606 -0
  69. package/src/config.mjs +705 -0
  70. package/src/decision-action.mjs +58 -0
  71. package/src/decision.mjs +220 -0
  72. package/src/decisions.mjs +787 -0
  73. package/src/deps.mjs +317 -0
  74. package/src/desktop-install.mjs +158 -0
  75. package/src/desktop-runtime.mjs +4 -0
  76. package/src/desktop.mjs +25 -0
  77. package/src/diff.mjs +101 -0
  78. package/src/doctor.mjs +591 -0
  79. package/src/durable-rename.mjs +55 -0
  80. package/src/errors-read.mjs +44 -0
  81. package/src/export.mjs +496 -0
  82. package/src/extractors.mjs +101 -0
  83. package/src/filing.mjs +255 -0
  84. package/src/fix-membership.mjs +134 -0
  85. package/src/fix-refs.mjs +174 -0
  86. package/src/flags.mjs +318 -0
  87. package/src/frontmatter-fix.mjs +195 -0
  88. package/src/frontmatter.mjs +252 -0
  89. package/src/git-commit-filters.mjs +32 -0
  90. package/src/git-commit-protocol.mjs +198 -0
  91. package/src/git-commit-signing.mjs +75 -0
  92. package/src/git-commit-store.mjs +26 -0
  93. package/src/git-commit-support.mjs +16 -0
  94. package/src/git-commit-worker.mjs +32 -0
  95. package/src/git.mjs +909 -0
  96. package/src/glossary-check.mjs +35 -0
  97. package/src/glossary.mjs +243 -0
  98. package/src/graph.mjs +298 -0
  99. package/src/guard.mjs +488 -0
  100. package/src/health.mjs +212 -0
  101. package/src/hints.mjs +129 -0
  102. package/src/host-integration.mjs +339 -0
  103. package/src/hub-membership.mjs +284 -0
  104. package/src/hub.mjs +292 -0
  105. package/src/hud.mjs +436 -0
  106. package/src/index-file.mjs +163 -0
  107. package/src/index.mjs +478 -0
  108. package/src/init.mjs +512 -0
  109. package/src/install.mjs +222 -0
  110. package/src/journal-read.mjs +116 -0
  111. package/src/journal.mjs +472 -0
  112. package/src/lifecycle.mjs +1444 -0
  113. package/src/lint.mjs +386 -0
  114. package/src/managed-path.mjs +192 -0
  115. package/src/markdown-code-spans.mjs +58 -0
  116. package/src/migrate-prompts.mjs +171 -0
  117. package/src/migrate-template.mjs +170 -0
  118. package/src/migrate.mjs +90 -0
  119. package/src/misuse-read.mjs +61 -0
  120. package/src/model-request.mjs +33 -0
  121. package/src/model.mjs +523 -0
  122. package/src/modules.mjs +355 -0
  123. package/src/naming.mjs +55 -0
  124. package/src/native-action.mjs +59 -0
  125. package/src/native-record.mjs +244 -0
  126. package/src/new.mjs +1321 -0
  127. package/src/output-identity.mjs +111 -0
  128. package/src/parent-plan.mjs +58 -0
  129. package/src/parse-cache.mjs +99 -0
  130. package/src/path-containment.mjs +15 -0
  131. package/src/pickup-card.mjs +293 -0
  132. package/src/pickup.mjs +671 -0
  133. package/src/prompt.mjs +25 -0
  134. package/src/prompts.mjs +585 -0
  135. package/src/query.mjs +977 -0
  136. package/src/record-action.mjs +11 -0
  137. package/src/record-create.mjs +82 -0
  138. package/src/reference-planner.mjs +388 -0
  139. package/src/reference-values.mjs +11 -0
  140. package/src/rename.mjs +107 -0
  141. package/src/render.mjs +678 -0
  142. package/src/roadmap.mjs +184 -0
  143. package/src/runlist.mjs +944 -0
  144. package/src/section.mjs +225 -0
  145. package/src/semantic-search-client.mjs +58 -0
  146. package/src/ship.mjs +166 -0
  147. package/src/show.mjs +101 -0
  148. package/src/skill-drift.mjs +98 -0
  149. package/src/source-editor.mjs +491 -0
  150. package/src/stages.mjs +73 -0
  151. package/src/state-migration.mjs +123 -0
  152. package/src/stats.mjs +200 -0
  153. package/src/status-metadata.mjs +87 -0
  154. package/src/statuses.mjs +721 -0
  155. package/src/summary.mjs +74 -0
  156. package/src/surfaces.mjs +28 -0
  157. package/src/sync-status.mjs +316 -0
  158. package/src/template-store.mjs +62 -0
  159. package/src/update.mjs +338 -0
  160. package/src/use.mjs +58 -0
  161. package/src/util.mjs +337 -0
  162. package/src/validate.mjs +794 -0
  163. package/src/watch.mjs +56 -0
  164. package/src/xref.mjs +406 -0
  165. package/src/yardstick-command.mjs +178 -0
  166. package/src/yardstick.mjs +112 -0
package/README.md CHANGED
@@ -1,14 +1,1122 @@
1
1
  # runlist
2
2
 
3
- Placeholder for the rename of [`dotmd-cli`](https://www.npmjs.com/package/dotmd-cli).
3
+ CLI for managing Markdown documents with YAML frontmatter.
4
4
 
5
- `runlist` manages markdown plan documents — lifecycle and status, ranked work queues,
6
- index generation, reference integrity, and session-to-session handoff.
5
+ runlist (formerly dotmd) indexes, queries, validates, graphs, exports, and lifecycle-manages plans,
6
+ ADRs, RFCs, design docs, and other structured Markdown. It is built for
7
+ AI-assisted development workflows where documents need to remain current and
8
+ safe to mutate.
7
9
 
8
- Until the rename lands, install the current package:
10
+ - Zero runtime dependencies
11
+ - Node.js 20 or newer
12
+ - Runtime support for Linux, macOS, and Windows
13
+ - Type-aware lifecycle rules for plans, docs, and saved prompts
9
14
 
15
+ ## Install
16
+
17
+ ```bash
18
+ npm install -g runlist # global CLI and agent-host hooks
19
+ npm install -D runlist # project scripts via node_modules/.bin
20
+ npx runlist init # try it without installing
21
+ ```
22
+
23
+ `runlist` is the canonical executable, `rl` is its short convenience alias, and
24
+ `dotmd` remains supported during the compatibility window. All three invoke the
25
+ same CLI. The npm package is `runlist`; existing `dotmd-cli` installs should be
26
+ replaced with `runlist`. The Claude Code plugin is `runlist@runlist`. Legacy
27
+ `dotmd.config.*` files, `DOTMD_*` variables and `.dotmd/` state keep working.
28
+
29
+ If you installed the old package globally, remove it before installing the new
30
+ one because both packages provide the same executable names:
31
+
32
+ ```bash
33
+ npm uninstall -g dotmd-cli
34
+ npm install -g runlist
35
+ ```
36
+
37
+ The optional desktop app is a separate download with the same Markdown engine; see
38
+ [desktop setup and validation](desktop/README.md). The delivered app includes
39
+ reviewed plan/doc/hub creation, ⌘/Ctrl+K navigation, on-demand local content
40
+ search, saved library views, checkout-wide recovery and reviewed local Git commits
41
+ for qualified macOS checkouts. Saving writes local Markdown; committing remains
42
+ a separate reviewed action. **Product goal** shows your written yardstick beside
43
+ a plan's delivery statement, with explicit Review/Apply for your assessment.
44
+ **Filing** shows where plans are homed and opens the supporting hub rows.
45
+ Stage filters, grouping and editing are included. Optional grepmax semantic
46
+ controls are experimental; live retrieval depends on a compatible external
47
+ provider. Local chat and push are deferred.
48
+
49
+ The previous Apple Silicon GUI was **0.94.0-rc.1**, signed and accepted by Apple.
50
+ Its public installers have been withdrawn during a privacy cleanup. A clean
51
+ replacement has not yet been built. Existing installations can still be opened.
52
+ The desktop app is separate from CLI 0.94.1,
53
+ which includes optional plan-filing checks and the owner-written product yardstick,
54
+ corrected hub-category inheritance, updates for every saved Claude plugin scope,
55
+ and `runlist desktop install`.
56
+ Updating the CLI does not replace the GUI's bundled engine; this GUI reports 0.94.0-rc.1.
57
+ Earlier development packages and their qualification results are historical;
58
+ see the [desktop validation record](desktop/VALIDATION.md).
59
+
60
+ Deferred work awaiting selection:
61
+
62
+ 1. Expand local-commit qualification to process filters, broader clean-filter
63
+ command profiles, Windows, Linux x64/other Git versions and additional signing profiles.
64
+ Configured commit hooks and noninteractive SSH/OpenPGP signing are supported
65
+ in current source on the qualified macOS/Linux combinations. Push is deferred.
66
+ 2. Optional grepmax live retrieval/coverage qualification is parked: the owner
67
+ reports a watcher issue requiring a reboot. The last check saw gmax 0.26.65
68
+ ready, but its installed bridge/daemon lacked Runlist's required document-search
69
+ contract. Watcher recovery and compatibility must be verified before live
70
+ qualification resumes; preserve the existing safety hold. See the
71
+ current status and resume gates.
72
+ The compatibility plan
73
+ now has steps 1–4 passing against gmax 0.26.66 source and an extracted local
74
+ npm candidate, including the actual private helper. Deployment and live
75
+ checks remain separate gates.
76
+ Large-checkout inventory,
77
+ unavailable-state memory/latency and bridge cleanup have terminal evidence.
78
+ The Runlist GUI/backend adapter and guarded protocol fixtures are included
79
+ in GUI 0.94.0-rc.1. External provider deployment and successful live retrieval
80
+ remain unverified. Optional local model chat is deferred.
81
+ 3. Complete native plan lifecycle, legacy migration,
82
+ settings/diagnostics. GUI yardstick and Filing reports are delivered in
83
+ 0.94.0-rc.1. Stage filters/groups and guarded Stage editing are also delivered.
84
+ 4. Finish platform qualification: a terminal-ready Windows host, Linux x64 and
85
+ older distributions, real-version upgrades, fresh/minimum-version and Intel
86
+ Macs, plus native rendering, focus, accessibility and whole-window memory.
87
+
88
+ Mac GUI downloads are temporarily unavailable pending a clean replacement.
89
+ CLI 0.94.1 includes the optional product yardstick.
90
+ The supported desktop
91
+ release is Apple Silicon macOS 13.5 or newer. Broader platform work and
92
+ experimental semantic search remain separate follow-up work.
93
+
94
+ Maintainer release automation is POSIX-only because it uses Bash and POSIX
95
+ command-line tools. The published Node.js CLI remains cross-platform.
96
+
97
+ ### Optional desktop GUI
98
+
99
+ The CLI works on its own. Public GUI downloads are temporarily unavailable
100
+ during a privacy cleanup; a clean replacement has not yet been built. On an
101
+ Apple Silicon Mac (macOS 13.5 or newer), open an existing installation with:
102
+
103
+ ```bash
104
+ runlist desktop
105
+ ```
106
+
107
+ The installer downloads the GUI from Runlist's public GitHub Releases, checks
108
+ its SHA-256 digest, developer signature and Apple approval, then installs it
109
+ without opening it. The app bundles its runtime and reads local files through
110
+ private pipes, with no listening server. Choose your checkout folder in the app.
111
+ No checkout configuration is loaded by these CLI commands.
112
+
113
+ The GUI is versioned separately from the CLI. There is currently no public Mac
114
+ installer available to `runlist desktop install`.
115
+ Windows, Linux and Intel Mac GUI downloads are not yet available through this
116
+ command. An existing app is kept as-is. To replace it using a downloaded signed
117
+ DMG, quit Runlist and run:
118
+
119
+ ```bash
120
+ runlist desktop install --from /path/to/Runlist.dmg
121
+ ```
122
+
123
+ Replacement keeps the previous app as a rollback copy. Add `--dry-run` to preview
124
+ an install or launch without network access, file changes or opening the app.
125
+ Use `runlist desktop --app /path/to/application` for a custom installation path.
126
+
127
+ ### Agent host setup
128
+
129
+ The CLI alone gives an agent no orientation and no session identity. Install the
130
+ integration for whichever host you run:
131
+
132
+ ```bash
133
+ runlist install # what's installed for each host
134
+ runlist install claude # Claude Code plugin (marketplace + plugin)
135
+ runlist install codex # Codex skill and hooks (personal marketplace)
136
+ runlist install opencode # OpenCode plugin (one auto-discovered file)
137
+ runlist doctor --session # what identity runlist sees here, and from where
138
+ ```
139
+
140
+ The integrations are one-time and global. Codex exports `CODEX_THREAD_ID` to
141
+ every tool shell, so its identity works without the plugin; the plugin adds a
142
+ workflow skill, session orientation, and the tool guard.
143
+
144
+ ### Codex Plugin
145
+
146
+ `runlist install codex` copies the plugin included in the npm package into the
147
+ personal Codex marketplace and runs `codex plugin add runlist-codex@personal`.
148
+ Codex asks you to review and trust plugin hooks separately. Start a new thread
149
+ after installation so the skill and SessionStart primer load. The hooks use
150
+ the globally installed `runlist` CLI; a missing CLI produces one install hint
151
+ and otherwise leaves tool calls alone. `CODEX_THREAD_ID` stays the ownership
152
+ source. The CLI refuses to overwrite a plugin directory it did not generate.
153
+
154
+ Direct prompt reads warn by default in Codex and Claude. A repository can set
155
+ `export const guard = { promptReads: 'deny' };` to block reads of existing
156
+ pending prompts; `runlist prompts show` remains the read-only inspection verb.
157
+
158
+ ### Claude Code Plugin
159
+
160
+ `runlist install claude` runs the two steps below for you. From inside a session:
161
+
162
+ ```text
163
+ /plugin marketplace add reowens/runlist
164
+ /plugin install runlist@runlist
165
+ ```
166
+
167
+ Existing `dotmd@dotmd` installs can be migrated with `runlist install claude`
168
+ or `runlist update --plugin-only`. The command installs `runlist@runlist` and
169
+ then uninstalls the old plugin, so its hooks do not run twice.
170
+
171
+ The plugin provides SessionStart and SubagentStart orientation, a
172
+ UserPromptSubmit hint that gives the exact `runlist baton` form when you ask for
173
+ a handoff, a PreToolUse guard, the canonical workflow skill, and `/plans`,
174
+ `/docs`, `/prompts`, and `/baton` commands.
175
+
176
+ ### OpenCode Plugin
177
+
178
+ `runlist install opencode` writes one plugin file into OpenCode's global config
179
+ directory, where OpenCode auto-discovers it — no `opencode.json` edit. It
180
+ supplies the two things the CLI cannot get on its own:
181
+
182
+ - **Per-session plan ownership.** OpenCode exports no session id to a tool
183
+ shell. Without the plugin, runlist falls back to `OPENCODE_PID`, which names the
184
+ OpenCode *process* — so every session in one OpenCode instance shares an
185
+ identity and can release the others' in-session plans.
186
+ - **A session-start briefing**, the equivalent of Claude Code's SessionStart
187
+ hook. OpenCode's Claude Code compatibility covers skills and the system
188
+ prompt, not hooks, so nothing else runs `runlist hud`.
189
+ - **Prompt-read guardrails.** Recognized reads are checked before execution so
190
+ the opt-in strict policy can stop them. Default warnings are attached to the
191
+ result because OpenCode's before hook cannot return model context.
192
+
193
+ Restart OpenCode after installing. The generated file is `runlist.js` and is
194
+ version-stamped (`runlist-generated:`). `runlist install opencode` migrates a
195
+ generated `dotmd.js` from older releases; an unmarked file is treated as
196
+ hand-authored and is never overwritten.
197
+
198
+ The plugin requires a global CLI install because its hooks resolve `runlist` (or `dotmd`) from
199
+ `PATH`. A project devDependency is useful for npm scripts but does not put the
200
+ CLI on the hook's `PATH`.
201
+
202
+ Keep the CLI and plugin aligned with:
203
+
204
+ ```bash
205
+ runlist update
206
+ runlist update --check
207
+ runlist update --cli-only
208
+ runlist update --plugin-only
209
+ ```
210
+
211
+ From CLI 0.93.2, Claude plugin updates cover each saved user, project and local
212
+ installation.
213
+ Project/local updates run from the recorded project folder. `update --check`
214
+ shows each scope separately, and an update verifies the fresh installation
215
+ records before reporting success. Missing project paths, unavailable folders
216
+ and managed scopes are reported rather than silently updating another scope.
217
+ The release workflow uses the same scope selection and verifies every entry
218
+ against the released version.
219
+
220
+ Restart Claude Code, or run `/reload-plugins`, after a plugin update.
221
+
222
+ ## Quick Start
223
+
224
+ ```bash
225
+ runlist init # create config, docs/, and the generated index
226
+ runlist new plan auth-refresh # scaffold a typed document
227
+ runlist plans # compact live plan dashboard
228
+ runlist briefing # comprehensive active-work view
229
+ runlist check # validate schema, references, and lifecycle shape
230
+ runlist doctor # preview repairs; add --apply to write
231
+ ```
232
+
233
+ `runlist plans` is the compact orientation view. `runlist briefing` lists live
234
+ plans with next steps and grows with the corpus. `runlist context` is the fuller
235
+ human/LLM briefing, while `runlist agent-context` emits bounded structured JSON for
236
+ agent integrations. Its default response is capped at 16,384 UTF-8 bytes,
237
+ including JSON formatting and the final newline. Each collection reports
238
+ `total`, `shown`, and `truncated`; `budget` reports emitted bytes. Claims, the
239
+ next pending prompt, and the first plan action are retained. If protected
240
+ information cannot fit, the command reports the required budget rather than
241
+ silently dropping it.
242
+
243
+ ```bash
244
+ runlist agent-context --sections plans,prompts,counts --max-bytes 8192
245
+ runlist context --json --compact --sections plans,issues
246
+ ```
247
+
248
+ Available sections are `statusVocabulary`, `counts`, `prompts`, `plans`, and
249
+ `issues`. Section selection is explicit in the response's scope. Passive
250
+ context reads continue to skip custom side effects and expensive Git history.
251
+
252
+ The developing native record format is specified by
253
+ [runlist-record-v1.schema.json](assets/schemas/runlist-record-v1.schema.json).
254
+ It uses flat frontmatter for identity and lifecycle fields, a literal
255
+ `record_data` block containing nested JSON, and native Markdown for narrative
256
+ and anchored plan tasks. The read-only parser in `src/native-record.mjs`
257
+ preserves original source, validates metadata and relationships, and rejects
258
+ ambiguous keys, unsupported versions, incomplete resolution evidence, and
259
+ invalid ruling provenance. Existing CLI writers and migration do not yet use
260
+ this format; ordinary legacy documents and flag logs remain unchanged.
261
+
262
+ The local source-editing core in `src/source-editor.mjs` provides authenticated
263
+ actor attribution, exact revision saves, durable retry/repair receipts, private
264
+ draft recovery, and compensating undo. It preserves frontmatter and lifecycle
265
+ history, respects CLI claims, and reports conflicts with the current source.
266
+ The [source editing contract](assets/contracts/source-editing-v1.md) describes
267
+ the API and trusted host responsibilities. The local browser adapter below
268
+ uses that core; managed record domain writers remain upcoming work.
269
+
270
+ Runlist also has a [macOS desktop application](desktop/README.md) built from this
271
+ source checkout. Install `Runlist.app`, open it normally, and choose a trusted
272
+ checkout. It bundles its runtime and uses private pipes; normal desktop work
273
+ needs no installed Node, browser access link or listening server. CLI 0.92.0 provides the desktop commands below.
274
+ The GUI remains optional:
275
+
276
+ ```bash
277
+ runlist desktop install # requires an available public installer
278
+ runlist desktop # open the installed GUI
279
+ runlist desktop install --from /path/to/Runlist.dmg # install a local signed DMG
280
+ ```
281
+
282
+ The installer currently supports Apple Silicon Macs. It verifies the published
283
+ download checksum, Runlist developer signature and Apple approval, and installs
284
+ without opening the app. An existing app is kept unless `--from` supplies a
285
+ replacement; replacement keeps a rollback copy. `--dry-run` uses no network and
286
+ changes no files. Public Mac downloads have been withdrawn during a privacy
287
+ cleanup; a clean replacement is pending. `--from` still works with a local
288
+ approved installer. These commands ship
289
+ in [CLI 0.92.0](https://github.com/reowens/runlist/releases/tag/v0.92.0) and can also
290
+ be used from this checkout as `node bin/runlist.mjs desktop …`. The GUI remains
291
+ separately versioned at **0.94.0-rc.1**; npm installation does not download it.
292
+
293
+ The optional browser document app is available from this source checkout (unreleased):
294
+
295
+ ```bash
296
+ node bin/runlist.mjs app docs/plans/my-plan.md --port 5173
297
+ ```
298
+
299
+ Open the local access link printed in the terminal. The app homes existing
300
+ hubs, plans and documents in the selected checkout, edits the document inline, exposes source, reviews a
301
+ diff before saving, keeps private recovery drafts, reports intervening edits,
302
+ and undoes a save through a new revision-checked operation. Related legacy
303
+ flags retain their original observation beside their current location; missing
304
+ observed revisions are explicit. Browser sessions identify as the local human
305
+ and respect agent claims. Save writes the Markdown file; Git commit and sharing
306
+ remain separate. Stop the server with Ctrl+C. CLI 0.92.0 also includes this explicitly launched browser-app command;
307
+ use `runlist app` from an installed CLI.
308
+
309
+ Click headings, paragraphs, list items, quotes, or code to edit them in place.
310
+ Enter creates the next block; an empty list item exits the list. Type `/` in an
311
+ empty paragraph or use the `+` beside a block to choose a heading, list, task,
312
+ quote, code block, or divider. Task checkboxes are interactive. Select text for
313
+ bold, italic, code, strikethrough, and links; Command/Ctrl+B and +I also work.
314
+ Command/Ctrl+Z undoes draft edits, while **Undo save** reverses a published save.
315
+ Private drafts save automatically; **Review changes → Save changes** publishes
316
+ them to Markdown. Managed lifecycle history stays read only. Tables and complex
317
+ blocks offer a local Markdown editor; **Edit Markdown** opens the full body as a
318
+ fallback. Untouched blocks, comments, and line endings retain their source.
319
+
320
+ The sidebar provides **All documents**, **Hubs**, **Plans**, **Docs**, **Flags**, **Decisions**, **Changes**, pins, recents,
321
+ and templates. Selecting a category opens its searchable results in the main
322
+ area, with type, status, location, sort and archive controls. Opened documents
323
+ have a **← Library** action; returning to the library retains unsaved drafts.
324
+ On narrow screens, **Navigation** opens the sidebar. Search spans the
325
+ whole configured library; only 50 result rows are returned/rendered per page.
326
+ Header metadata is cached and unchanged files are reused on refresh; Refresh
327
+ explicitly picks up external additions, removals, moves and metadata edits.
328
+ Discovery reads headers in 4 KiB chunks, up to 128 KiB when needed, and detaches
329
+ cached metadata from source buffers. Record refreshes process one document at a
330
+ time, retain decision fragments and flag connection paths, and load linked record
331
+ bodies when opened. To measure a read-only workload on your checkout, run
332
+ `node scripts/measure-app-memory.mjs /path/to/checkout`; adding `--expose-gc`
333
+ before the script also measures retained heap after collection.
334
+ Pinned/recent documents remain browser-local and reachable outside the current
335
+ results. Hub members, parent hubs and related documents remain navigable through
336
+ Connections and preview links, including documents on another page. Membership
337
+ uses the CLI's hub/order definition and parent back-pointers, rather than treating
338
+ every citation as a child. Configured non-plan narratives use the same reviewed
339
+ source save; untyped or unsupported formats open read only. Private prompts,
340
+ excluded corpora and generated indexes stay outside the library.
341
+
342
+
343
+ **Changes** reviews saved Markdown against the local Git HEAD, with 100-row
344
+ pages, search, archive inclusion and whole-file selection. Open it from the
345
+ sidebar, quick navigation or **Saved Git changes** in a document review.
346
+ Plans, hubs and other documents use the same configured-root and private-path
347
+ policy. Additions, modifications, deletions and renames include both safe rename
348
+ paths; partially staged files and ignored local-only files explain why selection
349
+ is blocked. Unrelated staging is counted without exposing unrelated source.
350
+ Refresh retains selection and the diff; navigation preserves unsaved drafts, and
351
+ **Return to draft** resumes the current editor without saving it. Git inspection
352
+ runs on demand with bounded asynchronous output and no optional index locks.
353
+ **Review local commit** opens a separate message and exact Git-content review.
354
+ Open each selected file before **Commit locally** becomes available. The review
355
+ uses the actual Git tree, including ordinary EOL normalization, and authorizes
356
+ both paths of a rename. The commit guard checks the actual commit’s tree, parent,
357
+ message, destination branch, saved files, effective Git configuration/attributes
358
+ and owned final-index generation before ref publication. Unrelated staging stays
359
+ staged. Selected partial staging and ignored/private files are never replaced or
360
+ force-added. Runlist initiates no fetch, push or credential operation.
361
+
362
+ The writable gate supports Apple Silicon macOS with Git 2.54.0 or 2.55.0 and Linux ARM64 with
363
+ Git 2.47.3. Linux was qualified through terminal fixtures on the dev Pi:
364
+ Debian 13.5, glibc 2.41 and the pinned Node 24.21.0 helper runtime; the initial
365
+ baseline passed 19 commit/recovery and 20 native-helper checks with external networking
366
+ disabled. Linux x64, other Linux Git versions and Windows remain unqualified.
367
+ See Linux commit evidence.
368
+ Both gates require an existing named branch, SHA-1 objects and a plain v2/v3
369
+ index (at most 2 MiB; only the ordinary TREE extension).
370
+ One-shot clean filters with a regular executable and literal arguments are supported,
371
+ including a standalone `%f` filename argument and quoted paths. Process filters,
372
+ shell expressions/builtins/globbing, working-tree encoding, sparse/split/fsmonitor/extended
373
+ indexes, unsupported signing profiles and other platforms/versions still require Git.
374
+ These settings are refused before execution, never bypassed. Opening Changes or
375
+ its saved-file diff disables executable filters: filtered candidates may be
376
+ unchanged in Git. **Review exact Git content** explicitly applies the configured
377
+ clean filter in two private indexes and displays the resulting canonical blobs.
378
+ Different outputs, partial staging, changed config/attributes/executable/literal
379
+ file arguments or a final tree/index mismatch block the commit. Saved Markdown
380
+ remains unchanged; unrelated staging is preserved. Git retains required/optional
381
+ filter-failure behavior. Executables and referenced file arguments have a 16 MiB
382
+ inspection bound; the existing 1 MiB combined review bound still applies.
383
+ Filters are trusted checkout code with their own side effects and indirect
384
+ dependencies; Runlist does not sandbox or undo those effects. A filtered private
385
+ Git step that exceeds its time/output limits stops its owned process group and
386
+ retains failure evidence. The read-only view remains independent of the write gate.
387
+
388
+ Configured commit hooks run at their original paths with Git's arguments, stdin,
389
+ working directory and index/editor context, including relative or absolute
390
+ `core.hooksPath`. Preview and private index preparation never execute them.
391
+ The review lists the enabled hooks, signing format and clean-filter names. Changed hook generations,
392
+ hook rejection or unreviewed tree/message/index changes block publication.
393
+ Post-commit failures retain the known commit; they never trigger another commit.
394
+ Hooks are trusted checkout code and can perform their own side effects; Runlist
395
+ preserves those effects and retained evidence rather than claiming to sandbox or
396
+ undo them. Each hook has a 10-second bound within the existing job limits.
397
+
398
+ Required signing supports local Ed25519 OpenSSH private-key files through
399
+ `ssh-keygen`, and OpenPGP through GnuPG with an explicit full signing fingerprint
400
+ and a ready agent. SSH agents/hardware, X.509, custom signer commands and
401
+ conflicting OpenPGP program aliases remain unqualified. SSH askpass is disabled;
402
+ GnuPG uses batch/no-tty, error-only pinentry and no agent autostart or automatic
403
+ key retrieval. Encrypted SSH keys and unavailable GPG agents fail without an
404
+ unsigned fallback. The guard verifies the actual signature against the selected
405
+ key before ref publication, alongside the reviewed content and staging checks.
406
+ Private keys/passphrases are never stored in receipts. See
407
+ hook and signing evidence.
408
+
409
+ Commit jobs return promptly and survive renderer/helper disconnect. **Recovery**
410
+ finds private human/checkout-bound disk receipts even without browser storage.
411
+ **Inspect outcome** checks retained evidence; **Recover owned staging** restores
412
+ only a proven owned generation after its process group has stopped. Foreign or
413
+ unverified locks/indexes are preserved. An uncertain publication is never retried;
414
+ an explicit note can acknowledge fresh inspected ref/index evidence without
415
+ replaying or undoing a commit. Closing a review preserves its receipt and message
416
+ draft. Bounds include a 1 MiB combined review, 8 KiB message, 30-minute review
417
+ expiry, bounded Git command/job deadlines and 500 retained operations. Private
418
+ receipt storage must be ignored, untracked and free of symlinks.
419
+
420
+ This source work has not replaced the installed desktop app. Native visual/focus
421
+ checks, broader Git compatibility and platform qualification remain separate;
422
+ Apple status checks remain stopped.
423
+
424
+ **Flags** is the triage queue, with search, severity/status filters, source and
425
+ hub filters, and 50-row pages. Open a flag for its original observation, current
426
+ evidence and append-only history. Accept, reject or resolve with a reason, review,
427
+ then confirm. Accept keeps the flag open; reject closes it; resolve records that
428
+ it was addressed.
429
+
430
+ **Decisions** brings existing plan sections and registers into one queue. Linked
431
+ register/plan records collapse using the CLI parser's scope rules. Each record
432
+ shows its source, connected work, blocking items, question and recorded outcomes.
433
+ Review a hold, ruling, closure or reopening before saving. A ruling requires a
434
+ selected answer and a reason; the app records the authenticated human and date.
435
+ Earlier outcomes and original text remain in the source. Reviewed requests are
436
+ retained in browser storage so a reload or lost acknowledgement can retry the
437
+ same operation without duplicating it. External edits and claims are checked
438
+ again on save. Native v1 records also support reviewed actions. Flag accept,
439
+ reject, manual resolution and reopening retain original evidence and history.
440
+ Native decision rulings select an existing option ID; changed rulings explicitly
441
+ supersede their predecessor, and reopening or holding a ruled decision records
442
+ a withdrawal. Human authority is required to record or withdraw rulings.
443
+ Duplicate native IDs and invalid records remain read only in the queue.
444
+
445
+ **New flag** and **New decision** are available in their queues, the New dialog
446
+ and quick actions in current source. A flag asks for a finding, severity and
447
+ context; it starts open and unreviewed. A decision asks for a question and two to
448
+ twelve described alternatives, with optional benefits, costs, risks and follow-up.
449
+ It starts open, without a ruling. Review the canonical fields and exact Markdown,
450
+ then explicitly confirm creation. The authenticated local human owns the creation
451
+ event. Retained operation IDs, exclusive writes and Recovery protect against
452
+ duplicate retries, conflicting files and interrupted publication.
453
+
454
+ The first record also reviews `runlist.records.json`, containing schema 1, a
455
+ stable `repositoryId`, a root under the configured document roots and
456
+ `shared: false`. The default root is `<catch-all document root>/records`; each
457
+ record lives in its `flags/` or `decisions/` folder. A single existing native
458
+ repository identity is reused; multiple identities require explicit selection.
459
+ Alternatively, set `export const records = { schema: 1, repositoryId:
460
+ 'repo:<UUID-v4>', root: 'docs/records', shared: false }` in `runlist.config.mjs`.
461
+ If both settings sources exist, they must agree. `shared: true` requires a working
462
+ Git checkout and a trackable destination; ignored files produce an error without
463
+ changing ignore rules or force-adding anything. To share the identity across
464
+ clones, include its configuration in your own Git commit; the GUI's managed-doc
465
+ selection does not include the root-level JSON file. Existing records and custom
466
+ configuration source are preserved. This feature is source-only and has not
467
+ replaced the installed desktop app. See the
468
+ creation work item.
469
+
470
+ The companion CLI uses the same native action preparation and editing core:
471
+
472
+ ```bash
473
+ node bin/runlist.mjs record docs/flags/finding.md resolve --note "Manually verified the fix"
474
+ node bin/runlist.mjs record docs/decisions/choice.md ruled --option option:<uuid> --note "Fits the work"
475
+ ```
476
+
477
+ Add `--dry-run` to inspect the prepared source, `--expected-revision sha256:<hash>`
478
+ to check an earlier read, or `--json` for a durable receipt. Legacy migration,
479
+ automated resolution proofs and agent recommendation editing
480
+ remain separate work.
481
+
482
+ **Change status** opens a lifecycle review for configured documents and plans.
483
+ The application uses the CLI engine for status validation, filing/archive moves,
484
+ reference repairs, history and index updates. The review checks source, claims,
485
+ configuration and destination again before publishing. Save or discard drafts
486
+ first. Claimed sources and native plan lifecycle operations are unavailable;
487
+ native flags and decisions use their domain actions instead. Moves retain
488
+ browser pins and heading bookmarks. Lost acknowledgements can be inspected and
489
+ retried through the retained operation ID. An interrupted runner stays uncertain
490
+ until inspected; acknowledging its outcome records that uncertainty without
491
+ replaying the operation. Retained CLI transactions must be repaired first.
492
+
493
+ **Semantic · gmax** is an optional search mode in ⌘/Ctrl+K and the library.
494
+ Type a natural-language query, then press **Search**; semantic queries do not run
495
+ on each keystroke. Results use relevance order over plans, hubs and other configured
496
+ Markdown roots. Section links are offered only when the indexed byte hash matches
497
+ the current file; changed sources open at the document. Library results are bounded
498
+ **top matches**, with no claim of full-corpus totals or pagination.
499
+
500
+ Runlist does not depend on, bundle or install grepmax, copy its index, start its
501
+ services, refresh its index, download/load models, or fall back to cloud search.
502
+ It requires an external gmax provider supporting `mcp --existing-index-only` and
503
+ a compatible already-running daemon with a warm embedding worker. The last
504
+ authorized check on October 7 at 21:36 UTC saw installed gmax 0.26.65 and a ready daemon,
505
+ but the installed document bridge and required daemon capability were absent.
506
+ Runlist's guarded probe returned `tool_unavailable`; the source bridge had
507
+ previously returned `unsupported_daemon` against 0.26.59. A ready ping alone
508
+ does not establish working semantic retrieval or watcher health.
509
+ Authorized steps 1–4 of the
510
+ compatibility plan
511
+ restore and qualify the bridge in gmax 0.26.66 source and an extracted npm
512
+ candidate. The first slice uses warm-only dense retrieval, with no hybrid/FTS,
513
+ ColBERT inference or reranking. Package/private-helper fixtures pass on Node
514
+ 22.23.1 and 26.8.1; checkout dependencies were reused, not freshly installed.
515
+ This candidate is not deployed. Installation, matching-daemon negotiation and
516
+ live relevance/runtime-memory checks remain separate.
517
+ The release audit's source items 1–6 are now fixed: oversized-worker retirement
518
+ without replacement, native-read lifetime, required generations, idle MLX
519
+ readiness, bounded coverage/freshness metadata and the ARM64 Git write gate.
520
+ Rebuilt provider/private-helper fixtures pass on Node 22 and bundled Node 24.
521
+ Fresh isolated consumers now pass on Node 22.12.0 and 24.21.0 against the distinct
522
+ local gmax `0.26.68-runlist.1` candidate, with lifecycle scripts disabled and no
523
+ checkout dependency links. An unsigned Runlist `0.91.0-rc.1` Mac ARM64 candidate
524
+ contains that historical source snapshot. Separate optional provider qualification
525
+ is documented in [provider qualification](desktop/PROVIDER-QUALIFICATION.md); it
526
+ requires an exact accessible artifact URL/hash when explicitly invoked. Normal
527
+ CLI publication and desktop builds do not require that provider job. These results
528
+ do not establish deployment, live retrieval, watcher recovery or native-window
529
+ acceptance.
530
+ Ordinary text/content search works without gmax. Primary local stores are supported
531
+ by this first contract; external/secondary stores remain unavailable in Semantic mode.
532
+
533
+ **Settings → Semantic search** detects an external installation or lets you save
534
+ absolute paths to its Node executable and `grepmax/dist/bin.js`. These tool settings
535
+ stay in the user's Runlist configuration directory, outside the checkout; a changed
536
+ saved installation must be selected again. No queries/snippets are saved by Runlist,
537
+ and this gmax mode suppresses query logging without changing global gmax settings.
538
+ See the integration plan for
539
+ qualification limits. Older frozen packages omitted these additions; the delivered
540
+ 0.92.0-rc.1 GUI includes the experimental semantic controls. An external provider
541
+ and live-search qualification remain separate.
542
+
543
+ Terminal checks on the real platform checkout covered 2,757 library documents.
544
+ The source engine harness and transient bridge sampled at 97.5 MiB and 81.7 MiB
545
+ peak RSS respectively; requests safely reported the absent daemon in 0.7–0.9 seconds.
546
+ These measure the unavailable path, not successful semantic queries or whole-app
547
+ memory. See [qualification evidence](desktop/VALIDATION.md#optional-gmax-real-checkout-probes--2026-10-07).
548
+ The absent-daemon and memory-pressure findings above are historical. The owner
549
+ now reports a gmax watcher problem requiring a reboot; its cause and post-reboot
550
+ recovery are unverified. Live qualification remains parked for watcher recovery
551
+ and the external contract gap. Preserve the host-safety hold; neither service
552
+ startup nor model headroom has been qualified. See the
553
+ watcher/search status.
554
+ Ordinary text/content search remains available; gmax is optional. Installing
555
+ current Runlist alone does not provide the missing external gmax contract.
556
+
557
+ **Settings** in the sidebar saves browser defaults for appearance, document order,
558
+ archive visibility and the records view. It links to the editable templates and
559
+ shows loaded document roots, exclusions, status rules and where changes live.
560
+ Repository configuration remains editable in its source or through the CLI;
561
+ this panel displays its effective rules.
562
+
563
+ **Appearance** in the header offers Light, Dark, and System. The browser remembers
564
+ your choice across reloads and shares it with other tabs at the same local app
565
+ address. System follows your OS appearance, including live changes. The theme
566
+ covers the library, inline editor, source, diffs, section tools, and templates.
567
+
568
+ **Sections** provides a searchable heading outline, heading bookmarks, and section
569
+ insertion. Command/Ctrl+Shift+J focuses section search; Alt+Page Up/Down moves
570
+ between headings. Stars save bookmarks for this checkout and file in the current
571
+ browser. Inline heading renames update their bookmarks; removed or unmatched
572
+ headings stay visible as unavailable bookmarks.
573
+
574
+ **Templates** in the sidebar opens the doc, plan, and prompt scaffolds with
575
+ Markdown editing, an example preview, and a diff before saving. Template drafts
576
+ stay in browser storage. Saves use revision checks and write the repository's
577
+ `runlist.templates.json`; ordinary `runlist new` commands consume these overrides.
578
+ Existing documents are unaffected. Keep `{{title}}`, `{{body}}`, and the managed
579
+ `{{status}}`/`{{date}}` metadata placeholders; `{{version}}` is also available.
580
+ Authored complete bodies and explicit plan variants retain their existing CLI
581
+ behavior. JavaScript templates from `runlist.config.mjs` can be inspected without
582
+ executing them. Built-in types can receive a Markdown override; custom JavaScript
583
+ types remain editable in that config file. The template file can be committed
584
+ with Git; bookmarks and draft recovery remain local.
585
+
586
+ The renderer covers headings, paragraphs, lists/tasks, tables, quotes, fenced
587
+ code, and safe links. Authored HTML is displayed as text; unsupported syntax
588
+ remains available in Source. The optional `test/browser-app-smoke.mjs` exercises
589
+ real browser save/CLI readback, undo, reload recovery, conflict review, lost
590
+ acknowledgements, and narrow-screen layouts with Playwright supplied externally.
591
+
592
+ ### Plan stages
593
+
594
+ Stages describe when a plan should ship. Status describes its progress. Each
595
+ repository owns its ordered vocabulary in `taxonomy.milestones`; existing string
596
+ lists remain valid, and entries can include a plain-English meaning:
597
+
598
+ ```js
599
+ export const taxonomy = {
600
+ milestones: [
601
+ { word: 'beta', meaning: 'First customers are using it while it settles.' },
602
+ { word: 'ga', meaning: 'Available to every customer who buys it.' },
603
+ { word: 'later', meaning: 'Parked with no stage committed.' },
604
+ ],
605
+ };
606
+ ```
607
+
608
+ A plan selects a stage with `ships: beta`. Missing or blank `ships:` is **Unset**,
609
+ separate from an explicit `later`. Runlist never assigns a stage from status.
610
+ `check` reports stage coverage and rejects malformed or unknown configured values.
611
+
612
+ ```bash
613
+ runlist plans --stage beta
614
+ runlist plans --stage @unset
615
+ runlist plans --group-by stage
616
+ ```
617
+
618
+ Use `word:<name>` for a literal stage named `@unset` or beginning with `word:`.
619
+ In the GUI, Library → Plans can filter/group by Stage and save that view.
620
+ A plan's Stage dropdown changes the draft; review and save publishes it through
621
+ the existing revision, ownership and recovery guards. Other document metadata
622
+ stays protected. Semantic results retain relevance order when filtered by stage.
623
+ Plan stages are available in CLI 0.92.0 and GUI 0.92.0-rc.1.
624
+
625
+ ## Core Workflow
626
+
627
+ ```bash
628
+ runlist plans
629
+ runlist use docs/plans/auth-refresh.md
630
+ runlist set awaiting docs/plans/auth-refresh.md --note "Need API owner decision"
631
+ runlist set active docs/plans/auth-refresh.md --note "Decision received"
632
+ runlist archive docs/plans/auth-refresh.md --note "Shipped and verified"
633
+ ```
634
+
635
+ Use `runlist set <status> [<file>]` for lifecycle changes rather than editing a
636
+ `status:` line. It validates the status for the document type, updates history,
637
+ runs lifecycle hooks, repairs references after moves, and synchronizes the
638
+ index.
639
+
640
+ For unfinished session work, save the handoff and release the owned plan in one
641
+ operation:
642
+
643
+ ```bash
644
+ runlist baton @/tmp/resume.md
645
+ ```
646
+
647
+ Baton refuses when a handoff for the same work is already pending, so one piece
648
+ of work never has two resume prompts. Inspect the pending handoff with
649
+ `runlist prompts show <slug>`. Keep it if current; if stale, pass `--replace`
650
+ with a new draft. Baton archives the previous text and refreshes the pending
651
+ prompt in the same operation as any plan release.
652
+
653
+ Repositories with a commit wrapper can export `batonCommitCommand(message, paths)`
654
+ from `runlist.config.mjs` and return an argv array such as
655
+ `['just', 'commit', message, ...paths]`. Baton quotes the printed command and
656
+ excludes session prompts from `paths`.
657
+
658
+ Saved prompts are local session state. Consume them with `runlist use`; inspect
659
+ without consuming via `runlist prompts show`. Consuming a baton prompt also claims
660
+ its plan; `runlist use --no-claim` reads and archives it without starting the plan.
661
+
662
+ New plans are created `planned`; `runlist use` starts one, and
663
+ `runlist new plan <name> --status <status>` sets a different starting status.
664
+
665
+ ## Document Format
666
+
667
+ ```markdown
668
+ ---
669
+ type: plan
670
+ status: active
671
+ updated: 2026-07-13
672
+ modules:
673
+ - auth
674
+ surfaces:
675
+ - backend
676
+ current_state: Token validation is complete.
677
+ next_step: Wire refresh rotation into middleware.
678
+ related_docs:
679
+ - ./auth-design.md
680
+ ---
681
+
682
+ # Auth Refresh
683
+
684
+ - [x] Validate tokens
685
+ - [ ] Rotate refresh tokens
686
+ ```
687
+
688
+ `status` is the only universally required field. A `type` enables type-specific
689
+ statuses, validation, templates, and briefing behavior. Explicit frontmatter
690
+ wins, but runlist can also derive titles, summaries, state, next steps, checklist
691
+ progress, and Markdown links from the body.
692
+
693
+ Use plural `modules:` and `surfaces:` arrays. The old singular keys remain
694
+ readable for compatibility and can be migrated with `runlist lint --fix`.
695
+
696
+ ### Built-In Types
697
+
698
+ | Type | Purpose | Default statuses |
699
+ |---|---|---|
700
+ | `plan` | Executable work | `in-session`, `active`, `planned`, `blocked`, `partial`, `paused`, `awaiting`, `queued-after`, `archived` |
701
+ | `doc` | Specs, ADRs, audits, and reference material | `draft`, `active`, `review`, `reference`, `deprecated`, `archived` |
702
+ | `prompt` | Saved future-session instructions | `pending`, `archived` |
703
+
704
+ Status definitions can be customized per type. Rich status objects co-locate
705
+ display, staleness, validation, terminal, and archive behavior in one place.
706
+
707
+ ## Hubs, Ordered Plans, And Roadmaps
708
+
709
+ A **hub** is a Markdown document that organizes related plans and supporting
710
+ docs. Older documentation and existing filenames also call these documents
711
+ **runlists**. Hub and runlist describe the same organizing document; they are
712
+ not two successive levels. **Runlist** is also the product name.
713
+
714
+ A hub can organize an area through prose and links (**coordination hub**) or
715
+ use a `runlist:` array for an explicit plan sequence (**ordered hub**, also
716
+ called a sprint runlist). Coordination hubs can also rank plans through linked
717
+ body rows or lists. A **roadmap** is an optional hub that collects other hubs and
718
+ rolls up their progress. These are hub shapes, not three containers every
719
+ project must create. A simple arrangement is:
720
+
721
+ ```text
722
+ Repository
723
+ └── Roadmap hub (optional, collects hubs)
724
+ └── Area or ordered hub
725
+ ├── Supporting docs
726
+ └── Plans (optionally ordered)
727
+ └── Tasks
728
+ ```
729
+
730
+ These are document relationships, not a required folder layout. Plans and
731
+ supporting docs can also stand alone. A plan's **stage** describes when
732
+ it should ship, and its **status** describes progress; neither adds a document
733
+ level. Hubs currently use `type: plan` with hub metadata, while supporting specs,
734
+ ADRs and reference material use `type: doc` or a configured document type.
735
+
736
+ Existing commands, fields, filenames and CLI labels retain `runlist` terminology.
737
+ The `runlist:` array declares the ordered plans **on the hub itself**. It does
738
+ not create a separate runlist document inside the hub. Scaffold an ordered hub
739
+ and its child plans together:
740
+
741
+ ```bash
742
+ runlist new hub auth-revamp --runlist extract,rewrite,cleanup
743
+ runlist runlist auth-revamp
744
+ runlist runlist next auth-revamp
745
+ ```
746
+
747
+ Mutate the structure through the CLI so the array, child `parent_plan` refs, and
748
+ body order list remain synchronized:
749
+
750
+ ```bash
751
+ runlist runlist add auth-revamp docs/plans/existing-plan.md
752
+ runlist runlist add auth-revamp follow-up
753
+ runlist runlist reorder auth-revamp follow-up --before cleanup
754
+ runlist runlist remove auth-revamp extract --clear-parent
755
+ ```
756
+
757
+ Archived children count as complete. Parked children (`blocked`, `partial`,
758
+ `paused`, `awaiting`, and `queued-after`) are skipped when choosing the next
759
+ pickup but do not count as done.
760
+
761
+ For a prose-first area map, create a coordination hub:
762
+
763
+ ```bash
764
+ runlist new hub platform-work
765
+ runlist runlists
766
+ ```
767
+
768
+ `runlist new hub` defaults to a coordination hub; add `--runlist a,b,c` for an
769
+ ordered hub or `--roadmap` for a roadmap hub. The existing `new plan` forms with
770
+ `--coordination`, `--runlist` or `--roadmap` create the same respective shapes.
771
+
772
+ For progress across several hubs, create an optional roadmap hub:
773
+
774
+ ```bash
775
+ runlist new hub platform-roadmap --roadmap
776
+ runlist roadmap platform-roadmap
777
+ runlist roadmap platform-roadmap next
778
+ ```
779
+
780
+ Roadmaps roll up progress recursively and choose the first startable plan across
781
+ their child hubs. They can also link plans directly. Hubs, including roadmaps,
782
+ are held out of actionable plan counts so dashboards do not double-count their
783
+ children.
784
+
785
+ ### Product Yardstick
786
+
787
+ Optional yardstick support is included from CLI 0.94.0. The separately installed
788
+ GUI 0.92.0-rc.1 retains its earlier engine; yardstick controls in the GUI are
789
+ follow-up work. From a source checkout, use `node bin/runlist.mjs` in place of
790
+ `runlist` below.
791
+
792
+ Write your description of the finished product in an ordinary Markdown document
793
+ and opt in from repository config:
794
+
795
+ ```js
796
+ export const yardstick = 'docs/product-yardstick.md';
797
+ ```
798
+
799
+ Runlist reads that document's body and shows it beside a plan's literal
800
+ `delivers:` text on pickup cards. It records your judgment; it does not generate
801
+ the goal, score plans or decide which ones belong. Unset assessments are
802
+ **not yet reviewed**. The goal file must stay inside the repository; an unset
803
+ or false config disables the feature.
804
+
805
+ ```bash
806
+ runlist yardstick show
807
+ runlist yardstick show docs/plans/navigation.md --json
808
+ runlist yardstick mark docs/plans/navigation.md serves
809
+ runlist yardstick fold docs/plans/old-navigation.md --into docs/plans/navigation.md --reason "Combined into navigation work." --dry-run
810
+ runlist yardstick close docs/plans/unused-navigation.md --reason "No longer needed." --dry-run
811
+ runlist yardstick clear docs/plans/navigation.md
812
+ ```
813
+
814
+ **Close and fold actually archive the plan**, retaining the owner reason and
815
+ replacement link when folded. Removing `--dry-run` applies the displayed action.
816
+ Writes respect plan ownership, and archive/reference updates remain one
817
+ transaction. Replacement links are repaired when their targets move, including
818
+ with custom reference-field lists. Clearing an assessment does not reopen or
819
+ unarchive a plan. Every write supports `--dry-run` and `--json`; `--no-index`
820
+ leaves generated-index refresh to the caller.
821
+
822
+ Assessments use flat `yardstick_disposition`, `yardstick_into`,
823
+ `yardstick_reason` and `yardstick_revision` fields in plan frontmatter. After
824
+ the goal body changes, older assessments remain recorded and are labeled
825
+ **Reviewed against an earlier goal**. Goal frontmatter date edits and line-ending
826
+ changes alone do not require reassessment. `runlist check` warns about malformed
827
+ assessment fields or closed/folded metadata on live plans, and never closes
828
+ them automatically. Goal reads and assessments require no semantic provider,
829
+ local model or server. GUI controls are implemented in the source checkout:
830
+ Product goal shows the saved statement, delivery and assessment, with reviewed
831
+ Serves/Clear/Close/Fold actions and retained recovery. Structured plans display
832
+ the comparison with an explanation when assessment changes are unavailable.
833
+ These controls are included in the public desktop package 0.94.0-rc.1;
834
+ updating the CLI alone does not replace an existing app.
835
+
836
+ ### Plan Homes And Filing Checks
837
+
838
+ This policy is available in CLI 0.93.0. From a source checkout, invoke the
839
+ commands below as `node bin/runlist.mjs …`. The separately versioned GUI
840
+ 0.94.0-rc.1 also includes a read-only Filing view. The correction
841
+ for category inheritance from status-less hub indexes is included in CLI
842
+ 0.93.1.
843
+
844
+ Repositories can enable the plan-home policy in `runlist.config.mjs`:
845
+
846
+ ```js
847
+ export const filing = true;
848
+ // Or choose the category heading level (default: ###):
849
+ // export const filing = { categoryDepth: 3 };
850
+ ```
851
+
852
+ A home is a table row in a live hub whose **first cell links to the plan** and
853
+ whose status cell contains a recognized plan status. Explicit managed status
854
+ markers also count. Links in prose, another row's commentary, frontmatter,
855
+ order lists, or tables without statuses are references. A numbered row with
856
+ the plan in its second cell is an execution order, not a filing home.
857
+
858
+ Categories come from `###` headings by default (`categoryDepth` accepts 2–6),
859
+ or from explicit first-cell hub index rows beneath those headings. These index
860
+ rows can categorize a hub without a status column; they do not establish a
861
+ plan home or a home for its children. Categories propagate through nested hub
862
+ indexes. A plan row's own category takes precedence over inherited categories.
863
+ Hub titles do not supply an inferred category, and competing inherited mappings
864
+ stay visible. A child with no own row can inherit a home through its explicit
865
+ `parent_plan:` chain; the report names the filed ancestor and its home rows.
866
+ A child's own row takes precedence. Missing, ambiguous or cyclic parent links
867
+ do not invent a home. Hubs and archived/terminal plans are excluded from the
868
+ executable-plan totals; closed hubs do not provide current homes.
869
+
870
+ ```bash
871
+ runlist check # filing defect counts
872
+ runlist check --verbose # affected plans and hub:line locations
873
+ runlist check --json # filingCoverage, including inherited homes
874
+ runlist coverage # plan homes, categories and locations
875
+ runlist coverage --json # same report under filing
876
+ ```
877
+
878
+ The three findings are **unfiled**, **multiply filed** (multiple rows or
879
+ categories), and **filed under no category**. Findings can overlap. These are
880
+ warnings; Runlist does not choose homes or add/remove rows. An incomplete scan
881
+ is labeled and suppresses absence/uniqueness findings. Path/type-scoped output
882
+ keeps the full hub/ancestor evidence while reporting only selected plans.
883
+ The source checkout also includes a read-only Filing view: open it to scan,
884
+ filter 50-plan pages, and inspect exact hub rows in 20-row evidence pages. Saved
885
+ edits invalidate the report. This view is included in public desktop package 0.94.0-rc.1.
886
+ The policy is off when `filing` is unset, false, or `{ enabled: false }`.
887
+ It can replace a repository's older “any link counts” coverage script once
888
+ that repository enables it and retires its custom check.
889
+
890
+ ## Decisions
891
+
892
+ A decision is an entry in its plan, not a document of its own. Write the record
893
+ (the situation, what exists today, what each answer leaves in place) to a file
894
+ and add it:
895
+
896
+ ```bash
897
+ runlist new decision auth-revamp --question "Which token store?" @record.md
10
898
  ```
11
- npm install -g dotmd-cli
899
+
900
+ It takes the next id (`D1`, `D2`, …) that no decision item in that plan uses,
901
+ lands at the end of the plan's top-level decisions section (created before
902
+ `## Version History` when there is none) with a `Disposition: OPEN.` line, and
903
+ refuses an empty record. `--disposition held` parks it instead.
904
+
905
+ A corpus that indexes its decisions in one register numbers them in one
906
+ sequence. Name the register, and the id follows the highest the register or the
907
+ plan uses, and the register gets the entry's row in the same locked write:
908
+
909
+ ```js
910
+ export const decisions = {
911
+ section: 'Decisions',
912
+ prefix: 'D',
913
+ register: { file: 'docs/plans/register.md', statusLine: 'waiting on you:' },
914
+ };
915
+ ```
916
+
917
+ The register block is the fenced block whose first line carries `statusLine`.
918
+ The row is the question plus `--answers` (what each answer leaves in place),
919
+ which is required when a register is configured.
920
+
921
+ `runlist decisions --json` gives each open or held decision its `question`,
922
+ its document's `docTitle`, and `blocks`: what its record says it blocks or
923
+ gates, then every unticked checklist item and frontmatter blocker that names
924
+ its id, alone or inside a written range (`A2 to A12`). In another document the
925
+ id has to sit beside a link to the decision's document.
926
+
927
+ Record an outcome in an existing legacy decision with the same source operation
928
+ used by the app:
929
+
930
+ ```sh
931
+ runlist decision docs/plans/work.md D1 --disposition held --note "Need evidence"
932
+ runlist decision docs/plans/work.md D1 --disposition ruled --choice "Blue bin" --note "Fits the shelf"
933
+ ```
934
+
935
+ `--dry-run` prints prepared source. `--expected-revision sha256:<hash>` checks a
936
+ previous read; `--json` returns the operation receipt. Human rulings require a
937
+ human CLI context. Agent sessions may record open, held or closed outcomes.
938
+ The source editor retains receipts and checks claims and exact source revisions.
939
+
940
+ ## Flags
941
+
942
+ A flag is something someone found that the person should know about when they
943
+ come back: a plan that contradicts another, a decision open in one place and
944
+ ruled in another, a citation that no longer says what it claims. Any session,
945
+ person or check can add one, and no model is needed:
946
+
947
+ ```bash
948
+ runlist flag add docs/plans/auth.md:42 "says tokens expire in 1h; the spec says 24h" --severity problem
949
+ runlist flags # open flags, problems first, newest first
950
+ runlist flag accept F3 --note "real, owner agrees"
951
+ runlist flag reject F4 # not a problem; closed
952
+ runlist flag resolve F3 # fixed
953
+ runlist check --flag # the check's errors become flags, attributed to it
954
+ ```
955
+
956
+ Each flag keeps the text of the line it points at, so the list says when that
957
+ line has moved or changed since. A repeat of an open flag on the same place is
958
+ merged. The log is append-only, `.runlist/flags.jsonl` by default
959
+ (`export const flags = { file }` moves it), and triage is recorded as events
960
+ beside the flag, never over it. Every session start shows a count and the top
961
+ open flags.
962
+
963
+ ## Local model
964
+
965
+ Summaries (`--summarize`, `runlist summary`, `runlist diff --summarize`) and
966
+ lint's status inference use one local model server, Ollama by default or any
967
+ OpenAI-compatible server. runlist never starts it or pulls a model on its own:
968
+
969
+ ```bash
970
+ runlist model # server, model, cap, free memory, what is loaded
971
+ runlist model start # ollama serve, one model and one request at a time
972
+ runlist model measure # record each pulled candidate's peak memory and speed here
973
+ runlist model use qwen3.5:9b # name a model; `auto` picks the first measured one under the cap
974
+ runlist model cap 8 # most memory a model may take; `auto` is a quarter of the machine
975
+ runlist model stop # unload it now
976
+ ```
977
+
978
+ The model unloads after 5 idle minutes. Before it loads, the memory free right
979
+ now must hold it plus 1.5 GB with memory pressure normal, or the command goes
980
+ on without it. On an 8 GB machine the cap is 2 GB and model features stay off;
981
+ point `RUNLIST_MODEL_ENDPOINT` at a server on a bigger machine instead. Settings
982
+ are per machine in `~/.runlist/model.json`.
983
+
984
+ `runlist model status --json` leads with a one-line reading for dashboards,
985
+ `running`, `name` (the model loaded now, else the one runlist would load) and
986
+ `memoryMb` (what it holds, null when nothing is loaded), followed by the full
987
+ detail.
988
+
989
+ ## One document's card
990
+
991
+ ```bash
992
+ runlist show docs/plans/shelf.md # title, status, next step, blockers, checklist, related, links
993
+ runlist show shelf bins --json # [{ path, title, status, nextStep, blockers, checklist,
994
+ # related: [{ field, path, title, status }], links: [...] }]
995
+ ```
996
+
997
+ Read-only: nothing is claimed. `related` is what the frontmatter names
998
+ (`related_plans`, `related_docs`, `supports_plans`, `parent_plan`, `runlist` and
999
+ the configured reference fields), each with its title and status; `links` is
1000
+ every other document the body links to.
1001
+
1002
+ ## Failed commands
1003
+
1004
+ Every runlist command that fails, by an error or a non-zero exit, appends one
1005
+ line to `~/.claude/logs/runlist-errors.log` (`RUNLIST_ERROR_LOG_DIR` moves it)
1006
+ with the time, the command with secrets redacted, and the error's one-line
1007
+ message. It rotates at 5 MB, a new runlist version, or 30 days of active
1008
+ history, retaining up to eight numbered backups for 30 days. Readers include
1009
+ the retained backups. Dry runs and the session-start `hud` are never logged.
1010
+
1011
+ ```bash
1012
+ runlist errors # the newest 20 failures, newest first
1013
+ runlist errors --limit 50 # the newest N
1014
+ runlist errors --json # [{ at, command, message, repo, exit }]
1015
+ runlist errors --by-family --json # validation, unknown-command, conflicts, exceptions
1016
+ ```
1017
+
1018
+ Validation findings remain non-zero results and remain in the raw chronological
1019
+ view. Grouping distinguishes those findings from command errors and unexpected
1020
+ exceptions. Failed `xref --check` entries include the first finding's file,
1021
+ line, and message.
1022
+
1023
+ The repository invocation journal remains opt-in through
1024
+ `export const journal = true;` in config or `RUNLIST_JOURNAL=1`. It uses the same retention policy.
1025
+ Top-level and per-command help calls record their topic and outcome without
1026
+ authored arguments. Use `runlist journal --help-topics --json` to see topic,
1027
+ session, version, and retained invocation counts. These denominators cover the
1028
+ retained opt-in window; passive context, HUD, dry runs, disabled journaling,
1029
+ and pruned history are excluded. They are not machine-wide usage rates.
1030
+
1031
+ ## Safety Model
1032
+
1033
+ - Mutation commands support `--dry-run` / `-n`.
1034
+ - Managed writes are confined to configured document roots.
1035
+ - Lifecycle and multi-file moves use atomic, conflict-aware mutation paths.
1036
+ - Session ownership is durable local state, not inferred from telemetry.
1037
+ - Passive orientation commands do not mutate repository state.
1038
+ - Repository paths in machine and human output use stable slash-normalized
1039
+ identities across supported operating systems.
1040
+
1041
+ ## Command Reference
1042
+
1043
+ The CLI is the source of truth for command syntax and options:
1044
+
1045
+ ```bash
1046
+ runlist --help
1047
+ runlist help all
1048
+ runlist help statuses
1049
+ runlist <command> --help
12
1050
  ```
13
1051
 
14
- This name is reserved for that tool. It is not abandoned and not for sale.
1052
+ Shell completion is generated from the same command registry:
1053
+
1054
+ ```bash
1055
+ eval "$(runlist completions bash)"
1056
+ eval "$(runlist completions zsh)"
1057
+ ```
1058
+
1059
+ This README intentionally documents onboarding and concepts instead of
1060
+ duplicating the complete command catalog.
1061
+
1062
+ ## Configuration
1063
+
1064
+ Run `runlist init` to create `runlist.config.mjs` (a legacy `dotmd.config.mjs` is still read). A minimal typed configuration:
1065
+
1066
+ ```js
1067
+ export const root = 'docs';
1068
+ export const archiveDir = 'archived';
1069
+
1070
+ export const types = {
1071
+ plan: {
1072
+ statuses: {
1073
+ 'in-session': { context: 'expanded', staleDays: 1 },
1074
+ active: { context: 'expanded', staleDays: 14 },
1075
+ planned: { context: 'listed', staleDays: 30 },
1076
+ archived: {
1077
+ context: 'counted',
1078
+ archive: true,
1079
+ terminal: true,
1080
+ skipStale: true,
1081
+ skipWarnings: true,
1082
+ },
1083
+ },
1084
+ },
1085
+ };
1086
+ ```
1087
+
1088
+ ### Code references
1089
+
1090
+ Archive and rename repair every reference inside the doc roots. `codeRoots`
1091
+ extends that to source files that cite a document by its repo-relative path in
1092
+ a comment, a docstring or a string literal:
1093
+
1094
+ ```js
1095
+ export const codeRoots = ['packages', 'scripts', 'services'];
1096
+ export const codeRefsUntouched = ['scripts/guards/plan-baseline.json'];
1097
+ ```
1098
+
1099
+ `runlist refs <old> <new>` reports every citation by file and line and writes
1100
+ only on `--fix`; `runlist refs repair` does the same for every archived
1101
+ document still cited at its previous path. Archive and rename print the count
1102
+ afterwards and take `--fix-refs`. Only the full repo-relative path matches,
1103
+ never a bare basename, and only that segment is replaced, so a trailing `§` or
1104
+ `#` anchor survives. A citation inside a string literal waits for `--strings`,
1105
+ a file in `codeRefsUntouched` is never written, and with no `codeRoots` set
1106
+ nothing is scanned.
1107
+
1108
+ Configuration supports multiple roots, custom types and templates, taxonomy,
1109
+ reference fields, presets, rendering, lifecycle hooks, validation hooks, and
1110
+ AI summarization hooks. See [`runlist.config.example.mjs`](runlist.config.example.mjs)
1111
+ for the complete annotated reference.
1112
+
1113
+ ## Hooks
1114
+
1115
+ Functions exported from `runlist.config.mjs` are detected as hooks. They can add
1116
+ validation, customize rendering and summaries, or react to lifecycle events.
1117
+ Hooks receive the resolved config and command context; mutation hooks participate
1118
+ in the command's dry-run and failure contracts.
1119
+
1120
+ ## License
1121
+
1122
+ MIT