@xingular/harness 1.2.0 → 1.3.1-unstable.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 (186) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +26 -17
  3. package/builtin/skills/plugin-authoring/SKILL.md +34 -0
  4. package/dist/cli.js +7362 -6239
  5. package/dist/sdk/agents/builtin.js +3 -3
  6. package/dist/sdk/agents/planResearch.d.ts +23 -1
  7. package/dist/sdk/agents/planResearch.js +71 -8
  8. package/dist/sdk/agents/profiles.d.ts +16 -4
  9. package/dist/sdk/agents/profiles.js +75 -12
  10. package/dist/sdk/annotations/bridge.d.ts +2 -0
  11. package/dist/sdk/annotations/bridge.js +4 -0
  12. package/dist/sdk/annotations/capture.d.ts +44 -2
  13. package/dist/sdk/annotations/capture.js +104 -3
  14. package/dist/sdk/annotations/delivery.d.ts +24 -17
  15. package/dist/sdk/annotations/delivery.js +82 -49
  16. package/dist/sdk/annotations/inspect.js +7 -6
  17. package/dist/sdk/annotations/pageScript.js +4 -4
  18. package/dist/sdk/annotations/part.d.ts +0 -2
  19. package/dist/sdk/annotations/part.js +4 -33
  20. package/dist/sdk/annotations/queue.d.ts +2 -2
  21. package/dist/sdk/annotations/queue.js +12 -7
  22. package/dist/sdk/annotations/serverMethods.js +11 -7
  23. package/dist/sdk/annotations/store.d.ts +13 -21
  24. package/dist/sdk/annotations/store.js +47 -37
  25. package/dist/sdk/capabilities/runSnapshot.js +10 -4
  26. package/dist/sdk/commands/list.js +2 -0
  27. package/dist/sdk/commands/registry.d.ts +11 -3
  28. package/dist/sdk/commands/registry.js +3 -2
  29. package/dist/sdk/core/links.d.ts +51 -0
  30. package/dist/sdk/core/links.js +155 -0
  31. package/dist/sdk/core/shell.d.ts +20 -0
  32. package/dist/sdk/core/shell.js +73 -0
  33. package/dist/sdk/core/workspaceBashTool.d.ts +17 -1
  34. package/dist/sdk/core/workspaceBashTool.js +16 -2
  35. package/dist/sdk/core/workspaceSandbox.d.ts +10 -0
  36. package/dist/sdk/core/workspaceSandbox.js +52 -12
  37. package/dist/sdk/core/workspaceWriteOperations.d.ts +11 -0
  38. package/dist/sdk/core/workspaceWriteOperations.js +26 -8
  39. package/dist/sdk/doctor/checks.js +71 -12
  40. package/dist/sdk/harness.d.ts +5 -0
  41. package/dist/sdk/harness.js +11 -6
  42. package/dist/sdk/hub/hub.js +5 -3
  43. package/dist/sdk/index.d.ts +3 -2
  44. package/dist/sdk/index.js +2 -1
  45. package/dist/sdk/plugins/builtin.js +14 -9
  46. package/dist/sdk/plugins/builtinRegistry.d.ts +3 -1
  47. package/dist/sdk/plugins/builtinRegistry.js +9 -3
  48. package/dist/sdk/plugins/discover.d.ts +7 -1
  49. package/dist/sdk/plugins/discover.js +41 -2
  50. package/dist/sdk/plugins/identity.js +1 -1
  51. package/dist/sdk/plugins/install.d.ts +6 -2
  52. package/dist/sdk/plugins/install.js +29 -5
  53. package/dist/sdk/plugins/inventory.js +3 -3
  54. package/dist/sdk/plugins/manifest.d.ts +2 -0
  55. package/dist/sdk/plugins/manifest.js +21 -4
  56. package/dist/sdk/plugins/plugins.d.ts +2 -0
  57. package/dist/sdk/plugins/plugins.js +1 -0
  58. package/dist/sdk/plugins/proposals.d.ts +17 -0
  59. package/dist/sdk/plugins/proposals.js +147 -0
  60. package/dist/sdk/plugins/types.d.ts +1 -1
  61. package/dist/sdk/plugins/types.js +1 -1
  62. package/dist/sdk/prompt/compile.d.ts +13 -4
  63. package/dist/sdk/prompt/compile.js +46 -20
  64. package/dist/sdk/prompt/standard.d.ts +1 -1
  65. package/dist/sdk/prompt/standard.js +1 -1
  66. package/dist/sdk/server/methods.js +14 -2
  67. package/dist/sdk/sessions/compactionCheckpoint.d.ts +3 -3
  68. package/dist/sdk/sessions/compactionCheckpoint.js +12 -12
  69. package/dist/sdk/sessions/continuation.d.ts +4 -2
  70. package/dist/sdk/sessions/continuation.js +7 -6
  71. package/dist/sdk/sessions/contracts.d.ts +22 -4
  72. package/dist/sdk/sessions/contracts.js +12 -7
  73. package/dist/sdk/sessions/planMode.js +2 -2
  74. package/dist/sdk/sessions/runStore.js +3 -1
  75. package/dist/sdk/sessions/runner.js +2 -2
  76. package/dist/sdk/sessions/sessionState.d.ts +13 -0
  77. package/dist/sdk/sessions/sessionState.js +31 -0
  78. package/dist/sdk/sessions/sessions.d.ts +7 -0
  79. package/dist/sdk/sessions/sessions.js +73 -15
  80. package/dist/sdk/sessions/subagentService.d.ts +15 -0
  81. package/dist/sdk/sessions/subagentService.js +195 -55
  82. package/dist/sdk/sessions/subagents.d.ts +10 -1
  83. package/dist/sdk/sessions/subagents.js +4 -0
  84. package/dist/sdk/sessions/workSlice.d.ts +8 -5
  85. package/dist/sdk/sessions/workSlice.js +77 -45
  86. package/dist/sdk/terminal/controller.d.ts +20 -0
  87. package/dist/sdk/terminal/controller.js +43 -18
  88. package/dist/sdk/terminal/opentui/ansi.d.ts +25 -0
  89. package/dist/sdk/terminal/opentui/ansi.js +192 -0
  90. package/dist/sdk/terminal/opentui/model.d.ts +163 -0
  91. package/dist/sdk/terminal/opentui/model.js +482 -0
  92. package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +3 -3
  93. package/dist/sdk/terminal/opentui/subagentsWidget.js +7 -5
  94. package/dist/sdk/terminal/opentui/theme.d.ts +2 -0
  95. package/dist/sdk/terminal/opentui/theme.js +2 -0
  96. package/dist/sdk/terminal/piExtension.js +98 -15
  97. package/dist/sdk/terminal/subagentMonitor.d.ts +17 -4
  98. package/dist/sdk/terminal/subagentMonitor.js +29 -8
  99. package/dist/sdk/terminal/terminals.d.ts +16 -0
  100. package/dist/sdk/terminal/terminals.js +130 -26
  101. package/dist/sdk/terminal/trajectory.d.ts +6 -1
  102. package/dist/sdk/terminal/trajectory.js +8 -0
  103. package/dist/sdk/terminal/tui/annotateCommand.d.ts +5 -1
  104. package/dist/sdk/terminal/tui/annotateCommand.js +21 -7
  105. package/dist/sdk/terminal/tui/annotateSend.d.ts +30 -0
  106. package/dist/sdk/terminal/tui/annotateSend.js +40 -0
  107. package/dist/sdk/terminal/tui/chrome.d.ts +4 -0
  108. package/dist/sdk/terminal/tui/chrome.js +13 -0
  109. package/dist/sdk/terminal/tui/commandPages.d.ts +1 -1
  110. package/dist/sdk/terminal/tui/commandPages.js +16 -11
  111. package/dist/sdk/terminal/tui/commands.d.ts +4 -0
  112. package/dist/sdk/terminal/tui/commands.js +12 -2
  113. package/dist/sdk/terminal/tui/dialogs.js +1 -0
  114. package/dist/sdk/terminal/tui/pageOverlay.d.ts +3 -0
  115. package/dist/sdk/terminal/tui/pageOverlay.js +25 -7
  116. package/dist/sdk/terminal/tui/pages/agentsPage.js +5 -2
  117. package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +70 -16
  118. package/dist/sdk/terminal/tui/pages/annotatePage.js +349 -115
  119. package/dist/sdk/terminal/tui/pages/browserPage.js +5 -4
  120. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +14 -1
  121. package/dist/sdk/terminal/tui/pages/hubPage.js +192 -28
  122. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +14 -1
  123. package/dist/sdk/terminal/tui/pages/pluginsPage.js +295 -25
  124. package/dist/sdk/terminal/tui/pages/subagentsPage.js +8 -5
  125. package/dist/sdk/terminal/tui/pages/usagePage.d.ts +4 -2
  126. package/dist/sdk/terminal/tui/pages/usagePage.js +39 -12
  127. package/dist/sdk/terminal/tui/pluginCommands.d.ts +1 -1
  128. package/dist/sdk/terminal/tui/pluginCommands.js +13 -3
  129. package/dist/sdk/tools/defaultSkills.d.ts +4 -0
  130. package/dist/sdk/tools/defaultSkills.js +20 -0
  131. package/dist/sdk/tools/definitions.d.ts +3 -1
  132. package/dist/sdk/tools/definitions.js +17 -1
  133. package/dist/sdk/tools/dispatch.js +12 -0
  134. package/dist/sdk/tools/harnessTools.js +1 -1
  135. package/dist/sdk/tools/sessionName.d.ts +9 -0
  136. package/dist/sdk/tools/sessionName.js +58 -11
  137. package/dist/sdk/tools/spawnSubagent.js +9 -7
  138. package/dist/sdk/tools/todo.d.ts +15 -0
  139. package/dist/sdk/tools/todo.js +64 -0
  140. package/dist/sdk/world/world.d.ts +0 -2
  141. package/dist/terminal-opentui.js +3331 -1584
  142. package/dist/terminal-pi.js +421 -133
  143. package/docs/README.md +3 -0
  144. package/docs/architecture/00-overview.md +1 -1
  145. package/docs/architecture/01-extension-points.md +1 -1
  146. package/docs/architecture/02-sessions-and-runs.md +73 -36
  147. package/docs/architecture/03-variants.md +1 -3
  148. package/docs/architecture/04-prompt.md +24 -13
  149. package/docs/architecture/06-plugins-and-capabilities.md +46 -10
  150. package/docs/architecture/07-tools-and-gate.md +49 -8
  151. package/docs/architecture/09-accounts-and-connectors.md +8 -2
  152. package/docs/architecture/10-server-protocol.md +68 -16
  153. package/docs/architecture/11-terminal.md +94 -45
  154. package/docs/architecture/12-storage.md +1 -0
  155. package/docs/architecture/13-world-tools.md +8 -6
  156. package/docs/architecture/14-surfaces-and-parity.md +4 -1
  157. package/docs/architecture/README.md +20 -18
  158. package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
  159. package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +6 -2
  160. package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +32 -21
  161. package/docs/architecture/proposals/PROP-0044-work-slice-defaults.md +93 -0
  162. package/docs/architecture/proposals/PROP-0045-rename-checklist-to-todo.md +132 -0
  163. package/docs/architecture/proposals/PROP-0046-progress-aware-stall-guards.md +82 -0
  164. package/docs/architecture/proposals/PROP-0047-plugins-hub-separation.md +122 -0
  165. package/docs/architecture/proposals/PROP-0048-simple-annotate.md +85 -0
  166. package/docs/architecture/proposals/README.md +11 -6
  167. package/docs/decisions/ADR-0039-progress-aware-stall-guards.md +39 -0
  168. package/docs/decisions/ADR-0040-architecture-change-workflow.md +31 -0
  169. package/docs/decisions/ADR-0041-plugins-hub-separation.md +41 -0
  170. package/docs/decisions/ADR-0042-windows-shell-without-sandbox.md +40 -0
  171. package/docs/decisions/ADR-0043-parents-continue-stopped-subagents.md +49 -0
  172. package/docs/decisions/ADR-0044-annotations-pending-or-sent.md +24 -0
  173. package/docs/decisions/ADR-0045-default-plugin-authoring-skill.md +9 -0
  174. package/docs/decisions/ADR-0046-hash-bound-plugin-proposals.md +20 -0
  175. package/docs/decisions/ADR-0047-links-open-with-the-os-handler.md +47 -0
  176. package/docs/doctor.md +14 -1
  177. package/docs/parity.md +16 -13
  178. package/docs/releases/1.3.0.md +21 -0
  179. package/docs/releases/1.3.1-unstable.1.md +8 -0
  180. package/docs/releases/README.md +9 -6
  181. package/docs/terminal-tui.md +127 -65
  182. package/package.json +1 -1
  183. package/dist/sdk/terminal/tui/pages/notesPage.d.ts +0 -75
  184. package/dist/sdk/terminal/tui/pages/notesPage.js +0 -201
  185. package/dist/sdk/tools/checklist.d.ts +0 -9
  186. package/dist/sdk/tools/checklist.js +0 -55
