@xingular/harness 1.1.1 → 1.3.1-unstable.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +36 -28
  3. package/dist/cli.js +10837 -6159
  4. package/dist/sdk/accounts/accounts.d.ts +27 -3
  5. package/dist/sdk/accounts/accounts.js +78 -24
  6. package/dist/sdk/accounts/secrets.d.ts +12 -0
  7. package/dist/sdk/accounts/secrets.js +114 -7
  8. package/dist/sdk/accounts/store.d.ts +26 -1
  9. package/dist/sdk/accounts/store.js +1 -1
  10. package/dist/sdk/agents/builtin.js +18 -4
  11. package/dist/sdk/agents/planResearch.d.ts +27 -0
  12. package/dist/sdk/agents/planResearch.js +82 -0
  13. package/dist/sdk/agents/profiles.d.ts +5 -1
  14. package/dist/sdk/agents/profiles.js +21 -5
  15. package/dist/sdk/annotations/pageScript.js +349 -48
  16. package/dist/sdk/annotations/part.js +34 -23
  17. package/dist/sdk/annotations/store.d.ts +7 -0
  18. package/dist/sdk/annotations/store.js +13 -5
  19. package/dist/sdk/browser/backend.d.ts +16 -0
  20. package/dist/sdk/browser/backend.js +17 -0
  21. package/dist/sdk/browser/contracts.d.ts +19 -0
  22. package/dist/sdk/browser/contracts.js +116 -0
  23. package/dist/sdk/browser/tools.d.ts +1 -4
  24. package/dist/sdk/browser/tools.js +14 -91
  25. package/dist/sdk/capabilities/runSnapshot.js +10 -4
  26. package/dist/sdk/cli.js +5 -4
  27. package/dist/sdk/commands/list.d.ts +3 -0
  28. package/dist/sdk/commands/list.js +75 -0
  29. package/dist/sdk/commands/registry.d.ts +258 -0
  30. package/dist/sdk/commands/registry.js +48 -0
  31. package/dist/sdk/commands/routes.d.ts +16 -0
  32. package/dist/sdk/commands/routes.js +33 -0
  33. package/dist/sdk/core/commandBudget.d.ts +23 -0
  34. package/dist/sdk/core/commandBudget.js +57 -0
  35. package/dist/sdk/core/index.js +17 -1
  36. package/dist/sdk/core/interactiveProfile.d.ts +46 -0
  37. package/dist/sdk/core/interactiveProfile.js +143 -0
  38. package/dist/sdk/core/shell.d.ts +20 -0
  39. package/dist/sdk/core/shell.js +73 -0
  40. package/dist/sdk/core/workspace.d.ts +13 -0
  41. package/dist/sdk/core/workspace.js +88 -0
  42. package/dist/sdk/core/workspaceBashTool.d.ts +20 -0
  43. package/dist/sdk/core/workspaceBashTool.js +50 -0
  44. package/dist/sdk/core/workspaceSandbox.d.ts +41 -0
  45. package/dist/sdk/core/workspaceSandbox.js +360 -0
  46. package/dist/sdk/core/workspaceWriteOperations.d.ts +33 -0
  47. package/dist/sdk/core/workspaceWriteOperations.js +224 -0
  48. package/dist/sdk/doctor/checks.js +71 -12
  49. package/dist/sdk/doctor/types.d.ts +2 -2
  50. package/dist/sdk/harness.d.ts +7 -0
  51. package/dist/sdk/harness.js +42 -2
  52. package/dist/sdk/hub/hub.js +5 -3
  53. package/dist/sdk/index.d.ts +8 -3
  54. package/dist/sdk/index.js +4 -1
  55. package/dist/sdk/pi/runtime.d.ts +2 -1
  56. package/dist/sdk/pi/runtime.js +2 -2
  57. package/dist/sdk/plugins/builtin.js +32 -15
  58. package/dist/sdk/plugins/builtinRegistry.d.ts +10 -3
  59. package/dist/sdk/plugins/builtinRegistry.js +30 -8
  60. package/dist/sdk/plugins/catalogue.js +2 -1
  61. package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
  62. package/dist/sdk/plugins/commandPrefix.js +21 -0
  63. package/dist/sdk/plugins/firstParty.d.ts +1 -1
  64. package/dist/sdk/plugins/firstParty.js +8 -2
  65. package/dist/sdk/plugins/install.d.ts +6 -2
  66. package/dist/sdk/plugins/install.js +29 -5
  67. package/dist/sdk/plugins/inventory.js +6 -5
  68. package/dist/sdk/plugins/manifest.d.ts +2 -0
  69. package/dist/sdk/plugins/manifest.js +2 -1
  70. package/dist/sdk/plugins/surfaces.d.ts +5 -0
  71. package/dist/sdk/plugins/surfaces.js +11 -0
  72. package/dist/sdk/plugins/types.d.ts +15 -0
  73. package/dist/sdk/prompt/compile.d.ts +14 -0
  74. package/dist/sdk/prompt/compile.js +65 -31
  75. package/dist/sdk/prompt/standard.d.ts +17 -0
  76. package/dist/sdk/prompt/standard.js +21 -0
  77. package/dist/sdk/server/methods.js +22 -2
  78. package/dist/sdk/server/remote.js +36 -11
  79. package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
  80. package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
  81. package/dist/sdk/sessions/continuation.d.ts +7 -2
  82. package/dist/sdk/sessions/continuation.js +11 -6
  83. package/dist/sdk/sessions/contracts.d.ts +190 -4
  84. package/dist/sdk/sessions/contracts.js +71 -8
  85. package/dist/sdk/sessions/control.d.ts +72 -0
  86. package/dist/sdk/sessions/control.js +158 -0
  87. package/dist/sdk/sessions/initialBash.d.ts +7 -0
  88. package/dist/sdk/sessions/initialBash.js +7 -0
  89. package/dist/sdk/sessions/planMode.d.ts +14 -3
  90. package/dist/sdk/sessions/planMode.js +74 -17
  91. package/dist/sdk/sessions/registry.d.ts +1 -1
  92. package/dist/sdk/sessions/registry.js +2 -2
  93. package/dist/sdk/sessions/runStore.d.ts +14 -0
  94. package/dist/sdk/sessions/runStore.js +38 -1
  95. package/dist/sdk/sessions/runner.d.ts +40 -2
  96. package/dist/sdk/sessions/runner.js +161 -13
  97. package/dist/sdk/sessions/sessions.d.ts +23 -3
  98. package/dist/sdk/sessions/sessions.js +225 -22
  99. package/dist/sdk/sessions/subagentService.d.ts +24 -0
  100. package/dist/sdk/sessions/subagentService.js +225 -26
  101. package/dist/sdk/sessions/subagents.d.ts +10 -1
  102. package/dist/sdk/sessions/subagents.js +4 -0
  103. package/dist/sdk/sessions/workSlice.d.ts +106 -0
  104. package/dist/sdk/sessions/workSlice.js +329 -0
  105. package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
  106. package/dist/sdk/sessions/workspaceBoundary.js +46 -0
  107. package/dist/sdk/terminal/browserControl.js +2 -1
  108. package/dist/sdk/terminal/controller.d.ts +31 -3
  109. package/dist/sdk/terminal/controller.js +81 -29
  110. package/dist/sdk/terminal/opentui/ansi.d.ts +25 -0
  111. package/dist/sdk/terminal/opentui/ansi.js +192 -0
  112. package/dist/sdk/terminal/opentui/model.d.ts +163 -0
  113. package/dist/sdk/terminal/opentui/model.js +482 -0
  114. package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +3 -3
  115. package/dist/sdk/terminal/opentui/subagentsWidget.js +7 -5
  116. package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
  117. package/dist/sdk/terminal/opentui/theme.js +88 -0
  118. package/dist/sdk/terminal/piExtension.d.ts +6 -1
  119. package/dist/sdk/terminal/piExtension.js +177 -63
  120. package/dist/sdk/terminal/standalone.d.ts +7 -0
  121. package/dist/sdk/terminal/standalone.js +72 -13
  122. package/dist/sdk/terminal/subagentMonitor.d.ts +28 -6
  123. package/dist/sdk/terminal/subagentMonitor.js +61 -9
  124. package/dist/sdk/terminal/terminals.d.ts +26 -2
  125. package/dist/sdk/terminal/terminals.js +325 -43
  126. package/dist/sdk/terminal/trajectory.d.ts +6 -1
  127. package/dist/sdk/terminal/trajectory.js +8 -0
  128. package/dist/sdk/terminal/tui/annotateCommand.d.ts +1 -1
  129. package/dist/sdk/terminal/tui/annotateCommand.js +3 -3
  130. package/dist/sdk/terminal/tui/chrome.d.ts +4 -0
  131. package/dist/sdk/terminal/tui/chrome.js +13 -0
  132. package/dist/sdk/terminal/tui/commandPages.d.ts +3 -1
  133. package/dist/sdk/terminal/tui/commandPages.js +17 -4
  134. package/dist/sdk/terminal/tui/commands.d.ts +6 -0
  135. package/dist/sdk/terminal/tui/commands.js +213 -124
  136. package/dist/sdk/terminal/tui/list.d.ts +14 -1
  137. package/dist/sdk/terminal/tui/list.js +96 -14
  138. package/dist/sdk/terminal/tui/pageOverlay.js +21 -5
  139. package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +1 -1
  140. package/dist/sdk/terminal/tui/pages/browserPage.js +5 -4
  141. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +14 -1
  142. package/dist/sdk/terminal/tui/pages/hubPage.js +192 -28
  143. package/dist/sdk/terminal/tui/pages/notesPage.d.ts +5 -5
  144. package/dist/sdk/terminal/tui/pages/notesPage.js +18 -18
  145. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +8 -6
  146. package/dist/sdk/terminal/tui/pages/pluginsPage.js +206 -28
  147. package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +1 -0
  148. package/dist/sdk/terminal/tui/pages/subagentsPage.js +104 -19
  149. package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
  150. package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
  151. package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
  152. package/dist/sdk/terminal/tui/piAdapter.js +3 -5
  153. package/dist/sdk/terminal/tui/pluginCommands.d.ts +2 -0
  154. package/dist/sdk/terminal/tui/pluginCommands.js +13 -9
  155. package/dist/sdk/terminal/tui/runtime.js +23 -3
  156. package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
  157. package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
  158. package/dist/sdk/tools/checkpoint.d.ts +27 -0
  159. package/dist/sdk/tools/checkpoint.js +154 -0
  160. package/dist/sdk/tools/getCapabilities.d.ts +31 -0
  161. package/dist/sdk/tools/getCapabilities.js +34 -0
  162. package/dist/sdk/tools/sessionName.d.ts +2 -0
  163. package/dist/sdk/tools/sessionName.js +5 -3
  164. package/dist/sdk/tools/spawnSubagent.js +11 -8
  165. package/dist/sdk/tools/todo.d.ts +15 -0
  166. package/dist/sdk/tools/todo.js +64 -0
  167. package/dist/sdk/usage/analytics.d.ts +20 -0
  168. package/dist/sdk/usage/analytics.js +151 -0
  169. package/dist/sdk/usage/ledger.d.ts +38 -0
  170. package/dist/sdk/usage/ledger.js +142 -0
  171. package/dist/sdk/usage/limits/adapters.d.ts +11 -0
  172. package/dist/sdk/usage/limits/adapters.js +349 -0
  173. package/dist/sdk/usage/limits/capture.d.ts +8 -0
  174. package/dist/sdk/usage/limits/capture.js +47 -0
  175. package/dist/sdk/usage/limits/http.d.ts +12 -0
  176. package/dist/sdk/usage/limits/http.js +51 -0
  177. package/dist/sdk/usage/limits/normalize.d.ts +15 -0
  178. package/dist/sdk/usage/limits/normalize.js +211 -0
  179. package/dist/sdk/usage/limits/service.d.ts +30 -0
  180. package/dist/sdk/usage/limits/service.js +176 -0
  181. package/dist/sdk/usage/limits/types.d.ts +65 -0
  182. package/dist/sdk/usage/limits/types.js +1 -0
  183. package/dist/sdk/usage/serverMethods.d.ts +3 -0
  184. package/dist/sdk/usage/serverMethods.js +22 -0
  185. package/dist/sdk/usage/service.d.ts +32 -0
  186. package/dist/sdk/usage/service.js +66 -0
  187. package/dist/sdk/usage/settings.d.ts +7 -0
  188. package/dist/sdk/usage/settings.js +28 -0
  189. package/dist/sdk/usage/types.d.ts +60 -0
  190. package/dist/sdk/usage/types.js +4 -0
  191. package/dist/terminal-opentui.js +9204 -4812
  192. package/dist/terminal-pi.js +1848 -272
  193. package/docs/architecture/00-overview.md +1 -1
  194. package/docs/architecture/01-extension-points.md +1 -1
  195. package/docs/architecture/02-sessions-and-runs.md +169 -36
  196. package/docs/architecture/04-prompt.md +55 -15
  197. package/docs/architecture/06-plugins-and-capabilities.md +36 -15
  198. package/docs/architecture/07-tools-and-gate.md +131 -25
  199. package/docs/architecture/08-memory-and-history.md +4 -2
  200. package/docs/architecture/09-accounts-and-connectors.md +39 -3
  201. package/docs/architecture/10-server-protocol.md +71 -9
  202. package/docs/architecture/11-terminal.md +148 -60
  203. package/docs/architecture/12-storage.md +30 -2
  204. package/docs/architecture/13-world-tools.md +22 -1
  205. package/docs/architecture/14-surfaces-and-parity.md +58 -8
  206. package/docs/architecture/README.md +20 -17
  207. package/docs/architecture/proposals/PROP-0006-run-checklist.md +2 -0
  208. package/docs/architecture/proposals/PROP-0017-page-annotations.md +6 -2
  209. package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +1 -1
  210. package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
  211. package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
  212. package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
  213. package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
  214. package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
  215. package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
  216. package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
  217. package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
  218. package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
  219. package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
  220. package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +258 -0
  221. package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
  222. package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
  223. package/docs/architecture/proposals/PROP-0044-work-slice-defaults.md +93 -0
  224. package/docs/architecture/proposals/PROP-0045-rename-checklist-to-todo.md +132 -0
  225. package/docs/architecture/proposals/PROP-0046-progress-aware-stall-guards.md +82 -0
  226. package/docs/architecture/proposals/PROP-0047-plugins-hub-separation.md +122 -0
  227. package/docs/architecture/proposals/README.md +24 -6
  228. package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
  229. package/docs/decisions/ADR-0021-required-command-namespaces.md +1 -1
  230. package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
  231. package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
  232. package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
  233. package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
  234. package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
  235. package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
  236. package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
  237. package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
  238. package/docs/decisions/ADR-0039-progress-aware-stall-guards.md +39 -0
  239. package/docs/decisions/ADR-0040-architecture-change-workflow.md +31 -0
  240. package/docs/decisions/ADR-0041-plugins-hub-separation.md +41 -0
  241. package/docs/decisions/ADR-0042-windows-shell-without-sandbox.md +40 -0
  242. package/docs/decisions/ADR-0043-parents-continue-stopped-subagents.md +49 -0
  243. package/docs/doctor.md +14 -1
  244. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
  245. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
  246. package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
  247. package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
  248. package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
  249. package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
  250. package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
  251. package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
  252. package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
  253. package/docs/parity.md +83 -27
  254. package/docs/releases/1.1.1.md +28 -0
  255. package/docs/releases/1.2.0.md +49 -0
  256. package/docs/releases/1.3.0.md +21 -0
  257. package/docs/releases/4.0.0.md +10 -9
  258. package/docs/releases/README.md +35 -30
  259. package/docs/study/00-index.md +3 -0
  260. package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
  261. package/docs/terminal-tui.md +162 -82
  262. package/package.json +4 -3
  263. package/dist/sdk/tools/checklist.d.ts +0 -9
  264. package/dist/sdk/tools/checklist.js +0 -54
