runlist 0.0.0 → 0.94.2

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