@@ -40,7 +40,9 @@ harness → host { v: 1, id, call, params } host → harness { v: 1
40
40
  `plugins.describe`.
41
41
  - `refine.start` takes `{ task, k?, mode?, improver?, executor?, baseVersion?, retainWorkspaces?, id? }`;
42
42
  `refine.candidates` returns each execution with `workspace: string | null` (page 05, PROP-0002, PROP-0003).
43
- - `runs.checklist { runId }` returns the run's latest checklist, `[]` when it wrote none (PROP-0006).
43
+ - `runs.todo { runId }` returns the run's latest todo list, `[]` when it wrote none (PROP-0006,
44
+ renamed by PROP-0045). `runs.checklist` is the deprecated pre-rename alias.
45
+ - `runs.continuation` returns `todo`; `checklist` remains a deprecated mirror of it for one release.
44
46
  - Run records include optional nullable `workspaceRoot`, the canonical root whose files a run may
45
47
  modify by default (page 02). New Harness runs set it; older records may omit it. Hosts must
46
48
  tolerate the additive field and must not nominate or widen the root.
@@ -49,15 +51,18 @@ harness → host { v: 1, id, call, params } host → harness { v: 1
49
51
  and refuses an existing file; `agents.remove { cwd?, name, scope }` deletes a person's own file.
50
52
  `subagents.spawn` takes `agent` as a profile name and returns `agent` and `unavailableTools`
51
53
  (PROP-0029). It takes an optional `title` (at most six words); without one the child's title is
52
- the first line of its brief (PROP-0030).
54
+ the first line of its brief (PROP-0030). With `continue: <runId>` it continues a stopped child of
55
+ this conversation instead (no `agent` or `tools`; `brief` and `title` optional) and returns
56
+ `continued`, the run it continued (ADR-0043).
53
57
  - `runs.continuation { runId, sessionDir? }` returns a `Continuation` (its `checkpoint` is the last
54
58
  work-slice handoff), and `sessions.run` accepts `continueFrom` (page 02, PROP-0007) and `workSlice`
55
59
  (PROP-0041). `harness.status` reports `recovery.interruptedRunIds`.
56
60
  - `workSlice { enabled?, maxToolCalls?, maxMinutes?, maxNewTokens?, maxSlices?, continue? }` on
57
- `sessions.run` bounds that reply; absent uses 160 calls, 40 minutes, 320 000 new tokens, 8 slices and
58
- automatic continuation. A token cap counts new input, cache writes and output, never the cached
59
- prefix. `enabled: false` turns the guard off for that run; `XINGULAR_WORK_SLICE=off` in the
60
- launching process turns it off for every run in it, and nothing is persisted. The policy is
61
+ `sessions.run` bounds that reply; absent uses 320 calls, 60 minutes, no new-token cap, 8 slices and
62
+ automatic continuation. A token cap, when set, counts new input, cache writes and output, never the
63
+ cached prefix (PROP-0044). `enabled: false` turns the guard off for that run;
64
+ `XINGULAR_WORK_SLICE=off` in the launching process turns it off for every run in it, and nothing is
65
+ persisted. The policy is
61
66
  carried into the continuation. A value outside its range is refused with `invalid_request` before
62
67
  the run record is written.
63
68
  - The run-event stream adds `checkpoint` (the bounded handoff) and `heartbeat` (steps, elapsed time,
@@ -65,6 +70,24 @@ harness → host { v: 1, id, call, params } host → harness { v: 1
65
70
  relayed in order (INV-RUN-3).
66
71
  - Errors carry a stable `code`, a message and an optional hint (`core/errors.ts`).
67
72
 
73
+ ## Plugin proposals
74
+
75
+ | Method | Input | Reply |
76
+ |---|---|---|
77
+ | `plugins.proposals.create` | `{ name, description, files }` (path-to-text object) | pending `Proposal` |
78
+ | `plugins.proposals.list` | `{}` | `Proposal[]`, including decided records |
79
+ | `plugins.proposals.preview` | `{ id }` | revalidated `Proposal` with current content hash |
80
+ | `plugins.proposals.accept` | `{ id, hash }` | accepted `Proposal` |
81
+ | `plugins.proposals.reject` | `{ id, hash }` | rejected `Proposal` |
82
+
83
+ A `Proposal` has `id`, `name`, `description`, `files`, generated `manifest`, `hash`, `createdAt`,
84
+ `status` and optional `decidedAt`. Both decisions require the pending proposal's current preview
85
+ hash; acceptance installs it switched off without trusting code. These methods expose trusted host
86
+ operations, not an assertion that a host has built a review UI. Protected terminal control routes
87
+ `plugins.proposals.list|preview|accept|reject` delegate to the same service when configured; they
88
+ require the terminal control key. The model tool can create only. Validation and trust details are
89
+ on page 06.
90
+
68
91
  ## Usage (PROP-0042)
69
92
 
70
93
  | Method | Input | Reply |
@@ -183,11 +206,14 @@ from preparation, never from the request.
183
206
  | `terminal.browser.connections.save` | `{ input: ConnectionInput }` | Existing safe `Connection` record |
184
207
  | `terminal.browser.connections.test\|signIn\|signOut\|remove` | `{ id }` | Existing connection service result |
185
208
  | `terminal.usage.summary\|limits` | `{ scope, period, timezoneOffsetMinutes }` / `{ refresh? }` | Existing usage service result, scoped to this terminal's account and project |
209
+ | `terminal.usage.allLimits` | `{ refresh? }` | All-account provider limits; refresh reads providers due under the configured cache interval, without changing the pinned account |
186
210
  | `terminal.usage.headers` | `{ provider, status, headers }` | `{}`; only limit-bearing headers, throttled, stored as an account limit reading |
187
211
 
188
- Protected `plugins.install { source }` and `plugins.remove { pluginId }` delegate to the package
189
- service. Optional matching callbacks extend `PluginControl`; hosts without them receive a clear
190
- unsupported-operation error. No protocol version or persisted schema changes.
212
+ Protected `plugins.install { source }`, `plugins.update { pluginId? }` and
213
+ `plugins.remove { pluginId }` delegate to the package service. Removing a Hub-owned package routes
214
+ through Hub's receipt-aware uninstall; a floating update refuses Hub-owned packages, while an
215
+ update-all skips them. Optional matching callbacks extend `PluginControl`; hosts without them
216
+ receive a clear unsupported-operation error. No protocol version or persisted schema changes.
191
217
 
192
218
  ## Worktrees (PROP-0016)
193
219
 
@@ -224,14 +250,18 @@ same service through `terminal.worktrees.*` routes, which need the control key (
224
250
  | `annotations.revokeBinding` | `{ binding }` | `{ revoked }` |
225
251
  | `annotations.import` | `{ notes }` | `{ imported, skipped }` (ids kept) |
226
252
  | `annotations.pageScript` | `{}` | `{ script }`: the page helper, with `__ARGS__` for one operation |
227
- | `annotations.queue` | `{ id, sessionId, expectedVersion?, autoSend? }` | `Note`, shared with the session and queued (PROP-0018) |
228
- | `annotations.dequeue` / `annotations.confirm` | `{ id, expectedVersion? }` | `Note` |
229
- | `annotations.queued` | `{ sessionId }` | `{ notes }`, oldest first |
230
- | `annotations.createAndAct` | `{ note, action: save \| queue \| send, sessionId?, trusted? }` | `{ note, send }`; an untrusted send waits for `confirm` |
231
- | `annotations.compose` | `{ sessionId, ids? }` | `{ text, ids }`: one instruction for a host's own `sessions.run` |
253
+ | `annotations.markPending` | `{ id, sessionId, expectedVersion? }` | `Note`, shared with the session and unsent (PROP-0018, PROP-0048) |
254
+ | `annotations.confirm` | `{ id, expectedVersion? }` | `Note` |
255
+ | `annotations.confirmAll` | `{ sessionId }` | `{ notes }`: every page-origin note of the session, confirmed |
256
+ | `annotations.pending` | `{ sessionId }` | `{ notes }`, unsent, oldest first |
257
+ | `annotations.clear` | `{ sessionId }` | `{ notes }`: the session's unsent notes, resolved and no longer shared with it |
258
+ | `annotations.createAndAct` | `{ note, action: save \| send, sessionId?, trusted? }` | `{ note, send }`; with a session the note is always shared; `send` sends all unsent notes; an untrusted note waits for `confirm` |
259
+ | `annotations.compose` | `{ sessionId, ids?, prompt? }` | `{ text, ids }`: one message for a host's own `sessions.run`, with the person's request last |
232
260
  | `annotations.delivered` | `{ ids, sessionId, runId }` | `{ notes }`, marked sent |
233
- | `annotations.send` | `{ sessionId, ids? }` | `{ state: sent \| busy \| host \| empty, … }` |
261
+ | `annotations.send` | `{ sessionId, ids?, prompt? }` | `{ state: sent \| busy \| host \| empty, …; empty has unconfirmed }` |
234
262
  | `annotations.capture.attach` | `{ key, kind: web \| cdp \| bridge, endpoint?, name? }` | `{ kind, app, windows, bridge? }` |
263
+ | `annotations.capture.discover` | `{}` | `{ apps: [{ endpoint, port, name, browser, electron, windows }] }`: apps on a loopback DevTools port |
264
+ | `annotations.capture.launch` | `{ key, path, args? }` | `{ kind: cdp, app, windows, endpoint }`: starts the app with a DevTools port and attaches |
235
265
  | `annotations.capture.target` | `{ key }` | `{ kind, app, inspecting, windows }` |
236
266
  | `annotations.capture.selectWindow` | `{ key, window }` | `{}` |
237
267
  | `annotations.capture.open` | `{ key, url? }` | `{ url, title }` |
@@ -240,9 +270,31 @@ same service through `terminal.worktrees.*` routes, which need the control key (
240
270
  | `annotations.capture.release` | `{ key }` | `{}` |
241
271
  | `annotations.bridge.start` | `{}` | `{ port, token, scriptUrl, snippet }` |
242
272
 
243
- Notices: `annotations.changed { sessionId, ids }` after any queue, send or fix;
273
+ Notices: `annotations.changed { sessionId, ids }` after any share, send or clear;
244
274
  `annotations.ready { sessionId, ids }` when a host session's waiting notes should be sent now.
245
275
 
246
276
  Errors: `version_conflict`, `not_found`, `annotation_limit`, `invalid_request`, `invalid_data`. The
247
277
  terminal reaches the same store through `terminal.annotations.*`, which shares only with its own
248
278
  session and needs the control key (`INV-TUI-4`).
279
+
280
+ ## Links (ADR-0047)
281
+
282
+ A link a person clicks is a person's action, not a model tool call: nothing here is in
283
+ `HARNESS_TOOLS`, so the gate, standing approvals and redaction never see it. `core/links.ts` holds
284
+ the one allowlist both front ends use, and `openLink` is the only door into the operating system.
285
+
286
+ | Method | Input | Reply |
287
+ |---|---|---|
288
+ | `links.open` | `{ target, base? }` | `OpenedTarget`: `{ kind: "web", url }`, `{ kind: "mail", address }`, `{ kind: "file", path }` or `{ kind: "directory", path }` |
289
+
290
+ `target` is what the link says; `base` is the absolute folder a relative target is resolved
291
+ against, and without it a relative target is refused. `linkTarget` classifies without touching the
292
+ filesystem (`http`/`https`, `mailto`, `file`, an absolute path, or a relative path under `base`),
293
+ and `openableTarget` then checks what it names: a regular file or a directory, never an application
294
+ bundle, an installer, or a launchable script, and never a file with an executable bit set, because
295
+ `xdg-open` runs one. The address is passed to `open`/`xdg-open`/`rundll32` as one argument, never
296
+ through a shell.
297
+
298
+ Errors: `link_not_openable`, with a message a person can read, and `invalid_request` when `target`
299
+ is missing. The opener is `HarnessOptions.linkOpener`, so a host with its own native opener keeps
300
+ the policy and replaces only the spawn.
@@ -43,7 +43,7 @@ Screen: transcript above the composer, centred dialogs, full-screen resource bro
43
43
  per-tool grants do not widen it, and command output never triggers approval or replay.
44
44
  - The terminal compiles its prompt once (`compile` + `render`) and keeps that pack; each run
45
45
  records a copy (page 04). The shared compaction checkpoint extension reintroduces the active
46
- request and latest checklist into post-compaction model context until the run settles.
46
+ request and latest todo list into post-compaction model context until the run settles.
47
47
  - Normal mode keeps `ask_user` out of the active tool set. An attended plan request enables the
48
48
  shared tool alongside its read-only set and restores the normal set on success, failure or
49
49
  interruption. There is no terminal-only question alias (PROP-0040).
@@ -77,14 +77,18 @@ Screen: transcript above the composer, centred dialogs, full-screen resource bro
77
77
  leaves the main conversation untouched. The dock streams, scrolls and copies the complete answer.
78
78
  Aliases remain callable and searchable, but help and palette show only the canonical
79
79
  entry. `/usage:` and `/usage:analysis` open the usage page's Analysis tab, and `/usage:limit`
80
- opens its Limits tab (PROP-0042); both are plugin-owned namespaced routes. The usage page is a
81
- centered dialog: each window is a label and reset line above a quota-left bar coloured green at
80
+ opens its Limits tab (PROP-0042); `/usage:accounts` opens the All accounts limits tab. These are plugin-owned namespaced routes. All-account refresh reads due providers using their own account credentials without switching the session account. The usage page is a
81
+ full-screen page with a top tab strip: each window is a label and reset line above a quota-left bar coloured green at
82
82
  50% or more left, amber from 20–49%, and red below 20%. `commands.list`
83
83
  publishes the effective routes; the browser-safe core catalogue is `commands/registry.ts`. First-class Harness commands are unprefixed and live in that registry,
84
84
  independently of plugin command metadata. Every plugin-owned command uses
85
85
  `/<owner-prefix>:<command>`; the namespace root is offered only by plugins that declare a default
86
86
  command. Prompt templates and `/skill:<name>` keep their existing forms.
87
87
 
88
+ The `/plugins` Proposals tab previews the complete stored files and generated manifest before
89
+ confirmation. Accept and reject pass the preview hash through the control-key-protected socket;
90
+ the proposal service checks it again. Acceptance leaves the package switched off and untrusted.
91
+
88
92
  ## Invariants
89
93
 
90
94
  - **INV-TUI-1** OpenTUI is the only terminal frontend. Pi's `InteractiveMode` is never constructed
@@ -96,7 +100,7 @@ Screen: transcript above the composer, centred dialogs, full-screen resource bro
96
100
  their existing layers. The terminal adds no second path for any of them; its runs are written
97
101
  through the controller and the run store.
98
102
  - **INV-TUI-4** Changes made through the session socket (`plugins.attach|detach|trust|untrust|configure`,
99
- `accounts.*`, Hub installs, `terminal.browser.*`, `terminal.worktrees.*`,
103
+ `plugins.proposals.*`, `accounts.*`, Hub installs, `terminal.browser.*`, `terminal.worktrees.*`,
100
104
  `terminal.annotations.*`, `terminal.sideQuestions.*`) require the control key the trusted terminal process claimed once
101
105
  (`control.claim`). The session's shell can read the session token, so the token alone is never
102
106
  enough.
@@ -144,6 +148,13 @@ The native `session_info_changed` event invalidates the frontend's cached snapsh
144
148
  refreshes the working line. Both the active and retained completion line append
145
149
  ` – <name>` after duration and token rate, for example
146
150
  `Working (2m, 50 tok/s) – Add web browser integrations`. Unnamed sessions omit the suffix.
151
+ A substantive first turn also receives a provisional name through the terminal policy; a refused
152
+ or failed name leaves the session unnamed.
153
+
154
+ Each user turn appends a hidden `xingular-session-state` custom message with the current name,
155
+ this run's empty todo, and the previous run's todo as context. The message is request-only and
156
+ never changes the compiled stable pack. A first turn is marked as such; later turns say the todo
157
+ list resets for each run.
147
158
  Names use the existing terminal text sanitization, remain outside the verb shimmer, and
148
159
  truncate at the right edge. Manual `/name` and existing long names remain supported.
149
160
 
@@ -156,19 +167,29 @@ on close. No command text is sent to the conversation model. See [Doctor](../doc
156
167
 
157
168
  ## Resource browser (PROP-0013)
158
169
 
159
- `/harness` owns shared navigation for Foundation, Variant, Skills, Plugins, Connections, Tools
160
- and Library. `/skills`, `/plugins`, `/connections` (`/mcp`), `/tools`, `/hub` and `/components`
161
- are shortcuts into that browser. Current availability comes from the live resource loader and
162
- active tool registry, independently of saved configuration and the latest variant head.
170
+ `/harness` owns broad navigation for Foundation, Variant, Skills, Plugins, Connections, Tools and
171
+ Library. `/skills`, `/connections` (`/mcp`), `/tools` and `/components` are shortcuts into that
172
+ browser. `/plugins` opens the focused local plugin manager (Plugins, Trust and Packages tabs); `/hub`
173
+ opens the separate Community catalog (Catalog and Installed tabs). The Hub Catalog shows Community
174
+ entries across supported types; Installed retains receipts from every channel with its channel
175
+ visible. Registry/document entries offer bounded payload Preview; Pi packages do not. Current
176
+ availability in `/harness` comes from the live resource loader and active tool registry,
177
+ independently of saved configuration and the latest variant head.
163
178
 
164
179
  Every `terminal.browser.*` call requires the private control key, including bounded resource
165
- inspection, local imports, connection management and browser settings. Package install/remove use protected
166
- `plugins.install|remove`. These are adapters to the existing services, not another loader,
167
- attachment store, gate or secret store. Browsing neither executes plugin code nor connects MCP.
180
+ inspection, local imports, connection management and browser settings. Direct plugin package
181
+ install/update/remove and attachment/trust/settings actions use protected `plugins.*`; Hub catalog
182
+ list/install/uninstall use protected `hub.*`. Hub-owned package removal keeps the receipt and
183
+ resource ownership in the Hub service. These routes are adapters to the existing services, not
184
+ another loader, attachment store, gate or secret store. Browsing neither executes plugin code nor
185
+ connects MCP.
168
186
  The browser uses the full terminal with persistent section tabs (PROP-0014); wide screens keep
169
187
  inventory beside details, actions and content, while compact screens keep inline details under
170
- the same tabs. Other command pages remain centered except `/settings` and `/accounts`, which use
171
- full-screen page layouts. Accounts keeps Accounts/Pools tabs, search and account-service operations.
188
+ the same tabs. The separate `/plugins` and `/hub` pages also use full-screen layouts with persistent
189
+ section tabs, responsive inventory/details panes and their existing protected operations. Other
190
+ command pages remain centered except `/settings`, `/accounts`, `/plugins`, `/hub` and `/usage:`, which use
191
+ full-screen page layouts.
192
+ Accounts keeps Accounts/Pools tabs, search and account-service operations.
172
193
  Wide terminals show selected-account details beside the list; Enter or a primary click opens grouped
173
194
  actions in that inspector. Compact terminals replace the list with a full-page account detail view
174
195
  and its grouped actions. Enter opens the selected account; Escape returns to the list while
@@ -243,39 +264,56 @@ contract is unchanged. See [PROP-0025](proposals/PROP-0025-contextual-question-w
243
264
  PTY verification is retained in `docs/evidence/terminal-wireframe-normalization/`; it establishes
244
265
  cell topology for bounded fixtures, not every emulator/font or live-model sketch quality.
245
266
 
246
- ## Web annotations commands (PROP-0017)
267
+ ## Web annotations commands (PROP-0017, PROP-0018, PROP-0048)
247
268
 
248
- `/annotate:notes` lists the Web annotations kept in the data root, with search, and offers reveal, edit, resolve or
249
- reopen, share with this session or stop sharing, and delete. `/annotate:` opens the default capture pane;
250
- `/annotate:annotate [url]` is its explicit command form. It opens a visible capture browser (its own window and profile, separate from the agent's browser), where the person can annotate the whole page,
251
- select text, or click an element there. An annotation is private until shared; this session's agent then reads it with `page_notes_list`
252
- and `page_notes_read`.
269
+ `/annotate:` opens the annotate page, a full-screen page with two tabs. `/annotate:notes` opens it on
270
+ **All annotations**: every annotation in the data root, with search, and reveal, edit, resolve or
271
+ reopen, share with this session or stop sharing, and delete. An annotation is private until shared;
272
+ this session's agent then reads it with `page_notes_list` and `page_notes_read`.
253
273
 
254
- The annotate pane (PROP-0018) is a full-screen page beside the window being inspected.
274
+ The **Annotate** tab is the panel beside the window being inspected.
255
275
 
256
276
  - **Ways to start it:**
257
- - `/annotate:` or `/annotate:annotate [url]`: the capture browser
258
- - `/annotate:annotate --app <DevTools address | port> [name]`: an app's own windows over its DevTools port
259
- - `/annotate:annotate --bridge [name]`: app windows that load the page bridge script, which the pane shows
260
- - **The inspector** (`i`) outlines components on hover. A click or a text drag opens a popover in the page with Create annotation, Ask agent to fix, and Proceed now.
261
- - **Sections:** Queue, Sent and fixed (with the agent's summary), and Saved.
262
- - **Other keys:** `s` sends the queue as one run of this session, confirming notes that came from a page-world script first; `x` takes a note out of the queue; `t` picks a window.
263
- - **Routes:** `terminal.annotations.target|attach|windows|selectWindow|inspect|stopInspect|next|queue|dequeue|confirm|send` act only on this terminal's session and need the control key.
264
-
265
- ## Checklist (PROP-0006, PAR-001)
266
-
267
- Terminal sessions register the shared `checklist_write` tool. The extension validates each list
268
- with the same tool code and sends it as `checklist` telemetry; the controller emits it as
269
- `checklist.updated` on the active run, so `runs.checklist` and continuation read terminal runs too.
270
- The gate treats it as read-only, plan mode allows it, and terminal children inherit it. The
271
- transcript shows each write as a checklist block (`✓` done, `●` in progress (warning yellow), `○` pending) under a
272
- `Checklist · n of m done` header instead of a tool row; a failed or malformed call stays a tool row.
277
+ - `/annotate: [url]`: the capture browser (its own window and profile, separate from the agent's
278
+ browser). With no address, the page returns to the window that is still open, with its URL and
279
+ the inspector on, and asks for one in its own inline field only when no window is open.
280
+ - `/annotate: --app [port | address] [name]`: an app's own windows over its DevTools port. With no
281
+ port, the page lists the apps answering on one (`annotations.capture.discover`).
282
+ - `/annotate: --bridge [name]`: app windows that load the page bridge script, which the page shows.
283
+ - **The inspector** (`i`) outlines components on hover. A click or a text drag opens a popover in
284
+ the page with **Annotate** and **Annotate & send**. Every annotation is shared with this session
285
+ at once.
286
+ - **Groups:** Unsent (n) and Sent, for this session.
287
+ - **Other keys:** `s` sends every unsent annotation as one run of this session, confirming the
288
+ page-origin ones once first; `o` types a page address; `a` lists apps with a DevTools port, with
289
+ *Start an app with a DevTools port*, *Type a DevTools port*, *Use the page bridge*; `t` picks a
290
+ window; `Tab` switches tab. A key pressed while the page is busy gets a notice, never nothing.
291
+ - **Commands:** `/annotate:submit <request>` sends the unsent annotations with the request after
292
+ them; `/annotate:clear` resolves the unsent ones and stops sharing them.
293
+ - **Routes:** `terminal.annotations.target|attach|windows|selectWindow|inspect|stopInspect|next|confirm|confirmAll|send|clear|discover|launch`
294
+ act only on this terminal's session and need the control key.
295
+
296
+ A page that opens a dialog as it starts gets it above itself: `PageOverlay` starts its page when the
297
+ host reports the overlay mounted.
298
+
299
+ ## Todo list (PROP-0006, PROP-0045, PAR-001)
300
+
301
+ Terminal sessions register the shared `todo_write` tool. The extension validates each list with
302
+ the same tool code and sends it as `todo` telemetry; the controller emits it as `todo.updated` on the
303
+ active run, so `runs.todo` and continuation read terminal runs too. The gate treats it as read-only,
304
+ plan mode allows it, and terminal children inherit it. The transcript shows each write as a todo
305
+ block (`✓` done, `●` in progress (warning yellow), `○` pending) under a `Todo · n of m done` header
306
+ instead of a tool row; a failed or malformed call stays a tool row. `/todo` reads the latest
307
+ non-side-question run of this terminal's native session and appends the same card as a snapshot,
308
+ without a model request; an empty list is a one-line notice. `/checklist` remains its alias for one
309
+ release.
273
310
 
274
311
  ## Work-slice checkpoint (PROP-0041)
275
312
 
276
- Terminal replies carry the same work-slice guard as structured runs: 160 tool calls, 40 minutes or
277
- 320 000 new tokens, then a refusal that asks for `checkpoint_write`. The extension registers the shared
278
- tool and sends it as `checkpoint` telemetry, which the controller records as `checkpoint` on the
313
+ Terminal replies carry the same work-slice guard as structured runs: 320 tool calls or 60 minutes,
314
+ with no new-token limit by default (PROP-0044), then a refusal that asks for `checkpoint_write`. The
315
+ extension registers the shared tool and sends it as `checkpoint` telemetry, which the controller
316
+ records as `checkpoint` on the
279
317
  active run, so an App reading the same session sees the handoff. Terminal replies are not
280
318
  auto-continued: at the boundary the person decides, which is what the terminal's own turn model
281
319
  already does. The run record says `interrupted` with terminal reason `slice_complete` (or `stalled`
@@ -288,13 +326,13 @@ boundary at all; it is not persisted, so the next launch without it restores the
288
326
  During an active parent run, the terminal polls a private read-only monitor once per second. It
289
327
  projects the flat set of child and nested-child runs with task, status, elapsed time, the latest
290
328
  tool name, the child's agent profile (name and colour, PROP-0029), the title the parent gave it
291
- (PROP-0030), counts from the child's own checklist, the pinned account label, effective model and
329
+ (PROP-0030), counts from the child's own todo list, the pinned account label, effective model and
292
330
  effort, and cumulative usage totals. Model and effort come from the volatile launch selection; the
293
331
  latest provider-reported model supersedes the launch model when usage is available. Usage is an
294
332
  explicit projection of token, cache, cost, request-count and context-window totals. Per-request
295
333
  payloads and reasoning summaries do not enter the monitor. The child's own `session_name` is not
296
334
  projected; it names the child's session, not its row. Tool summaries, other arguments, output and
297
- checklist item text never enter the monitor. The latest completed tool name remains visible across
335
+ todo item text never enter the monitor. The latest completed tool name remains visible across
298
336
  one-second snapshots until new tool or response activity replaces it. The monitor exposes no
299
337
  controls to steer or stop children.
300
338
 
@@ -302,15 +340,26 @@ The live rows sit under the status line, after one blank row, with no heading. E
302
340
  order: the status mark (`○` queued, a running row that shows the working spinner's frame in the profile's colour (warning for a copy of the parent), `●` waiting in the accent,
303
341
  `✓` done, `✕` failed, `!` stopped), the profile name in its colour (`subagent`, muted, for a copy
304
342
  of the parent), the title the parent gave the child (PROP-0030), and `n of m tasks` when the child
305
- keeps a checklist. Active rows come first, at most three, then `+N more · /subagents`; a narrow
343
+ keeps a todo list. Active rows come first, at most three, then `+N more · /subagents`; a narrow
306
344
  terminal cuts the title first. `/subagents` opens the searchable full roster, with a colored
307
345
  profile and normal-color title on its first line, then muted account, model, effort and usage
308
346
  metadata on its second line. One blank row separates each two-line entry. Narrow rows truncate this
309
347
  lower-priority summary without hiding the title.
310
348
  At parent settlement, the terminal makes a final monitor read and keeps the latest parent's rows
311
- visible until the next parent run starts. The projection remains volatile and read-only, is scoped to
312
- the latest parent run in the terminal session, and is cleared on session replacement or terminal
313
- disposal. It is not a persisted event or public server method.
349
+ visible until the next parent run starts.
350
+
351
+ The monitor also projects the parent run itself as a `main` row (profile `main`, a reserved name,
352
+ in the theme's primary colour) with the same account, model, effort, usage, activity and todo
353
+ fields. The `/subagents` page pins it first and counts only children in its header; the rows under
354
+ the status line omit it, since the status line already describes the main agent.
355
+
356
+ Every turn marks its run on the native branch (`xingular-subagent-owner`), and `ready` sends those
357
+ owners. When a conversation opens or is switched to with no run active, the monitor is rebuilt from
358
+ the branch's latest top-level run in this folder and its descendants, by folding their saved events
359
+ with their final status. Runs a stopped process left active were already marked `interrupted`.
360
+ The rows show under the status line and on the page until the next parent run starts (ADR-0043).
361
+ The projection remains read-only and scoped to one parent run; a switch to a conversation with no
362
+ such run clears it, as does terminal disposal. It is not a persisted event or public server method.
314
363
 
315
364
  ## Agent profiles (PROP-0029)
316
365
 
@@ -23,6 +23,7 @@ index.
23
23
  legacy/ an earlier Wiki's data, moved once (08)
24
24
  registry/ skills/, prompts/, rules/: the component library (03)
25
25
  plugins/<name>/ packages kept with the data (06)
26
+ plugin-proposals/<id>.json pending and decided proposal text, hash and status; owned by plugins/proposals.ts (06)
26
27
  trash/plugins/ removed packages (06)
27
28
  hub/ installed documents and provenance (09)
28
29
  runs/<id>/ run.json (including optional legacy-compatible workspaceRoot), events.jsonl, owner.json, subagents.json, context.json, caller.json, capabilities.json, mcp-context.json (02)
@@ -48,19 +48,21 @@ it. A tool returns only notes a person shared with the calling session or agent;
48
48
  and element names are marked untrusted. Capture happens in a visible capture browser in the
49
49
  terminal, or in a host's own web view running the same page helper (`annotations.pageScript`).
50
50
 
51
- **Inspector, queue and app targets (PROP-0018).**
51
+ **Inspector, sending and app targets (PROP-0018, PROP-0048).**
52
52
 
53
- - **Inspector.** In the page helper's inspector, hovering outlines a component and a click (or a drag over text) opens a comment popover inside the page, with three choices: save, queue for the agent, or send now.
54
- - A queued note is shared with its session.
55
- - `annotations/delivery.ts` sends a batch as one instruction, and sends notes the person asked for while the session was busy when its run ends.
56
- - The agent reports a fix with `page_notes_mark_fixed`, the only page-note tool that writes. It never resolves a note or changes grants.
53
+ - **Inspector.** In the page helper's inspector, hovering outlines a component and a click (or a drag over text) opens a comment popover inside the page, with two choices: Annotate and Annotate & send.
54
+ - With a session, every note is shared with it at once and is pending (unsent) until sent.
55
+ - `annotations/delivery.ts` sends all of a session's pending notes as one message, with the
56
+ person's request last when given, and sends notes held back while the session was busy when its
57
+ run ends, trying again while the session still answers busy.
58
+ - The page-note tools are read-only. Only the person resolves a note.
57
59
  - **Targets.** Element targets prefer semantic role/name/text. A visually empty element may still be
58
60
  annotated when it has a specific CSS selector (ID, test ID, classes, and a structural path when
59
61
  needed); bare tag selectors are not enough. Reveal checks for one live match and preserves any
60
62
  captured semantic/context evidence, otherwise reporting ambiguous or unresolved. Text annotations
61
63
  continue to use quote plus context, not screen coordinates.
62
64
  - Besides the browser window, capture can use an app's own windows:
63
- - **DevTools port:** an app started with a DevTools port, on a loopback address only. It uses the app's existing windows, routes nothing, and never closes the app.
65
+ - **DevTools port:** an app started with a DevTools port, on a loopback address only. It uses the app's existing windows, routes nothing, and never closes the app. `discover` probes loopback ports 9222–9230 and ports used before (a Node inspector is skipped); `launchApp` starts a program (the one inside a macOS `.app`) with `--remote-debugging-port` on a free loopback port and attaches. A started app keeps running.
64
66
  - **Page bridge:** a loopback server whose script an app loads while it is developed (`annotations/bridge.ts`), for web views without a DevTools port.
65
67
  - **Web components (PROP-0038).** The helper walks the composed tree: open shadow roots and slotted content can be picked, selected and revealed, and such targets carry `tree: 'composed'`. Targets without it resolve by the document-only rules as before. Closed shadow roots and frames stay out of reach, and the inspector says why it refuses something.
66
68
  - **Trust.** In Chromium targets the helper runs in an isolated script world, so the page cannot forge a comment. A send from the bridge, or from a host web view without isolation, waits for the person to confirm it.
@@ -17,7 +17,7 @@ terminal command or page, a host screen.
17
17
  |---|---|---|
18
18
  | Foundation service | A member of `Harness` with server methods | `sessions`, `accounts`, `apps`, `worktrees` (PROP-0016), agent profiles (`agents.*`, PROP-0029) |
19
19
  | Built-in feature plugin | A module in `BuiltinPluginRegistry` (`plugins/builtin.ts`) that may supply a `WorldPart`, server methods and terminal commands | web tools, browser tools, annotations, worktrees |
20
- | First-party plugin | A descriptor in the registry (`plugins/builtin.ts`) | lessons, checklist |
20
+ | First-party plugin | A descriptor in the registry (`plugins/builtin.ts`) | lessons, todo |
21
21
  | Terminal surface | A command, page or dialog in `terminal/` | `/plan`, `/doctor`, the resource browser |
22
22
  | Host surface | A host screen built on the same methods and tools | the App's chat, Capability and Harness screens |
23
23
  | Host-backed backend | An operating-system object only a host has, behind a generic Harness contract | the App's WebKit tabs, macOS computer bridge, keychain |
@@ -29,6 +29,9 @@ terminal command or page, a host screen.
29
29
  tool that passes the gate (page 07). Both front ends use the same methods; neither has a private
30
30
  path to Harness state. Foundation context behavior, including bounded checkpoint restoration after
31
31
  compaction (PROP-0033), is shared by terminal and embedded sessions; a host does not reimplement it.
32
+ The direct `/plugins` page manages local plugin state and package lifecycle; `/hub` presents the
33
+ Community catalog and all installed Hub receipts. These are distinct presentations of existing
34
+ Harness services, not host-only capabilities. The broad `/harness` browser remains available.
32
35
  - Workspace write scope is Harness-owned on both surfaces. Each run pins a canonical root after
33
36
  worktree selection; reads retain OS-permission scope, while native file writes and shell
34
37
  filesystem effects default to that root; the filesystem root itself is not a valid workspace.
@@ -1,10 +1,11 @@
1
1
  # Harness architecture specification
2
2
 
3
- **Status:** binding. **As of:** 2026-10-26, checked against `src/` on branch `release/1.0.0`.
3
+ **Status:** binding. **As of:** 2026-10-27, checked against `src/` on branch `release/1.0.0`.
4
4
 
5
5
  This folder is the core specification of `@xingular/harness`. Code must conform to it. A change
6
- that would alter what it says needs a proposal the user approves first (see
7
- [Changing the architecture](#changing-the-architecture)).
6
+ that alters what it says must update the affected pages in the same change (see
7
+ [Changing the architecture](#changing-the-architecture)). Proposals are optional design records,
8
+ not prerequisites or approval gates.
8
9
 
9
10
  Other documents explain and record; this folder decides. Where another document disagrees with a
10
11
  page here, this page wins, and the disagreement is listed under [Known drift](#known-drift).
@@ -64,7 +65,7 @@ current behavior.
64
65
 
65
66
  | Word | Meaning |
66
67
  |---|---|
67
- | **Foundation** | The fixed half of the harness: code and invariants that no edit, improver or adoption can change. Changes by release, and by proposal when a contract moves. |
68
+ | **Foundation** | The fixed half of the harness: code and invariants that no edit, improver or adoption can change. Changes by release; contract changes update the specification and may use an optional proposal as a design record. |
68
69
  | **Agent Mode** | A planned foundation-level work style, with at most one mode active at a time. Plugins remain independently stackable contributions. This is distinct from plan mode and existing `mode` fields; it is not a runtime contract ([FW-0001](../future-work.md#fw-0001-agent-modes-starting-with-router-agent-mode)). |
69
70
  | **Variant** | The mutating half: one tree of eight components (c1–c8) for one scope. Formerly "harness tree". |
70
71
  | **Component** | One of c1–c8 inside a variant (system prompt, guardrails, memory, tool guidance, subagents, skills, scripts, plugins). |
@@ -86,29 +87,29 @@ Every coding agent and contributor follows these steps.
86
87
  2. **Within the spec: just do it.** If the change fits every contract and invariant, make it. If it
87
88
  adds detail without changing a rule (a new server method in an existing group, a new optional
88
89
  field), update the page in the same commit.
89
- 3. **Outside the spec: propose and stop.** If the change would alter a contract, an invariant, a
90
- layer boundary, an extension point, or the storage layout, do not change code or pages yet.
91
- Write `proposals/PROP-NNNN-<slug>.md` from the [template](proposals/README.md#template) with
92
- status `Proposed`, add it to the proposals index, and ask the user to review it.
93
- 4. **After approval.** The user sets or confirms status `Accepted`. Then implement it, update the
94
- affected pages in the same change, and add an ADR in `../decisions/` when the choice is a
95
- lasting one. A rejected proposal keeps its file with status `Rejected`.
90
+ 3. **Outside the spec: implement and update.** If the change alters a contract, an invariant, a
91
+ layer boundary, an extension point, or the storage layout, implement the requested change and
92
+ update affected pages in the same change. A proposal may document the design, but is optional
93
+ and does not gate implementation.
94
+ 4. **Record lasting decisions.** Add an ADR in `../decisions/` when the choice is a lasting one.
95
+ Proposals may be added to the index when useful; no `Accepted` status is required before work.
96
96
  5. **Drift is reported, not fixed silently.** If code and a page already disagree, add the item to
97
- [Known drift](#known-drift) and tell the user. Do not change either side to match without
98
- asking; resolving drift that changes a rule is itself a proposal.
97
+ [Known drift](#known-drift) and tell the user. When resolving drift within the requested scope,
98
+ update the code and spec together and record the rationale; do not silently change unrelated
99
+ behavior.
99
100
 
100
- When unsure whether a change alters the architecture, treat it as if it does and write the
101
- proposal.
101
+ When unsure whether a change alters the architecture, read the affected pages and update them in
102
+ the same change. Use a proposal only when it helps explain the design.
102
103
 
103
104
  ## Known drift
104
105
 
105
- Disagreements found while writing this specification. Each needs a decision from the user (a
106
- proposal, or a correction to the other document).
106
+ Disagreements found while writing this specification. Record their evidence here and report them;
107
+ resolve relevant drift by updating the implementation and specification together in the same change.
107
108
 
108
109
  | ID | Where | What disagrees |
109
110
  |---|---|---|
110
111
  | D-1 | `AGENTS.md` (before this spec), `INV-RUN-6` | The old rule said only `sessions/runStore.ts` writes `runs/<id>/`. In code, four other harness modules also write side files there: `prompt/compile.ts` (`context.json`), `sessions/sessions.ts` (`caller.json`), `capabilities/runSnapshot.ts` (`capabilities.json`), `mcp/service.ts` (`mcp-context.json`). The spec states the rule the code keeps (see `INV-RUN-6`); whether to route all of them through `runStore.ts` is open. |
111
- | D-2 | `README.md` "Plugins" | Describes a `plugin_propose` tool and an Inbox for proposed plugins. No such tool exists in `src/`. |
112
+ | D-2 | Plugin proposal review surfaces | `plugin_propose` and hash-bound proposal APIs now exist; a terminal review UI is pending and no App review UI is claimed. See [PAR-017](../parity.md#gaps). |
112
113
  | D-3 | `README.md` "External curation" | Describes `externalMaintenance`, `vaultAccess`, `MAINTENANCE_PLUGIN`, `maintenance.*` methods and tools. None exist in `src/`. |
113
114
  | D-4 | `INV-BND-2` | Several names carry an application's name: the context message type `xingular-context`, the approval extension `xagent-approvals`, the MCP client name `xagent`, and the terminal commands `xagent-wiki` / `xagent-mcp`. The default product name `Xingular Agent` is allowed; these are not. |
114
115
  | D-5 | `INV-BND-2` | `RunRecord` carries `worktreeId` and `handoffId`, which are application concepts. They are stored and returned, never read, and are documented as the application's fields. Since PROP-0016 (2026-10-23) `worktreeId` has Harness meaning when it names a registered worktree; only `handoffId` remains an application field. |
@@ -124,4 +125,5 @@ proposal, or a correction to the other document).
124
125
  | D-15 | Terminal sketch verification status — resolved 2026-10-24 by PROP-0028 | Pages 11 and 14 and `terminal-tui.md` said connected-sketch implementation verification was pending, while retained PTY evidence and PAR-014 recorded it as verified. Updated the docs to distinguish deterministic fixture verification from owner visual acceptance, every-emulator rendering and live-model sketch quality. |
125
126
  | D-16 | Terminal slash-command highlighting — resolved 2026-10-24 | `terminal-tui.md` specified accent coloring for recognized leading commands while typing, but the OpenTUI composer only styled attachment labels. User-message bubbles also lacked command-token styling. The renderer now uses the active command registry for both surfaces. |
126
127
  | D-17 | `PROP-0039`, `ADR-0036`, `INV-GATE-3/8` | Implementation is in progress in the 1.2.0 worktree: native writes revalidate canonical targets and atomically replace files under an OS write scope; default Bash fails closed on external hard-link aliases and runs in a sandbox that prevents new cross-boundary links; outside-scope Bash requires approval before one execution and command output never triggers approval or replay. The filesystem root is rejected as a workspace, and approval details expose the complete command. Launcher selection uses fixed system paths. Same-user peer processes remain outside this boundary. Focused macOS tests, full Harness CI, App compatibility checks, and PTY verification at 40x20, 80x24, and 100x30 pass. Linux sandbox integration remains unverified locally because this Darwin host has no `bwrap` and Colima is stopped; both CI workflows now install bubblewrap and `scripts/ci.sh` fails if it is absent, but an Ubuntu run is still required. No candidate, tag, or publication exists. |
128
+ | D-19 | Provider limits layout | Page 09 describes a centered Limits dialog; page 11 and `src/terminal/tui/pages/usagePage.ts` describe and implement a full-screen page. |
127
129
  | D-18 | `core/index.ts` migration 5 | The `run_stats` table has no writer in the Harness. PROP-0042's `usage_requests` ledger is the analytics source; whether to drop the older table is open. |
@@ -9,6 +9,8 @@ affects: [02-sessions-and-runs.md, 06-plugins-and-capabilities.md, 07-tools-and-
9
9
 
10
10
  # PROP-0006: A run checklist the model writes, recorded as a run event
11
11
 
12
+ > Renamed to todo by [PROP-0045](PROP-0045-rename-checklist-to-todo.md). The names below are historical.
13
+
12
14
  ## Problem
13
15
 
14
16
  A run has no structured record of progress. `goal` on a run is opaque text, and plan mode ends
@@ -1,14 +1,18 @@
1
1
  ---
2
2
  id: PROP-0018
3
3
  title: Inspector-style page notes, a fix queue to the agent, and app windows as capture targets
4
- status: Implemented
4
+ status: Implemented; queue, three-button popover and page_notes_mark_fixed superseded by PROP-0048
5
5
  created: 2026-10-23
6
- updated: 2026-10-23
6
+ updated: 2026-10-27
7
7
  affects: [INV-STO-3, INV-SRV-1, 07-tools-and-gate.md, 10-server-protocol.md, 11-terminal.md, 12-storage.md, 13-world-tools.md, 14-surfaces-and-parity.md]
8
8
  ---
9
9
 
10
10
  # PROP-0018: Inspector, fix queue and app targets for page notes
11
11
 
12
+ > The fix queue, its three-button popover and `page_notes_mark_fixed` were replaced by
13
+ > [PROP-0048](PROP-0048-simple-annotate.md): a note is pending or sent, and the popover has Annotate
14
+ > and Annotate & send.
15
+
12
16
  Requested by the owner on 2026-10-23. They chose these four things:
13
17
  - the popover's three choices: Save, Queue, Send now
14
18
  - the popover drawn inside the page