@@ -134,7 +134,7 @@ Modules with no member of their own: `variant/` (functions over the variant stor
134
134
  | Letter | The harness owns |
135
135
  |---|---|
136
136
  | **E** Execution | Isolated account folders, the Pi session, the terminal launch spec |
137
- | **T** Tools | History, trajectory, Wiki notes, skill loading, `ask_user`, the run checklist, the connected-apps broker, the tool gate |
137
+ | **T** Tools | History, trajectory, Wiki notes, skill loading, `ask_user`, the run todo list, the connected-apps broker, the tool gate |
138
138
  | **C** Context | The compiler, stable prefix and updates, the versioned variant (c1–c8), skills, on-demand Wiki notes |
139
139
  | **L** Lifecycle | Run state, interrupt, recovery, approvals and questions, subagents, refinement |
140
140
  | **O** Observability | Validated run events saved per run; usage counters |
@@ -50,7 +50,7 @@ harness forwards to the policy and never reads.
50
50
  ## Invariants
51
51
 
52
52
  - **INV-EXT-1** There are seven extension points. Adding, removing or changing the shape of one is
53
- an architecture change (proposal required).
53
+ an architecture change; update this page and affected contracts in the same change.
54
54
  - **INV-EXT-2** Every extension point is optional. The harness runs with none of them supplied.
55
55
  - **INV-EXT-3** An extension point carries data or decisions the application owns. It never
56
56
  carries an application's name or a branch for one application (`INV-BND-3`).
@@ -13,6 +13,7 @@ records everything the run does as validated events.
13
13
  |---|---|---|
14
14
  | `Sessions` | `sessions/sessions.ts` | Starts a turn: `run(input: SessionRunInput)`, `provide(provider)`. Builds the gate. |
15
15
  | `runTurn`, `piSessionFactory`, `loadResources` | `sessions/runner.ts` | Opens the Pi session, loads resources in a fixed order, streams events, settles the run. |
16
+ | compaction checkpoint | `sessions/compactionCheckpoint.ts` | Restores the active request's bounded goal, todo list and plan instructions to model context after compaction. |
16
17
  | `RunRegistry`, `ActiveRun` | `sessions/registry.ts` | Live runs: `emit`, `requestApproval`, `requestAnswer(s)`, `onInterrupt`, `onSteer`, `finish`; `listen` for observers. |
17
18
  | run store functions | `sessions/runStore.ts` | `saveRun`, `updateRun`, `persistEvent`, `appendEvent`, `readEvents`, `markInterruptedRuns`, `runFamily`, `listRuns`. |
18
19
  | `RunRecord`, `RunEvent`, schemas | `sessions/contracts.ts` | The one contract every session shares. |
@@ -27,15 +28,18 @@ records everything the run does as validated events.
27
28
 
28
29
  1. Validate the input (`run.id`, `sessionId`, `text`; an `initialBashCommand` only on a new
29
30
  interactive user turn).
30
- 2. Select the native history (`selectHistory`) and resolve the account (`accounts.resolve`).
31
+ 2. Resolve a continuation when requested; reuse its pinned root or derive one from its recorded
32
+ working directory. For a new run, resolve and pin the root from the effective `cwd` (after
33
+ worktree selection). Select the native history (`selectHistory`) and resolve the account
34
+ (`accounts.resolve`).
31
35
  3. Resolve the caller's capabilities, intersect with any narrower requested set, and **freeze**
32
36
  them for the run (`capabilities/runSnapshot.ts::freezeRun`).
33
37
  4. **Pin** the variant once (`variant/materialise.ts::materialise`).
34
38
  5. `saveRun` with status `queued`, the account, `harnessScope` and `harnessVersion`.
35
39
  6. Compile the prompt (`sessionLaunch`, page 04): a stable system prompt and an optional context
36
40
  update.
37
- 7. `runs.start` the live run; build the tool list (broker, harness tools, the plan-eligible
38
- `ask_user`, subagent tools, provider tools) and the gate.
41
+ 7. `runs.start` the live run; build the tool list (broker, Harness tools including read-only
42
+ `get_capabilities`, the plan-eligible `ask_user`, subagent tools, provider tools) and the gate.
39
43
  8. Open Pi through the `SessionFactory`, with resources loaded in order: disk extensions chosen by
40
44
  the harness, variant extensions, inline extensions, and the gate last.
41
45
  9. Record `nativeSessionId`, register the run with `Subagents`, start `runTurn`, and return
@@ -51,9 +55,17 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
51
55
  `message.completed`, `message.steered`, `tool.started`, `tool.completed`, `retry.started`,
52
56
  `retry.ended`, `compaction.started`, `compaction.ended`, `approval.requested`,
53
57
  `approval.resolved`, `question.requested`, `question.answered`, `extension.notice`,
54
- `reaction.added`, `agent.message`, `checklist.updated`, `artifact.added`, `file.changed`, `usage.updated`,
58
+ `reaction.added`, `agent.message`, `todo.updated`, `artifact.added`, `file.changed`, `usage.updated`,
55
59
  `account.status`, `status.changed`, `failed`, `completed`. Each has a payload schema in
56
60
  `runEventPayloadSchemas`.
61
+ - **Workspace root** (`RunRecord.workspaceRoot`) is the canonical root whose filesystem effects
62
+ native writes and default-scope Bash may modify: the nearest Git repository or worktree above its
63
+ effective working directory, otherwise that canonical directory. New runs pin it; continuations
64
+ reuse it. Older records may omit it, in which case a continuation derives it from the recorded
65
+ `workingDirectory`. The filesystem root itself cannot be selected as a workspace, because it
66
+ would collapse the write boundary. Native writes revalidate the target and atomically replace it
67
+ inside an OS write scope; Bash scans for external hard-link aliases and runs in the same pinned
68
+ boundary (page 07).
57
69
  - **Question sketches** (PROP-0025, ADR-0026; originally PROP-0024, ADR-0025). `question.requested` may include `uiSketch: true`
58
70
  and `sketch` text on each choice. If enabled, every choice must have a sketch; otherwise no
59
71
  choice may carry one. A sketch is 1–24 LF-separated lines, at most 80 printable ASCII characters
@@ -64,9 +76,10 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
64
76
  across alternatives; generation quality is guidance, not a schema guarantee. Old events remain
65
77
  valid without a data rewrite; readers with the old bounds must update before accepting larger
66
78
  sketches. `question.answered` and `QuestionAnswer` are unchanged.
67
- - **Checklist** (PROP-0006): `checklist.updated` carries the whole list the model last wrote with
68
- `checklist_write`, `{ items: { text, status: pending | in_progress | completed }[] }`, at most 50
69
- items. The latest event replaces every earlier one; `checklistOf(events)` reads it.
79
+ - **Todo list** (PROP-0006, renamed by PROP-0045): `todo.updated` carries the whole list the model
80
+ last wrote with `todo_write`, `{ items: { text, status: pending | in_progress | completed }[] }`, at
81
+ most 50 items. The latest event replaces every earlier one; `todoOf(events)` reads it. The
82
+ pre-rename `checklist.updated` is still read so old runs keep their list, and is never written.
70
83
  - **`RunRecord`** fields are listed in `sessions/contracts.ts`. `mode`, `harness`, `sessionType`,
71
84
  `worktreeId`, `attachmentCount`, `exitCode`, `handoffId` and `trigger` belong to the
72
85
  application: stored and returned, and only `mode` and `trigger` are read.
@@ -85,23 +98,50 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
85
98
  `results` for the host (`sessions.spawnSubagent` is a compatibility alias). Child runs have
86
99
  `relation: 'subagent'` and `parentRunId`. Nesting defaults to 1, at most 3 (`subagentDepth`).
87
100
  The child's record carries `title`, the short name the parent gave it (PROP-0030).
101
+ `spawn_subagent { continue: <runId> }` (`subagents.spawn { continue }`) continues a child that
102
+ stopped before finishing as a new child run with `continueFrom`. It reopens the first link's
103
+ history folder and keeps the earlier child's session id, profile, title, account, variant version
104
+ and frozen capability set, which must still lie within the parent's; `agent` and `tools` are
105
+ refused with it, and the newest link of a chain is the one continued (ADR-0043). Children an
106
+ earlier reply left stopped are delivered before the next reply's first request, each with a
107
+ note that it can be continued; a stopped child that was continued is reported through its
108
+ continuation. Every run record carries the launch `model` and `effort`, superseded by the model
109
+ the session opened with.
88
110
  - **Agent profiles** (PROP-0029). `agent` names a profile: built-in (`worker`, `explorer`),
89
111
  `<data root>/agents/<name>.md`, `<project>/.xingular/agents/<name>.md`, or a c5 definition of
90
112
  the parent's variant, later sources winning (`agents/profiles.ts`). A profile narrows the
91
113
  child's tools and plugins (`agents/narrow.ts`), may choose its variant, model and effort, and
92
114
  frames it with a "Your role" section. The child's record carries `profile`; the spawn result
93
- carries `agent` and any `unavailableTools`. A run that may spawn lists every profile in its
115
+ carries `agent` and any `unavailableTools`. `main` is reserved for the main agent's row: no
116
+ profile file or variant definition may take it. A run that may spawn lists every profile in its
94
117
  `subagents` section.
95
118
  - **Plan mode** (`plan: true`). The stable system prompt is unchanged. An attended plan run may
96
- include `ask_user`, subject to the caller's frozen capabilities; the gate refuses everything
97
- outside `PLAN_READ_ONLY_TOOLS`, provider tools marked `readOnly`, and calls a provider marks
98
- `planModeSafe`. The plan instruction arrives as a dynamic section; for UI-related plans it asks
99
- the model to explore distinct design directions, compare trade-offs and recommend one, using
100
- contextual `uiSketch` questions when helpful. The reply ends with one `<proposed_plan>` block.
119
+ include `ask_user` and `spawn_subagent` / `wait_subagents`, subject to the caller's frozen
120
+ capabilities. Delegation is limited to named profiles whose effective tool and plugin allowlists
121
+ qualify for read-only research; the child inherits plan mode and cannot write, run commands, ask
122
+ the user, use connectors or spawn children. The gate refuses unsafe calls before approvals and the
123
+ subagent service rechecks profile eligibility before launch. Other calls must be in
124
+ `PLAN_READ_ONLY_TOOLS` (including `get_capabilities` when frozen for the run), be provider tools
125
+ marked `readOnly`, or be explicitly classified by `planModeSafe`. Model-issued `bash` is allowed
126
+ and runs in the sandbox's read-only scope: no writes except a discarded temp folder, no network,
127
+ nothing that widens the scope; the gate refuses `outside` requests and `PLAN_BASH_DENIED` commands
128
+ (PROP-0043). The dynamic plan instruction
129
+ requires an opening `Goal` or `Summary`, evidence-grounded findings when useful, and task-scaled
130
+ steps and verification. A small fix stays concise without omitting its
131
+ outcome or check; cross-cutting work uses ordered steps. It uses alternatives only when requested
132
+ or materially useful; contextual `uiSketch` questions clarify real choices.
133
+ The reply ends with one `<proposed_plan>` block.
134
+ - **Compaction checkpoint** (PROP-0033, ADR-0032). After compaction, an active run's model context
135
+ receives a bounded, ephemeral checkpoint with the current user request and the latest validated
136
+ todo list or applicable plan instructions, when either is available to restore. It is re-added to
137
+ each request while that run continues;
138
+ its state is cleared when the run settles or the session branch changes. The message changes no
139
+ tools, permissions, run events or native history. An interrupted run still uses the durable
140
+ todo list and normal continuation path.
101
141
  - **Continuation** (PROP-0007). `continuationOf(root, runId, sessionDir?)` (`runs.continuation`)
102
142
  says whether a stopped run can be continued: `resumable`, a `reason` when not (`not_found`,
103
143
  `active`, `completed`, `no_history`, `history_missing`), the exact native history to reopen,
104
- the pinned account, variant version and capability set, the checklist, unanswered approvals and
144
+ the pinned account, variant version and capability set, the todo list, unanswered approvals and
105
145
  questions, the last tool and whether it finished, and subagents that did not finish.
106
146
  `SessionRunInput.continueFrom` starts a **new** run from it: it reopens that history, records
107
147
  `resumedFromRunId`, pins the same account, variant version and capability set (anything different
@@ -109,7 +149,8 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
109
149
  `continuation_unavailable`). If the earlier snapshot includes `ask_user`, an automatic or
110
150
  refinement-triggered continuation fails with `continuation_mismatch` rather than narrowing it.
111
151
  Empty text defaults to "Continue from where you stopped.", and the new run adds
112
- a dynamic `continuation` section (order 26) saying where the earlier run stopped. The next run
152
+ a dynamic `continuation` section (order 26) saying where the earlier run stopped and that its
153
+ unfinished subagents can be continued with `spawn_subagent { continue }`. The next run
113
154
  without `continueFrom` withdraws it. `Recovery.interruptedRunIds` lists the runs `open` marked
114
155
  interrupted.
115
156
  - **Worktrees** (PROP-0016). When `run.worktreeId` names a worktree in the Harness registry
@@ -120,18 +161,52 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
120
161
  - **Usage** (`usage.updated`). `inputTokens` is uncached input; `cacheReadTokens` and
121
162
  `cacheWriteTokens` are separate; `outputTokens` includes `reasoningTokens`. Totals are
122
163
  cumulative for the run, not the native session. `contextTokens` is the latest request's size.
164
+ The derived usage ledger (`usage_requests`, page 08) copies these requests for
165
+ `/usage:analysis`; run events remain the only source of truth.
166
+ - **Limit snapshots** (`account.status.limits`). A provider reading carries a window or balance,
167
+ its reset, and its source. It is produced by the usage limits service from provider response
168
+ headers or a documented provider endpoint (page 09), stored in the account's state, and never
169
+ inferred from a made-up cap.
123
170
  - **Provider reasoning summaries.** For supported Responses API families, when reasoning is
124
171
  enabled the runner requests a `detailed` summary and records only the provider's explicit summary
125
172
  (bounded to 4,000 characters) in request-level usage. This does not change reasoning effort or
126
173
  guarantee a provider will return a summary; raw reasoning is not used as a substitute.
127
174
 
175
+ ## Session controls and command runs (PROP-0040)
176
+
177
+ `commands/registry.ts` is the browser-safe core command catalogue, shared by front ends.
178
+ `commands.list` combines it with effective plugin, extension, prompt and skill routes (page 10).
179
+ A listed route is not proof that its surface passes acceptance.
180
+
181
+ `sessions/control.ts` owns saved-history operations: tree, navigation without a summary, fork,
182
+ clone, rename, last reply and JSONL export. A `SessionRef` names `sessionDir`, optional
183
+ `sessionFile` and optional `cwd`; the resolved JSONL must be inside that directory. Navigation
184
+ records a `xingular-navigation` entry; choosing a user message returns its text for editing and
185
+ moves before it. Fork and clone create history in an absolute `targetDir`.
186
+
187
+ `SessionRunInput.command` (also `TurnParams.command`) is one of:
188
+
189
+ - `{ name: 'compact', instructions? }`
190
+ - `{ name: 'navigate', entryId, summarize: boolean, instructions? }`
191
+ - `{ name: 'export', path }` (absolute `.html` path)
192
+
193
+ It replaces prompt submission and skips the normal context update. It requires saved history and
194
+ cannot combine with plan mode, continuation, automatic execution, initial Bash or images. It uses
195
+ normal account/variant/capability pins, events and cancellation. Front ends must fence history
196
+ mutations against active work; the current raw saved-history helpers do not themselves establish
197
+ that fence. Stable native entry IDs must connect host transcript projection to navigation/fork,
198
+ not positional message counts. A host can route `/history` to Harness `sessions.navigate` and
199
+ navigate the same saved session; it must not substitute a fork. Shared session catalog registration
200
+ is approved but remains in progress; no completed cross-surface catalog is implied (PAR-008).
201
+
128
202
  ## Invariants
129
203
 
130
- - **INV-RUN-1** A run pins one account, one variant version and one capability set when it
131
- starts. None of them changes during the run. A pinned account that cannot be used fails the
132
- run; it is never swapped (`INV-ACC-2`). A side-question run is the explicit exception for the
133
- variant: it pins no variant and uses the fixed Harness instruction plus a redacted main-run
134
- context projection (PROP-0019).
204
+ - **INV-RUN-1** A run pins one account, one variant version, one capability set and one canonical
205
+ `workspaceRoot` when it starts. None changes during the run. A continuation reuses the prior
206
+ root, deriving one from `workingDirectory` only for a legacy record without the field. A pinned
207
+ account that cannot be used fails the run; it is never swapped (`INV-ACC-2`). A side-question
208
+ run is the explicit exception for the variant: it pins no variant and uses the fixed Harness
209
+ instruction plus a redacted main-run context projection (PROP-0019).
135
210
  - **INV-RUN-2** A run's capability set is written once (`freezeRun`). A resumed or duplicate launch
136
211
  with a different set fails with `capabilities_frozen`. A child run's set is the intersection of
137
212
  its parent's, its profile's tools and plugins, and what it asked for; it never widens.
@@ -140,9 +215,14 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
140
215
  and never applied or relayed.
141
216
  - **INV-RUN-4** A restarted harness never restarts model work. On `open`, runs left active are
142
217
  marked `interrupted` unless another live process owns them (`owner.json`). Recovery of a
143
- subagent needs the same account, caller, working folder and history branch. Continuing is always
144
- a new run the application asks for with `continueFrom`; it pins the earlier run's account, variant
145
- version and capability set, and the earlier run's record is never reopened.
218
+ subagent needs the same account, caller, working folder and history branch; the history branch
219
+ (owner marker and native history id), not the host's session id, ties a parent to an earlier
220
+ one. A stopped subagent is continued only by its parent, through `spawn_subagent { continue }`. Continuing is always
221
+ a new run with `continueFrom`; it pins the earlier run's account, variant version and capability
222
+ set, and the earlier run's record is never reopened. The application asks for it, or the earlier
223
+ run's work-slice policy does when the reply stopped at its budget (PROP-0041); a run started
224
+ without a person (`automatic`), a plan, a subagent, a session command or a worktree never
225
+ continues itself.
146
226
  - **INV-RUN-5** Unattended runs (`automatic: true`) load no extension found on disk, read no
147
227
  context files, and never ask a person: anything that would need approval is refused. A variant's
148
228
  own trusted plugins still load, except for side-question runs, which have no variant or plugin
@@ -156,45 +236,98 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
156
236
  - **INV-RUN-7** Token accounting follows the usage contract above. Changing what a field means is
157
237
  an architecture change.
158
238
  - **INV-RUN-8** Plan mode keeps the stable system prompt but has mode-specific tools: an attended
159
- plan may include `ask_user`, subject to the frozen caller capabilities; newly resolved normal,
160
- automatic, probe, improver and reflection runs omit it. The terminal activates `ask_user` and
161
- `ask_user_question` only for a plan request, then restores its normal set. Plan refusals happen
162
- before approvals and no approval can lift them. Provider-cache effects of the tool-list difference
163
- are not assumed (page 04, `INV-PRM-8`).
239
+ plan may include `ask_user`, `spawn_subagent` and `wait_subagents`, subject to the frozen caller
240
+ capabilities; newly resolved normal, automatic, probe, improver and reflection runs omit
241
+ `ask_user`. Plan-mode spawning requires a named profile whose effective explicit tool and plugin
242
+ allowlists qualify for read-only research. The prompt lists only profiles whose intersection with
243
+ the parent's frozen tools and plugin contributions includes a research evidence tool. An omitted
244
+ `tools` override inherits that safe intersection; an explicit override can only narrow it. The
245
+ child inherits plan mode and is narrowed to the intersection of the parent's frozen capabilities,
246
+ the profile and the plan research set; it has no
247
+ connectors, user questions, writes, commands or nested subagents. The plan run itself may run
248
+ Bash only in the OS-enforced read-only scope (PROP-0043, ADR-0038); research children cannot run
249
+ commands. Generic browser actions and connected-app calls remain unavailable in plan mode. The
250
+ gate refuses unsafe calls before approvals, and the service rechecks before launch. The terminal activates plan-eligible
251
+ tools only for a plan request, then restores its normal set. Provider-cache effects of the tool-list
252
+ difference are not assumed (page 04, `INV-PRM-8`).
164
253
  - **INV-RUN-9** Subagent results reach the parent at native turn boundaries, at most once
165
254
  automatically (typed receipts in native history). A parent joins outstanding children before it
166
255
  completes.
167
256
  - **INV-RUN-10** An initial Bash command is allowed only on a new interactive user turn (not
168
- automatic, plan, resumed, continuing, relation, probe or improver runs), must match the leading `!` command
169
- in the text, and passes the same gate as model-issued Bash.
257
+ automatic, plan, resumed, continuing, relation, probe or improver runs), must match the leading `!`
258
+ command in the text, and passes the same gate as model-issued Bash. It is workspace-scoped by
259
+ default; the explicit terminal syntax `!outside <command>` requests the same human-only,
260
+ pre-execution outside-scope approval as the Bash tool and runs the command at most once.
170
261
  - **INV-RUN-11** A side-question run is independent, tool-free and temporary. It receives only a
171
262
  bounded, redacted projection of the main run's effective prompt and public events plus the
172
263
  surface's visible transcript and selected references. It excludes hidden reasoning and attachment
173
264
  bytes, never reads the main native history, and never changes or steers the parent. Its own run
174
265
  record and events use the normal store contract (PROP-0019).
266
+ - **INV-RUN-13** A reply is a bounded work slice (PROP-0041). The foundation defaults are 320 tool
267
+ calls and 60 minutes, whichever comes first, with no new-token limit (PROP-0044). A token cap is
268
+ available with `workSlice.maxNewTokens`, counted on new input, cache writes and output and never on
269
+ the cached prefix: a few large reads pass any small cap before useful work, so the tool calls and
270
+ the clock are the bound and the token count is only a ceiling for whoever asks for one. At the
271
+ limit the guard refuses the next tool call. When `checkpoint_write` is available, it requests a
272
+ checkpoint and leaves handoff calls callable; otherwise a plan-research child must stop with a
273
+ concise partial research report, and the runner derives a checkpoint from run evidence. A
274
+ non-handoff tool call after the refusal ends the reply. A budget-ended reply is `interrupted` with
275
+ terminal reason `slice_complete`; a reply ended by a stall guard is `stalled`.
276
+ The targeted stall guard identifies calls by name and every argument; three identical calls cause
277
+ one refusal, and a repeated trigger ends the reply. A Bash check that fails twice is a trigger. The
278
+ guard counts only successful native `edit`/`write` results (`isError === false`) with a path toward
279
+ the four-edit per-path churn limit; the next edit is refused, and a repeated trigger ends the
280
+ reply. Failed or blocked edits do not count. A successful edit/write clears failed-check counts,
281
+ identical Bash-check repeat counts and the pending nudge, but leaves edit counts and other
282
+ repeated-call counts intact. A passing check clears edit counts. The general 25-call file/check
283
+ no-progress trigger is removed. `todo_write` is bookkeeping: it is exempt from repeated-call
284
+ detection and does not reset loop state, but counts toward the tool-call budget. Third-compaction
285
+ thrash detection remains. Plan-research children without `checkpoint_write` receive the configured
286
+ bound without a new capability and do not auto-continue. A new run continues it only up to the
287
+ policy's slice cap, only after a slice that changed a file, passed a check or recorded a finished
288
+ item, and never after a checkpoint that is `blocked`. A run may turn the guard off with
289
+ `workSlice.enabled: false`, and a launch may set `XINGULAR_WORK_SLICE=off` for every run in that
290
+ process; with it off a reply has no boundary — no checkpoint, no continuation, no stall notes — and
291
+ ends only when the model stops or a person interrupts.
292
+ - **INV-RUN-14** A run event stream carries `checkpoint` (the handoff `checkpoint_write` records or
293
+ the harness derives from the run's own evidence when the model wrote none) and `heartbeat`
294
+ (steps, elapsed time, last tool, compactions, slice, and the call budget). A heartbeat older than
295
+ five minutes while the owner process lives marks the run `interrupted` with reason `stalled`; a
296
+ run that never emitted one keeps the 30-minute silence rule. The watchdog never restarts work.
297
+ - **INV-RUN-12** A post-compaction checkpoint is a bounded context projection of the active request,
298
+ the latest validated todo list and applicable plan instructions. It is compiled by
299
+ `prompt/compile.ts`, supplied only to model requests in the active run, and never persists hidden
300
+ reasoning or changes permissions, stable prompt text, native history or run-event schemas. Its
301
+ in-memory state is cleared when the run settles or the active session branch changes
302
+ (PROP-0033, ADR-0032).
175
303
 
176
304
  ## Data
177
305
 
178
- `<data root>/runs/<id>/`: `run.json`, `events.jsonl`, `owner.json`, `subagents.json`,
179
- `context.json`, `caller.json`, `capabilities.json`, `mcp-context.json`. Native history lives in
306
+ `<data root>/runs/<id>/`: `run.json` (including the optional, legacy-compatible `workspaceRoot`),
307
+ `events.jsonl`, `owner.json`, `subagents.json`, `context.json`, `caller.json`, `capabilities.json`,
308
+ `mcp-context.json`. Native history lives in
180
309
  the session directory the caller passes (`sessionDir`), owned by Pi. Side-question native history
181
310
  uses a one-use OS temporary directory, removed when the run settles; its tracked run and events
182
311
  remain in the ordinary run store.
183
312
 
184
313
  ## Source map
185
314
 
186
- `src/sessions/*.ts`, `src/capabilities/runSnapshot.ts`, `src/tools/spawnSubagent.ts`.
315
+ `src/sessions/*.ts`, `src/capabilities/runSnapshot.ts`, `src/core/workspaceBashTool.ts`,
316
+ `src/core/workspaceSandbox.ts`, `src/core/workspaceWriteOperations.ts`, `src/tools/spawnSubagent.ts`.
187
317
  Decisions: [ADR-0002](../decisions/ADR-0002-native-subagent-lifecycle.md) (superseded),
188
318
  [ADR-0003](../decisions/ADR-0003-shared-asynchronous-subagents.md),
189
319
  [ADR-0022](../decisions/ADR-0022-plan-only-question-tools.md),
190
320
  [ADR-0023](../decisions/ADR-0023-contextual-side-question-runs.md),
191
- [ADR-0026](../decisions/ADR-0026-contextual-question-wireframes.md).
321
+ [ADR-0026](../decisions/ADR-0026-contextual-question-wireframes.md),
322
+ [ADR-0033](../decisions/ADR-0033-plan-mode-research-delegation.md),
323
+ [ADR-0039](../decisions/ADR-0039-progress-aware-stall-guards.md).
192
324
 
193
325
  ## Native session names (PROP-0010)
194
326
 
195
327
  `session_name({ name: string })` adds or revises the current Pi session's name in embedded
196
- and terminal execution. The agent names meaningful work early and revises it when the overall
197
- objective changes, including a manual name. Agent-submitted names are imperative sentences
328
+ and terminal execution. The agent calls it once before its first other tool call when a request
329
+ needs tools or changes state, and revises it only when the overall objective changes, including a
330
+ manual name. Agent-submitted names are imperative sentences
198
331
  of at most six whitespace-separated words; whitespace is normalized, and empty names,
199
332
  terminal escapes, non-whitespace controls and longer names fail without writing. Identical
200
333
  names are a no-op. Pi's native session-info history is the only storage; continuation and
@@ -16,11 +16,13 @@ keeps provider caching effective across turns.
16
16
  | `render(env, pack)` → `string` | One string for a session that takes a single prompt. |
17
17
  | `sessionLaunch(env, caller, launch, historyFile, variant)` → `{ system, update, pack }` | SDK sessions: stable prefix plus an update with only the dynamic sections that changed since the last delivered snapshot. |
18
18
  | `deliveredSnapshot(sessionFile)` | Reads the last delivered snapshot on the active history branch; a compaction forces a fresh one. |
19
+ | `renderCompactionCheckpoint` | Compiles a bounded current-request, todo list and plan-state message for post-compaction model requests. |
19
20
  | `saveForSession`, `copyToRun` | Terminal sessions keep the pack they started with and copy it to each run. |
20
21
  | `record`, `load`, `packPath` | The pack each run was given, at `runs/<id>/context.json`. |
21
22
  | `toolGroups`, `fit`, `clip` | The tool manifest by group; cutting text to a budget at a paragraph boundary. |
22
23
 
23
- All in `prompt/compile.ts`. A `ContextPack` holds `sections: Section[]` (each with `id`, `title`,
24
+ Assembly is in `prompt/compile.ts`; shared standard-section data is in `prompt/standard.ts`.
25
+ A `ContextPack` holds `sections: Section[]` (each with `id`, `title`,
24
26
  `body`, `sources`, `budget`, `size`, `cut`), `toolGroups`, `harness` (scope and fingerprint),
25
27
  `profile`, `compiledAt` and `delivery` (`systemSectionIds`, `updatedSectionIds`).
26
28
 
@@ -29,14 +31,23 @@ All in `prompt/compile.ts`. A `ContextPack` holds `sections: Section[]` (each wi
29
31
  `SECTION_ORDER`: `harnessIdentity` 5, `system` 25, `guardrails` 40, `memory` 45, `references`
30
32
  50, `subagents` 64, `scripts` 66, `wiki` 80, `tools` 90, `reporting` 95. Application sections
31
33
  sit among them by their `order`; plan mode uses `plan` at 25. Ties keep insertion order.
32
- When a run may spawn, `subagents` lists every agent profile it can start (built-in, global,
33
- project and the variant's c5 names) and replaces the variant's own list (PROP-0029). The `tools`
34
- section has a Progress paragraph whenever `checklist_write` is available: it asks for a checklist
35
- early and kept current, because the person follows work from it (PROP-0006).
34
+ When a run may spawn, the dynamic `subagents` section lists every profile it can start (built-in,
35
+ global, project and variant c5 names) and replaces the variant's own list (PROP-0029). Normal-mode
36
+ guidance in that section explains when delegation is worth its overhead, profile selection,
37
+ self-contained briefs, independent parallel work, and parent ownership of integration. Plan mode
38
+ lists only effective profiles eligible for read-only research and requires a named profile; keeping
39
+ this section dynamic leaves the stable system prompt unchanged across modes. The `tools`
40
+ section has a Progress paragraph whenever `todo_write` is available: it asks for `todo_write` before
41
+ the first other tool call when work has several steps, asks for the list to stay current, then
42
+ requests a final update before the reply. Only fully completed work is
43
+ marked completed; unfinished or blocked steps remain accurate (PROP-0006).
36
44
 
37
45
  The fixed `harness-identity` section says `You are an AI agent running in <productName>.` and uses
38
- `env.productName` (default `Xingular Agent`). Host-provided identity and role sections remain
39
- separate, so an embedding application can still describe its agent and task.
46
+ `env.productName` (default `Xingular Agent`). `Launch.standard: { cwd, project?: { name } | null }` requests shared role and working-folder
47
+ sections from `prompt/standard.ts`; the compiler supplies common connections, file and annotation
48
+ guidance for the effective tools. Terminal preparation defaults to standard sections (explicit
49
+ `standard: null` opts out); the host interactive path requests the same sections. Hosts may add
50
+ attributed add-on and task context, not a duplicate standard role or connection policy (PROP-0040).
40
51
 
41
52
  Budgets (characters): variant sections 30,000 each (already capped at save, so never cut here);
42
53
  references 12,000; Wiki pointer 2,500; tools 8,000; reporting 2,000; application sections their
@@ -69,17 +80,34 @@ compile ──► pack ──► stable sections ──► system prompt (+ "Con
69
80
  `dynamic: true`.
70
81
  - An update lists only the dynamic sections that changed, and announces a withdrawn one.
71
82
  `references` is always resent when present, because it belongs to the current request.
83
+ - After successful compaction, the foundation checkpoint extension detects the compacted context and
84
+ uses `renderCompactionCheckpoint` to append one hidden, ephemeral context message to each model
85
+ request while the active run continues, when a todo list or applicable plan instructions exist.
86
+ It contains only the current request and available state. It is not written to native history, and its state is
87
+ discarded when the run settles or the branch changes.
72
88
  - The session appends the update as a hidden custom message and saves its snapshot in the
73
89
  message details (`xingularContext`); recording a pack does not mark it delivered.
74
90
  - Terminal sessions use `compile` + `render` once, pass it as `--append-system-prompt`, and keep
75
91
  that pack for the life of the session.
76
- - Read-only native file guidance states that absolute and `~` paths work when the operating system
77
- permits access, names the configured data root, and describes the working folder as a default
78
- location. Edits and commands remain subject to the gate.
92
+ - Native file guidance states that absolute and `~` paths work for reads when the operating
93
+ system permits access, names the configured data root, and describes the working folder as a
94
+ default location. Native writes and Bash filesystem effects default to the run's pinned project
95
+ or worktree root; outside file targets require one-call approval, and Bash is sandboxed unless
96
+ the eligible user explicitly enables Full Permission. Edits and commands remain subject to the
97
+ gate.
79
98
  - A side-question launch attributes its fixed no-tool instruction to the `side-questions` plugin.
80
99
  Its launch suppresses tool guidance entirely. The main run's effective prompt and current context
81
100
  update are included in the separately bounded, redacted context message (PROP-0019).
82
101
 
102
+ ## Launch parity status (2026-11-19)
103
+
104
+ Shared section generation is present in source; `surfaceParity.test.ts` checks compiler equality.
105
+ That does not verify actual prepared launches, registered schemas, credentials, variant pins or
106
+ provider-cache reuse. PROP-0040 also requires one Harness-owned interactive default for roots,
107
+ variant scope and credential backend. Adoption and runtime acceptance remain in progress; explicit
108
+ roots/scopes and continuation pins take precedence. Matching `--data` alone cannot reconcile a
109
+ file SecretStore with a host Keychain. See [parity](../parity.md).
110
+
83
111
  ## Invariants
84
112
 
85
113
  - **INV-PRM-1** The prompt is assembled only in `src/prompt/compile.ts`. Nothing else builds model
@@ -99,9 +127,20 @@ compile ──► pack ──► stable sections ──► system prompt (+ "Con
99
127
  - **INV-PRM-8** Whether a prompt or callable tool-list change keeps the provider's cache is measured
100
128
  with real requests from the application, only with the account owner's permission. Tests do not
101
129
  stand in for it.
102
- - **INV-PRM-9** Native file guidance describes the existing OS-permission boundary accurately:
103
- absolute and `~` paths are valid for read-only file tools; the working folder is not a sandbox.
104
- Side-question runs with no callable tools omit tool guidance.
130
+ - **INV-PRM-9** Native file guidance describes the boundary accurately: absolute and `~` paths
131
+ are valid for read-only file tools, which remain bounded by OS permissions rather than the
132
+ workspace root. Native file writes and Bash filesystem effects are workspace-scoped by default;
133
+ the working folder itself is not the boundary. Side-question runs with no callable tools omit
134
+ tool guidance.
135
+ - **INV-PRM-10** Compaction checkpoints are assembled by this compiler, bounded, and delivered only
136
+ as ephemeral context while their active run continues. They do not change the stable system prompt
137
+ or native history, and do not carry hidden reasoning (PROP-0033, ADR-0032). A work-slice handoff is
138
+ the same kind of bounded projection: the `checkpoint` event is rendered into the continuation
139
+ section by `continuationBody`, never into the system prompt (PROP-0041).
140
+ - **INV-PRM-11** The Progress group names `checkpoint_write` when it is in the frozen capability
141
+ set, with the same budget as the other tool guidance, and says only that a bounded reply records a
142
+ handoff when its budget is reached. It does not describe the limits themselves, which the guard
143
+ states at the boundary.
105
144
 
106
145
  ## Relation to DESIGN-0001
107
146
 
@@ -116,7 +155,8 @@ sections), `src/sessions/planMode.ts` (`plan` section).
116
155
 
117
156
  ## Session naming guidance (PROP-0010)
118
157
 
119
- The Session tool group describes `session_name` when available: name meaningful work early
120
- with an imperative sentence of at most six words, and revise when the objective changes.
158
+ The Session tool group describes `session_name` when available: call it once before the first
159
+ other tool call when a request needs tools or changes state, with an imperative sentence of at
160
+ most six words, and revise only when the objective changes.
121
161
  This is fixed foundation guidance. The current name stays in native session metadata and
122
162
  the terminal snapshot; it is never interpolated into the stable system prompt.
@@ -17,7 +17,7 @@ callable result for one run.
17
17
  | `Plugins` (`loading`, `loaded`) | `plugins/plugins.ts` | Chooses the paths a session or terminal loads; records what each extension registered. |
18
18
  | discovery | `plugins/discover.ts` | Finds items with Pi's own resolver, which runs no extension code. |
19
19
  | attachments (`load`, `save`, `attached`, `decided`, `set`) | `plugins/attachments.ts` | The one store of what is switched on, per scope. |
20
- | `BuiltinPluginRegistry`, `BuiltinPluginModule` | `plugins/builtinRegistry.ts`, `plugins/builtin.ts` | Registers built-in modules and their descriptors, world parts, server handlers and terminal command metadata. |
20
+ | `BuiltinPluginRegistry`, `BuiltinPluginModule` | `plugins/builtinRegistry.ts`, `plugins/builtin.ts` | Registers built-in modules and their descriptors, world parts, server handlers and plugin-owned terminal commands. Harness core commands live in `commands/registry.ts`, shared by both surfaces. |
21
21
  | `HARNESS_PLUGINS` | `plugins/builtin.ts` | Descriptor view of the registered Harness parts and feature plugins. |
22
22
  | `FIRST_PARTY_PLUGINS` | `plugins/firstParty.ts` | `output-trim`, `budget-guard`: inline extensions shipped switched off. `lessons`: switched off; its contribution turns on reflection after a run (page 08, PROP-0008) and loads no Pi code. |
23
23
  | `Hooks` | `plugins/hooks.ts` | Runs a package's hooks file after a write. |
@@ -29,14 +29,26 @@ callable result for one run.
29
29
  ## Contracts
30
30
 
31
31
  - **Loading.** `Plugins.loading({ cwd, agentDir, caller, contributions, install? })` returns
32
- `extensionPaths`, `skillPaths`, `promptPaths`, `themePaths`, `builtins` (terminal only), `hooks`,
32
+ `extensionPaths`, `skillPaths`, `promptPaths`, `themePaths`, `builtins` (legacy shape; no Pi CLI built-ins selected), `hooks`,
33
33
  `found`, `detached`, `projectCode`, `packageCode`. A session opens Pi with its own discovery off
34
34
  and only these paths; a terminal receives them as `--extension`, `--skill`,
35
35
  `--prompt-template` and `--theme` after `--no-extensions --no-skills --no-prompt-templates
36
36
  --no-themes`. Pi still reads `AGENTS.md` and `SYSTEM.md` itself.
37
+ - **Surface metadata (PROP-0040).** `PluginDescriptor.surfaces` and `Plugin.surfaces` optionally
38
+ carry `{ preferred: 'host', terminal: 'fallback' | 'unavailable', note: string }`.
39
+ `plugins/surfaces.ts` formats the note and badge. Inspection explains what the host adds and
40
+ what the terminal does instead; this is not a category, attachment switch or permission.
41
+ - **Shared resources (PROP-0040).** Both surfaces load Harness-selected resources and enabled
42
+ first-party hooks, including output trim and budget guard. Terminal preparation exposes these
43
+ through its protected bridge. Pi CLI-only llama.cpp, codemode, tool-search and MCP built-ins are
44
+ not selected or advertised as extra terminal capabilities. This does not remove Harness MCP.
37
45
  - **Attachments.** `config/plugin-attachments.json` holds `global`, `agents`, `projects` (each
38
46
  `{ on, off }`) and `settings` per plugin. The narrowest scope that says something wins: agent,
39
47
  then project, then everywhere. With no entry an item keeps its default.
48
+ - **Package metadata.** A Pi package may declare `"harness": { "extends": [...], "hooks": "./hooks.mjs", "commandPrefix": "my-tools" }`.
49
+ `commandPrefix` is optional; in the terminal, commands otherwise use a normalized package name as
50
+ their owner prefix. Prefixes use lowercase letters, digits and hyphens, starting with a letter;
51
+ `plugin` and `skill` are reserved. See page 11 for the command route and collision rules.
40
52
  - **Hooks.** A package declares `"harness": { "extends": [...], "hooks": "./hooks.mjs" }`. Events:
41
53
  `wiki.page.saved`, `history.run.ended`. A hook has 30 seconds; its errors are kept in
42
54
  `plugin-hooks.json`. `ctx.call(connection, tool, args)` reaches only a connected app that is on
@@ -48,7 +60,10 @@ callable result for one run.
48
60
  capability. Automatic or refinement-triggered continuations with it are rejected rather than
49
61
  weakening the frozen set. The `side-questions` descriptor owns the fixed instruction for the
50
62
  restricted side-question run; it has no tools, providers, connectors, subagents or variant code
51
- (PROP-0019).
63
+ (PROP-0019). In plan mode, delegation is limited to research children: the resolved profile must
64
+ have explicit tool and plugin allowlists confined to the research set, and the child's frozen
65
+ capabilities are intersected with the parent and profile. A profile name or its instructions alone
66
+ never grants eligibility (INV-RUN-8).
52
67
 
53
68
  ## Invariants
54
69
 
@@ -78,9 +93,11 @@ callable result for one run.
78
93
  parts are required and refuse to be switched off; switching something on grants no permission.
79
94
  A side-question run also has no variant plugin code or tool guidance (PROP-0019).
80
95
  - **INV-PLG-10** Every Harness-managed built-in feature is registered by `BuiltinPluginRegistry`.
81
- Its descriptor, world tools, server handlers and terminal command metadata share one owner. A
82
- module's world part releases resources through the existing session and Harness lifecycle. This
83
- registry does not load third-party Pi code or bypass its trust checks.
96
+ Its descriptor, world tools, server handlers and any plugin-owned terminal commands share one
97
+ owner. First-class Harness terminal commands are registered by the terminal command registry and
98
+ do not depend on a feature plugin's command metadata or attachment state. A module's world part
99
+ releases resources through the existing session and Harness lifecycle. This registry does not
100
+ load third-party Pi code or bypass its trust checks.
84
101
  - **INV-PLG-11** Built-in plugin categories are a documentation ownership taxonomy. They are not a
85
102
  `PluginDescriptor` field, a public response field or a second attachment scope.
86
103
  - **INV-CAP-1** A capability set only narrows. `intersect` never adds access; a run's set is
@@ -117,13 +134,17 @@ metadata or availability:
117
134
  | Foundation | Accounts, sessions and run recording, prompt and variant validation, gate, plugin loading/trust/attachments, resource browser, server and terminal frameworks | Release-owned infrastructure and security contracts |
118
135
  | World | Web search/read tools, browser tools, page annotations | The isolated browser engine and network policy remain Foundation services |
119
136
  | Memory | Wiki, history and trajectory | Storage and run records remain Foundation-owned services |
120
- | Automation | Subagents, ask-user, checklist, lessons and refinement | Run lifecycle, capability narrowing and approval gate remain Foundation-owned |
137
+ | Automation | Subagents, ask-user, todo, lessons and refinement | Run lifecycle, capability narrowing and approval gate remain Foundation-owned |
121
138
  | Integrations | Connected apps/MCP and Hub | Connector credentials and plugin installation remain behind Foundation services |
122
- | Operations | Doctor and worktrees | Diagnostics and repository operations remain Harness-managed services |
123
-
124
- ## Terminal resource inspection
125
-
126
- The unified browser joins saved plugin/contribution metadata with actual session skills and tool
127
- registration. A saved on/off state does not prove a resource loaded; origins and owners distinguish
128
- same-name resources. Protected install/remove, settings, attachment and trust actions call the
129
- existing services. No second discovery or enablement mechanism is introduced (PROP-0013).
139
+ | Operations | Doctor, worktrees and usage | Diagnostics, repository operations and usage analytics remain Harness-managed services |
140
+
141
+ ## Terminal plugin and resource inspection
142
+
143
+ The broad `/harness` browser joins saved plugin/contribution metadata with actual session skills and
144
+ tool registration. A saved on/off state does not prove a resource loaded; origins and owners
145
+ distinguish same-name resources. `/plugins` is a focused local manager with Plugins, Trust and
146
+ Packages tabs. It uses the existing plugin services for switching, trust, settings, package install,
147
+ update and removal. `/hub` is a distinct Community catalog surface; it does not load code or add a
148
+ second loader. Hub-owned package removal through `plugins.remove` delegates to Hub so the exact
149
+ receipt and its resources stay consistent. No second discovery or enablement mechanism is
150
+ introduced (PROP-0013, PROP-0047).