@xingular/harness 1.0.0 → 1.2.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 (397) hide show
  1. package/CHANGELOG.md +46 -5
  2. package/README.md +75 -21
  3. package/dist/cli.js +17421 -8711
  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.d.ts +2 -0
  11. package/dist/sdk/agents/builtin.js +48 -0
  12. package/dist/sdk/agents/narrow.d.ts +13 -0
  13. package/dist/sdk/agents/narrow.js +29 -0
  14. package/dist/sdk/agents/planResearch.d.ts +5 -0
  15. package/dist/sdk/agents/planResearch.js +19 -0
  16. package/dist/sdk/agents/profiles.d.ts +81 -0
  17. package/dist/sdk/agents/profiles.js +226 -0
  18. package/dist/sdk/annotations/bridge.d.ts +42 -0
  19. package/dist/sdk/annotations/bridge.js +264 -0
  20. package/dist/sdk/annotations/capture.d.ts +116 -0
  21. package/dist/sdk/annotations/capture.js +308 -0
  22. package/dist/sdk/annotations/delivery.d.ts +72 -0
  23. package/dist/sdk/annotations/delivery.js +130 -0
  24. package/dist/sdk/annotations/inspect.d.ts +10 -0
  25. package/dist/sdk/annotations/inspect.js +33 -0
  26. package/dist/sdk/annotations/isolated.d.ts +6 -0
  27. package/dist/sdk/annotations/isolated.js +51 -0
  28. package/dist/sdk/annotations/pageScript.d.ts +28 -0
  29. package/dist/sdk/annotations/pageScript.js +871 -0
  30. package/dist/sdk/annotations/part.d.ts +10 -0
  31. package/dist/sdk/annotations/part.js +155 -0
  32. package/dist/sdk/annotations/queue.d.ts +4 -0
  33. package/dist/sdk/annotations/queue.js +40 -0
  34. package/dist/sdk/annotations/serverMethods.d.ts +3 -0
  35. package/dist/sdk/annotations/serverMethods.js +62 -0
  36. package/dist/sdk/annotations/store.d.ts +167 -0
  37. package/dist/sdk/annotations/store.js +394 -0
  38. package/dist/sdk/browser/backend.d.ts +16 -0
  39. package/dist/sdk/browser/backend.js +17 -0
  40. package/dist/sdk/browser/contracts.d.ts +19 -0
  41. package/dist/sdk/browser/contracts.js +116 -0
  42. package/dist/sdk/browser/index.d.ts +14 -3
  43. package/dist/sdk/browser/index.js +11 -4
  44. package/dist/sdk/browser/serverMethods.d.ts +3 -0
  45. package/dist/sdk/browser/serverMethods.js +7 -0
  46. package/dist/sdk/browser/session.d.ts +1 -0
  47. package/dist/sdk/browser/session.js +45 -9
  48. package/dist/sdk/browser/tools.d.ts +1 -4
  49. package/dist/sdk/browser/tools.js +14 -91
  50. package/dist/sdk/cli.js +24 -15
  51. package/dist/sdk/commands/list.d.ts +3 -0
  52. package/dist/sdk/commands/list.js +75 -0
  53. package/dist/sdk/commands/registry.d.ts +250 -0
  54. package/dist/sdk/commands/registry.js +47 -0
  55. package/dist/sdk/commands/routes.d.ts +16 -0
  56. package/dist/sdk/commands/routes.js +33 -0
  57. package/dist/sdk/core/bus.js +1 -1
  58. package/dist/sdk/core/commandBudget.d.ts +23 -0
  59. package/dist/sdk/core/commandBudget.js +57 -0
  60. package/dist/sdk/core/env.d.ts +1 -1
  61. package/dist/sdk/core/env.js +1 -1
  62. package/dist/sdk/core/index.js +17 -1
  63. package/dist/sdk/core/interactiveProfile.d.ts +46 -0
  64. package/dist/sdk/core/interactiveProfile.js +143 -0
  65. package/dist/sdk/core/workspace.d.ts +13 -0
  66. package/dist/sdk/core/workspace.js +88 -0
  67. package/dist/sdk/core/workspaceBashTool.d.ts +4 -0
  68. package/dist/sdk/core/workspaceBashTool.js +36 -0
  69. package/dist/sdk/core/workspaceSandbox.d.ts +31 -0
  70. package/dist/sdk/core/workspaceSandbox.js +320 -0
  71. package/dist/sdk/core/workspaceWriteOperations.d.ts +22 -0
  72. package/dist/sdk/core/workspaceWriteOperations.js +206 -0
  73. package/dist/sdk/doctor/serverMethods.d.ts +3 -0
  74. package/dist/sdk/doctor/serverMethods.js +8 -0
  75. package/dist/sdk/doctor/types.d.ts +2 -2
  76. package/dist/sdk/harness.d.ts +22 -0
  77. package/dist/sdk/harness.js +84 -5
  78. package/dist/sdk/history/recall.js +8 -8
  79. package/dist/sdk/history/serverMethods.d.ts +3 -0
  80. package/dist/sdk/history/serverMethods.js +8 -0
  81. package/dist/sdk/hub/cli.d.ts +1 -1
  82. package/dist/sdk/hub/cli.js +1 -1
  83. package/dist/sdk/hub/schema.d.ts +1 -1
  84. package/dist/sdk/hub/serverMethods.d.ts +3 -0
  85. package/dist/sdk/hub/serverMethods.js +11 -0
  86. package/dist/sdk/index.d.ts +16 -1
  87. package/dist/sdk/index.js +10 -0
  88. package/dist/sdk/mcp/connections.js +14 -7
  89. package/dist/sdk/mcp/serverMethods.d.ts +3 -0
  90. package/dist/sdk/mcp/serverMethods.js +22 -0
  91. package/dist/sdk/pi/runtime.d.ts +2 -1
  92. package/dist/sdk/pi/runtime.js +2 -2
  93. package/dist/sdk/plugins/builtin.d.ts +1 -0
  94. package/dist/sdk/plugins/builtin.js +145 -33
  95. package/dist/sdk/plugins/builtinRegistry.d.ts +60 -0
  96. package/dist/sdk/plugins/builtinRegistry.js +71 -0
  97. package/dist/sdk/plugins/catalogue.js +2 -1
  98. package/dist/sdk/plugins/cli.d.ts +1 -1
  99. package/dist/sdk/plugins/cli.js +4 -3
  100. package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
  101. package/dist/sdk/plugins/commandPrefix.js +21 -0
  102. package/dist/sdk/plugins/firstParty.d.ts +1 -1
  103. package/dist/sdk/plugins/firstParty.js +8 -2
  104. package/dist/sdk/plugins/inventory.js +4 -3
  105. package/dist/sdk/plugins/manifest.d.ts +2 -0
  106. package/dist/sdk/plugins/manifest.js +2 -1
  107. package/dist/sdk/plugins/surfaces.d.ts +5 -0
  108. package/dist/sdk/plugins/surfaces.js +11 -0
  109. package/dist/sdk/plugins/types.d.ts +15 -0
  110. package/dist/sdk/prompt/compile.d.ts +19 -2
  111. package/dist/sdk/prompt/compile.js +79 -26
  112. package/dist/sdk/prompt/standard.d.ts +17 -0
  113. package/dist/sdk/prompt/standard.js +21 -0
  114. package/dist/sdk/refine/cli.d.ts +1 -1
  115. package/dist/sdk/refine/cli.js +2 -2
  116. package/dist/sdk/refine/serverMethods.d.ts +3 -0
  117. package/dist/sdk/refine/serverMethods.js +20 -0
  118. package/dist/sdk/server/methods.js +27 -86
  119. package/dist/sdk/server/params.d.ts +4 -0
  120. package/dist/sdk/server/params.js +11 -0
  121. package/dist/sdk/server/remote.js +36 -11
  122. package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
  123. package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
  124. package/dist/sdk/sessions/continuation.d.ts +3 -0
  125. package/dist/sdk/sessions/continuation.js +5 -1
  126. package/dist/sdk/sessions/contracts.d.ts +185 -0
  127. package/dist/sdk/sessions/contracts.js +101 -4
  128. package/dist/sdk/sessions/control.d.ts +72 -0
  129. package/dist/sdk/sessions/control.js +158 -0
  130. package/dist/sdk/sessions/initialBash.d.ts +7 -0
  131. package/dist/sdk/sessions/initialBash.js +7 -0
  132. package/dist/sdk/sessions/planMode.d.ts +18 -4
  133. package/dist/sdk/sessions/planMode.js +82 -16
  134. package/dist/sdk/sessions/reasoningSummaries.d.ts +2 -2
  135. package/dist/sdk/sessions/reasoningSummaries.js +3 -3
  136. package/dist/sdk/sessions/registry.d.ts +2 -1
  137. package/dist/sdk/sessions/registry.js +6 -3
  138. package/dist/sdk/sessions/runIndex.js +7 -7
  139. package/dist/sdk/sessions/runStore.d.ts +14 -0
  140. package/dist/sdk/sessions/runStore.js +38 -1
  141. package/dist/sdk/sessions/runner.d.ts +40 -2
  142. package/dist/sdk/sessions/runner.js +163 -15
  143. package/dist/sdk/sessions/sessions.d.ts +40 -8
  144. package/dist/sdk/sessions/sessions.js +279 -27
  145. package/dist/sdk/sessions/sideQuestionServerMethods.d.ts +3 -0
  146. package/dist/sdk/sessions/sideQuestionServerMethods.js +19 -0
  147. package/dist/sdk/sessions/sideQuestions.d.ts +66 -0
  148. package/dist/sdk/sessions/sideQuestions.js +290 -0
  149. package/dist/sdk/sessions/subagentServerMethods.d.ts +3 -0
  150. package/dist/sdk/sessions/subagentServerMethods.js +41 -0
  151. package/dist/sdk/sessions/subagentService.d.ts +22 -2
  152. package/dist/sdk/sessions/subagentService.js +93 -16
  153. package/dist/sdk/sessions/subagents.d.ts +9 -1
  154. package/dist/sdk/sessions/subagents.js +19 -0
  155. package/dist/sdk/sessions/workSlice.d.ts +103 -0
  156. package/dist/sdk/sessions/workSlice.js +297 -0
  157. package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
  158. package/dist/sdk/sessions/workspaceBoundary.js +46 -0
  159. package/dist/sdk/terminal/browser.d.ts +62 -0
  160. package/dist/sdk/terminal/browser.js +41 -0
  161. package/dist/sdk/terminal/browserControl.d.ts +29 -0
  162. package/dist/sdk/terminal/browserControl.js +187 -0
  163. package/dist/sdk/terminal/commandHelp.d.ts +17 -0
  164. package/dist/sdk/terminal/commandHelp.js +20 -0
  165. package/dist/sdk/terminal/controller.d.ts +15 -1
  166. package/dist/sdk/terminal/controller.js +67 -8
  167. package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +28 -0
  168. package/dist/sdk/terminal/opentui/subagentsWidget.js +52 -0
  169. package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
  170. package/dist/sdk/terminal/opentui/theme.js +87 -0
  171. package/dist/sdk/terminal/piExtension.d.ts +6 -1
  172. package/dist/sdk/terminal/piExtension.js +169 -84
  173. package/dist/sdk/terminal/socket.d.ts +6 -3
  174. package/dist/sdk/terminal/socket.js +40 -9
  175. package/dist/sdk/terminal/standalone.d.ts +9 -0
  176. package/dist/sdk/terminal/standalone.js +118 -19
  177. package/dist/sdk/terminal/subagentMonitor.d.ts +47 -0
  178. package/dist/sdk/terminal/subagentMonitor.js +152 -0
  179. package/dist/sdk/terminal/terminals.d.ts +60 -7
  180. package/dist/sdk/terminal/terminals.js +598 -47
  181. package/dist/sdk/terminal/trajectory.js +2 -2
  182. package/dist/sdk/terminal/tui/annotateCommand.d.ts +3 -0
  183. package/dist/sdk/terminal/tui/annotateCommand.js +22 -0
  184. package/dist/sdk/terminal/tui/commandPages.d.ts +7 -1
  185. package/dist/sdk/terminal/tui/commandPages.js +57 -6
  186. package/dist/sdk/terminal/tui/commands.d.ts +10 -4
  187. package/dist/sdk/terminal/tui/commands.js +269 -65
  188. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +2 -2
  189. package/dist/sdk/terminal/tui/dialogGeometry.js +4 -2
  190. package/dist/sdk/terminal/tui/dialogs.d.ts +6 -1
  191. package/dist/sdk/terminal/tui/dialogs.js +9 -2
  192. package/dist/sdk/terminal/tui/list.d.ts +14 -1
  193. package/dist/sdk/terminal/tui/list.js +96 -14
  194. package/dist/sdk/terminal/tui/modelPicker.js +1 -6
  195. package/dist/sdk/terminal/tui/page.d.ts +3 -0
  196. package/dist/sdk/terminal/tui/pageOverlay.js +27 -7
  197. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +26 -4
  198. package/dist/sdk/terminal/tui/pages/accountsPage.js +264 -36
  199. package/dist/sdk/terminal/tui/pages/agentsPage.d.ts +74 -0
  200. package/dist/sdk/terminal/tui/pages/agentsPage.js +190 -0
  201. package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +94 -0
  202. package/dist/sdk/terminal/tui/pages/annotatePage.js +341 -0
  203. package/dist/sdk/terminal/tui/pages/browserPage.d.ts +87 -0
  204. package/dist/sdk/terminal/tui/pages/browserPage.js +738 -0
  205. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +2 -0
  206. package/dist/sdk/terminal/tui/pages/doctorPage.js +103 -15
  207. package/dist/sdk/terminal/tui/pages/notesPage.d.ts +75 -0
  208. package/dist/sdk/terminal/tui/pages/notesPage.js +201 -0
  209. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +0 -5
  210. package/dist/sdk/terminal/tui/pages/pluginsPage.js +9 -3
  211. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +8 -0
  212. package/dist/sdk/terminal/tui/pages/settingsPage.js +16 -1
  213. package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +24 -0
  214. package/dist/sdk/terminal/tui/pages/subagentsPage.js +152 -0
  215. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +12 -5
  216. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +156 -83
  217. package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
  218. package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
  219. package/dist/sdk/terminal/tui/pages/worktreesPage.d.ts +72 -0
  220. package/dist/sdk/terminal/tui/pages/worktreesPage.js +203 -0
  221. package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
  222. package/dist/sdk/terminal/tui/piAdapter.js +3 -5
  223. package/dist/sdk/terminal/tui/planMode.d.ts +1 -1
  224. package/dist/sdk/terminal/tui/planMode.js +1 -1
  225. package/dist/sdk/terminal/tui/pluginCommands.d.ts +16 -0
  226. package/dist/sdk/terminal/tui/pluginCommands.js +31 -0
  227. package/dist/sdk/terminal/tui/questions.d.ts +2 -0
  228. package/dist/sdk/terminal/tui/runtime.js +27 -5
  229. package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
  230. package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
  231. package/dist/sdk/terminal/tui/settingsModel.d.ts +2 -0
  232. package/dist/sdk/terminal/tui/settingsModel.js +32 -2
  233. package/dist/sdk/terminal/tui/sideQuestion.d.ts +26 -26
  234. package/dist/sdk/terminal/tui/sideQuestion.js +131 -98
  235. package/dist/sdk/terminal/tui/ui.d.ts +2 -0
  236. package/dist/sdk/terminal/tui/ui.js +1 -0
  237. package/dist/sdk/tools/askUser.js +26 -8
  238. package/dist/sdk/tools/checklist.js +3 -2
  239. package/dist/sdk/tools/checkpoint.d.ts +27 -0
  240. package/dist/sdk/tools/checkpoint.js +154 -0
  241. package/dist/sdk/tools/getCapabilities.d.ts +31 -0
  242. package/dist/sdk/tools/getCapabilities.js +34 -0
  243. package/dist/sdk/tools/harnessTools.d.ts +2 -0
  244. package/dist/sdk/tools/harnessTools.js +1 -1
  245. package/dist/sdk/tools/spawnSubagent.js +14 -4
  246. package/dist/sdk/usage/analytics.d.ts +20 -0
  247. package/dist/sdk/usage/analytics.js +151 -0
  248. package/dist/sdk/usage/ledger.d.ts +38 -0
  249. package/dist/sdk/usage/ledger.js +142 -0
  250. package/dist/sdk/usage/limits/adapters.d.ts +11 -0
  251. package/dist/sdk/usage/limits/adapters.js +349 -0
  252. package/dist/sdk/usage/limits/capture.d.ts +8 -0
  253. package/dist/sdk/usage/limits/capture.js +47 -0
  254. package/dist/sdk/usage/limits/http.d.ts +12 -0
  255. package/dist/sdk/usage/limits/http.js +51 -0
  256. package/dist/sdk/usage/limits/normalize.d.ts +15 -0
  257. package/dist/sdk/usage/limits/normalize.js +211 -0
  258. package/dist/sdk/usage/limits/service.d.ts +30 -0
  259. package/dist/sdk/usage/limits/service.js +176 -0
  260. package/dist/sdk/usage/limits/types.d.ts +65 -0
  261. package/dist/sdk/usage/limits/types.js +1 -0
  262. package/dist/sdk/usage/serverMethods.d.ts +3 -0
  263. package/dist/sdk/usage/serverMethods.js +22 -0
  264. package/dist/sdk/usage/service.d.ts +32 -0
  265. package/dist/sdk/usage/service.js +66 -0
  266. package/dist/sdk/usage/settings.d.ts +7 -0
  267. package/dist/sdk/usage/settings.js +28 -0
  268. package/dist/sdk/usage/types.d.ts +60 -0
  269. package/dist/sdk/usage/types.js +4 -0
  270. package/dist/sdk/web/part.d.ts +10 -0
  271. package/dist/sdk/web/part.js +6 -0
  272. package/dist/sdk/web/serverMethods.d.ts +3 -0
  273. package/dist/sdk/web/serverMethods.js +7 -0
  274. package/dist/sdk/wiki/serverMethods.d.ts +3 -0
  275. package/dist/sdk/wiki/serverMethods.js +26 -0
  276. package/dist/sdk/worktrees/cli.d.ts +11 -0
  277. package/dist/sdk/worktrees/cli.js +146 -0
  278. package/dist/sdk/worktrees/copy.d.ts +9 -0
  279. package/dist/sdk/worktrees/copy.js +111 -0
  280. package/dist/sdk/worktrees/git.d.ts +16 -0
  281. package/dist/sdk/worktrees/git.js +81 -0
  282. package/dist/sdk/worktrees/serverMethods.d.ts +3 -0
  283. package/dist/sdk/worktrees/serverMethods.js +30 -0
  284. package/dist/sdk/worktrees/service.d.ts +73 -0
  285. package/dist/sdk/worktrees/service.js +483 -0
  286. package/dist/sdk/worktrees/setup.d.ts +23 -0
  287. package/dist/sdk/worktrees/setup.js +65 -0
  288. package/dist/sdk/worktrees/types.d.ts +91 -0
  289. package/dist/sdk/worktrees/types.js +1 -0
  290. package/dist/sdk/world/cli.d.ts +2 -2
  291. package/dist/sdk/world/cli.js +6 -6
  292. package/dist/sdk/world/world.d.ts +3 -1
  293. package/dist/sdk/world/world.js +8 -9
  294. package/dist/terminal-opentui.js +16456 -5966
  295. package/dist/terminal-pi.js +1579 -573
  296. package/docs/README.md +22 -2
  297. package/docs/architecture/00-overview.md +28 -16
  298. package/docs/architecture/02-sessions-and-runs.md +184 -25
  299. package/docs/architecture/03-variants.md +10 -2
  300. package/docs/architecture/04-prompt.md +65 -7
  301. package/docs/architecture/06-plugins-and-capabilities.md +57 -4
  302. package/docs/architecture/07-tools-and-gate.md +112 -17
  303. package/docs/architecture/08-memory-and-history.md +4 -2
  304. package/docs/architecture/09-accounts-and-connectors.md +39 -1
  305. package/docs/architecture/10-server-protocol.md +168 -4
  306. package/docs/architecture/11-terminal.md +251 -8
  307. package/docs/architecture/12-storage.md +45 -3
  308. package/docs/architecture/13-world-tools.md +49 -6
  309. package/docs/architecture/14-surfaces-and-parity.md +136 -0
  310. package/docs/architecture/README.md +17 -4
  311. package/docs/architecture/proposals/PROP-0006-run-checklist.md +4 -2
  312. package/docs/architecture/proposals/PROP-0013-resource-browser.md +58 -0
  313. package/docs/architecture/proposals/PROP-0014-fullscreen-browser-tabs.md +58 -0
  314. package/docs/architecture/proposals/PROP-0015-one-capability-surface.md +88 -0
  315. package/docs/architecture/proposals/PROP-0016-managed-worktrees.md +156 -0
  316. package/docs/architecture/proposals/PROP-0017-page-annotations.md +131 -0
  317. package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +179 -0
  318. package/docs/architecture/proposals/PROP-0019-contextual-side-questions.md +122 -0
  319. package/docs/architecture/proposals/PROP-0020-builtin-feature-plugins.md +105 -0
  320. package/docs/architecture/proposals/PROP-0021-command-namespaces-and-duplicates.md +99 -0
  321. package/docs/architecture/proposals/PROP-0022-plan-only-questions.md +102 -0
  322. package/docs/architecture/proposals/PROP-0023-xagent-cli-name.md +61 -0
  323. package/docs/architecture/proposals/PROP-0024-question-sketch-previews.md +130 -0
  324. package/docs/architecture/proposals/PROP-0025-contextual-question-wireframes.md +49 -0
  325. package/docs/architecture/proposals/PROP-0026-connected-sketch-display.md +94 -0
  326. package/docs/architecture/proposals/PROP-0027-xingular-agent-product-identity.md +60 -0
  327. package/docs/architecture/proposals/PROP-0028-normalize-question-wireframes.md +55 -0
  328. package/docs/architecture/proposals/PROP-0029-agent-profiles.md +124 -0
  329. package/docs/architecture/proposals/PROP-0030-subagent-title.md +86 -0
  330. package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
  331. package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
  332. package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
  333. package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
  334. package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
  335. package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
  336. package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
  337. package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
  338. package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
  339. package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
  340. package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +247 -0
  341. package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
  342. package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
  343. package/docs/architecture/proposals/README.md +39 -0
  344. package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
  345. package/docs/decisions/ADR-0009-xharness-command.md +6 -5
  346. package/docs/decisions/ADR-0014-public-release-baseline.md +3 -2
  347. package/docs/decisions/ADR-0015-resource-browser.md +28 -0
  348. package/docs/decisions/ADR-0016-fullscreen-browser-tabs.md +31 -0
  349. package/docs/decisions/ADR-0017-one-capability-surface.md +34 -0
  350. package/docs/decisions/ADR-0018-builtin-feature-plugins.md +35 -0
  351. package/docs/decisions/ADR-0019-managed-git-worktrees.md +31 -0
  352. package/docs/decisions/ADR-0020-page-annotations.md +37 -0
  353. package/docs/decisions/ADR-0021-required-command-namespaces.md +40 -0
  354. package/docs/decisions/ADR-0022-plan-only-question-tools.md +34 -0
  355. package/docs/decisions/ADR-0023-contextual-side-question-runs.md +35 -0
  356. package/docs/decisions/ADR-0024-xagent-command.md +40 -0
  357. package/docs/decisions/ADR-0025-question-choice-sketches.md +49 -0
  358. package/docs/decisions/ADR-0026-contextual-question-wireframes.md +58 -0
  359. package/docs/decisions/ADR-0027-connected-sketch-display.md +60 -0
  360. package/docs/decisions/ADR-0028-xingular-agent-product-identity.md +56 -0
  361. package/docs/decisions/ADR-0029-normalized-question-wireframe-borders.md +33 -0
  362. package/docs/decisions/ADR-0030-agent-profiles.md +43 -0
  363. package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
  364. package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
  365. package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
  366. package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
  367. package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
  368. package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
  369. package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
  370. package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
  371. package/docs/doctor.md +10 -4
  372. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
  373. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
  374. package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
  375. package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
  376. package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
  377. package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
  378. package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
  379. package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
  380. package/docs/features/README.md +26 -0
  381. package/docs/features/interfaces/README.md +1 -1
  382. package/docs/future-work.md +48 -0
  383. package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
  384. package/docs/parity.md +134 -0
  385. package/docs/releases/1.0.0.md +2 -2
  386. package/docs/releases/1.1.1.md +28 -0
  387. package/docs/releases/1.2.0.md +49 -0
  388. package/docs/releases/4.0.0.md +47 -0
  389. package/docs/releases/README.md +37 -27
  390. package/docs/study/00-index.md +8 -0
  391. package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
  392. package/docs/study/autonomous-engineering-sources.md +277 -0
  393. package/docs/study/autonomy-sources.md +147 -0
  394. package/docs/study/proactive-autonomy.md +408 -0
  395. package/docs/study/tui-resource-browser.md +78 -0
  396. package/docs/terminal-tui.md +386 -113
  397. package/package.json +6 -5
@@ -0,0 +1,59 @@
1
+ ---
2
+ id: PROP-0036
3
+ title: First-class Harness terminal commands
4
+ status: Implemented
5
+ created: 2026-10-25
6
+ updated: 2026-10-25
7
+ affects: [INV-PLG-10, INV-TUI-7, 06-plugins-and-capabilities.md, 11-terminal.md, 14-surfaces-and-parity.md, terminal-tui.md, parity, ADR-0031]
8
+ ---
9
+
10
+ # PROP-0036: First-class Harness terminal commands
11
+
12
+ ## Problem
13
+
14
+ Harness-owned pages for subagents, agent profiles, recorded-run inspection, diagnostics and worktrees are currently exposed through `BuiltinPluginRegistry` command metadata. This couples their terminal command namespace and discoverability to a feature-plugin registry even though these required features are not optional plugin toggles. It also makes ordinary Harness commands appear as plugin commands in help and completion.
15
+
16
+ Evidence: `src/plugins/builtin.ts` registers these commands on the `subagents`, `history`, `doctor` and `worktrees` modules; `src/terminal/tui/pluginCommands.ts` maps them to pages; `src/terminal/tui/commands.ts` builds canonical namespaced completion and dispatch from `BuiltinPluginRegistry`.
17
+
18
+ ## Affected rules
19
+
20
+ - **INV-PLG-10** currently couples a built-in feature's descriptor, tools, server methods and terminal command metadata to one registry owner. Plugin-owned commands should remain with their feature modules, but Harness core commands should be owned by the terminal's core command registry.
21
+ - **INV-TUI-7** requires every plugin-owned command to use an owner prefix. The commands in this proposal become Harness core commands, not plugin-owned commands; all other plugin and extension commands retain owner-qualified routes.
22
+ - **14 Surfaces and parity, Contracts** describes the current terminal command namespace. The command changes are presentation only and add no capability or server method.
23
+
24
+ ## Proposal
25
+
26
+ Register these routes directly in the core terminal command table and dispatch them to the existing Harness pages:
27
+
28
+ - `/doctor` opens readiness diagnostics.
29
+ - `/worktree` opens managed worktrees.
30
+ - `/trajectory [run-id]` opens recorded runs and events.
31
+ - `/subagents` opens the subagent roster; `/agents` opens agent profiles.
32
+
33
+ Keep `/history` (and its `/tree` alias) for session branch navigation. Keep `/mcp` and `/connections` as first-class entries into the Connections browser. All other core commands stay unprefixed. Plugin-owned built-in and extension commands continue to use `/<owner-prefix>:<command>`; annotations retain their `annotate` namespace and default route.
34
+
35
+ The `doctor`, `worktrees`, `history` and `subagents` feature descriptors remain registered and required. Their services, server methods, tools and capability behavior do not move. Only their terminal command metadata and dispatch move to the core command registry. Core commands reserve their names under the existing terminal command collision policy.
36
+
37
+ For one release, accept the prior owner-qualified and `/plugin:<command>` forms for the routes being promoted as hidden compatibility aliases. Do not show aliases in help or completion. Remove them after the compatibility release.
38
+
39
+ ## Alternatives
40
+
41
+ - Keep these routes under owner prefixes. Rejected: it keeps core terminal actions classified as plugin commands and exposes redundant namespaces for required Harness features.
42
+ - Remove the feature descriptors from `BuiltinPluginRegistry`. Rejected: those descriptors still own Harness tools, server methods and capability contributions; only terminal command ownership needs to change.
43
+ - Replace `/history` with the trajectory page. Rejected: `/history` already navigates the current session's branches. Keep it and expose the run trajectory as `/trajectory`.
44
+ - Do nothing. Rejected: help, completion and dispatch continue to treat these core pages as plugin-owned commands.
45
+
46
+ ## Consequences
47
+
48
+ Help, completion, slash recognition and dispatch use the core command table for the promoted commands. The `/mcp` command remains in that table and keeps its Connections behavior. Plugin command-prefix collision checks remain in force for plugin-owned commands. No capability set, server protocol, account data, run record or stored resource changes.
49
+
50
+ ## Migration
51
+
52
+ No stored-data migration. Accept the previous qualified forms as hidden aliases for one release; scripts and keybindings should use the bare canonical names. `/history` remains the branch picker and `/trajectory` is the recorded-run page.
53
+
54
+ ## Checks
55
+
56
+ - Registry and terminal tests cover bare routes, help, completion, slash recognition, compatibility aliases, prompt-name collisions, `/history`, `/mcp` and unchanged plugin namespace routing.
57
+ - Harness `npm run typecheck`, `npm test` (150 files; 1,143 passed, 3 skipped) and `npm run prove` passed.
58
+ - Xingular Agent `npm run typecheck`, `npm test` (App and sidecar suites: 634 passed; signing tests: 7 passed, 1 skipped), `npm run check:layers` and `cargo test` (167 passed, 1 ignored) passed.
59
+ - Isolated terminal PTY checks passed for `/help`, composer modes, and the `/trajectory` Runs/Events page. `/help` screen-layout assertions were skipped because optional `pyte` is unavailable.
@@ -0,0 +1,63 @@
1
+ ---
2
+ id: PROP-0037
3
+ title: Default filesystem writes to the active project workspace
4
+ status: Implemented
5
+ created: 2026-11-19
6
+ updated: 2026-11-19
7
+ affects: [INV-GATE-1, INV-GATE-3, INV-GATE-8, INV-RUN-1, INV-TUI-8, 02-sessions-and-runs.md, 04-prompt.md, 07-tools-and-gate.md, 10-server-protocol.md, 11-terminal.md, 12-storage.md, 14-surfaces-and-parity.md, parity]
8
+ ---
9
+
10
+ # PROP-0037: Default filesystem writes to the active project workspace
11
+
12
+ > **Implementation update:** This proposal records the original pathname-check and
13
+ > denial-triggered-retry design. Security review found those details bypassable; accepted
14
+ > [PROP-0039](PROP-0039-workspace-boundary-hardening.md) replaces them with operation-time atomic
15
+ > writes and explicit pre-execution outside-scope approval. Follow the current contracts in
16
+ > [07 Tools and the gate](../07-tools-and-gate.md) and [11 Terminal](../11-terminal.md).
17
+
18
+ ## Problem
19
+
20
+ Harness tells the model that read-only file tools can use any path the process can read, and that the working folder is not a repository boundary (`src/prompt/compile.ts`; `docs/architecture/07-tools-and-gate.md`, Native file paths). The same page says `edit`, `write` and `bash` pass through the existing gate and policy, but that gate has no built-in workspace-root rule. The SDK's `ToolPolicy` is optional, and the terminal's default approval flow is not a filesystem sandbox (`src/sessions/policy.ts`, `src/sessions/sessions.ts`, `src/terminal/terminals.ts`). Thus a session has no Harness-wide default that keeps model-initiated file mutations in its project.
21
+
22
+ ## Affected rules
23
+
24
+ - **INV-GATE-8**, as it stands: “Native read-only file access is bounded by process and operating-system permissions, not by the repository root. Absolute and `~` paths are valid inputs. This does not change the gate or permissions for writes and commands.” The first two sentences remain; the final sentence changes because the Harness will scope writes and shell file effects.
25
+ - **INV-GATE-3**, as it stands: “Order is fixed: capability and plan-mode refusals, then the policy's scope and authorize, then standing approvals, then the person, then authorize again.” The mandatory workspace check must join this ordering without allowing a host policy to silently broaden it; an approved one-call escape must be authorized before the operation runs.
26
+ - **INV-RUN-1**, as it stands: “A run pins one account, one variant version and one capability set when it starts. None of them changes during the run.” A run will also pin its resolved workspace-write root so a continuation or later filesystem change cannot silently widen its scope.
27
+ - **INV-TUI-8**, added by implementation: the terminal uses the same Harness-pinned root and workspace-write policy as SDK sessions; it cannot widen the boundary through its private socket or native extension.
28
+
29
+ ## Proposal
30
+
31
+ 1. **Preserve broad reads.** Read-only filesystem tools retain their existing process/OS-permission behavior. The write boundary applies to model-controlled filesystem mutations, not to reads.
32
+ 2. **Resolve one trusted workspace root per run.** After Harness has selected the effective `cwd` (including a managed worktree), resolve the nearest ancestor containing `.git`, canonicalize it, and store it as `RunRecord.workspaceRoot`. If there is no Git repository, use the canonical `cwd`. A worktree is its own active workspace. Do not infer the root from model-supplied tool arguments or an unvalidated `projectId`.
33
+ 3. **Default file writes to that root.** Native `edit` and `write` calls may mutate paths inside the root. Resolve paths canonically and reject symlink/path escapes. Paths outside it require approval for that operation. A per-tool remembered grant does not authorize an outside write.
34
+ 4. **Enforce shell writes, not just shell-call names.** Run model Bash—including the initial `!` command—under an OS-enforced workspace-write sandbox. Shell commands may read as before but may write only under `workspaceRoot`; `/tmp` and other external paths are outside the default write scope. A denied outside write produces a clear denial and a one-shot escalation path for that command. Approval reruns only that command with the wider access needed. Fail closed when workspace-mode enforcement is unavailable; never silently run it unconfined.
35
+ 5. **Use existing approval controls.** Outside writes require a person’s one-call approval. Mark the request human-only so remembered grants cannot answer it. The existing Full Permission switch may automatically grant this explicitly eligible escape; it is off by default. Preserve hard policy denials and the existing read-only, plan, unattended, probe, improver and reflection restrictions. Full Permission does not add tools or bypass those restrictions.
36
+ 6. **Keep artifacts in the project by default.** Files created for the task, including deliverables, belong inside the active workspace. Prefer an existing project convention such as `artifacts/` or `outputs/` when present; do not require or create a universal output folder. An explicitly approved outside write remains possible.
37
+ 7. **Make the policy Harness-owned and shared.** Apply the same root and decision in SDK sessions and the standalone terminal. Host `ToolPolicy` may impose stricter limits, but cannot waive the Harness boundary except through the same explicit approval path. Connected-app and other non-filesystem side effects remain governed by their existing tool policies.
38
+
39
+ ## Alternatives
40
+
41
+ - **Prompt-only “write in the repo” guidance.** Rejected: it expresses a preference but does not prevent absolute paths, symlink escapes or shell commands from writing elsewhere.
42
+ - **Rely only on the host `ToolPolicy`.** Rejected: it is optional and host-specific, so terminal and embedded sessions could differ.
43
+ - **Check only `edit`/`write` paths or parse Bash strings.** Rejected: shell commands can write through arbitrary programs, redirection, subprocesses and indirect paths; string inspection is not a reliable boundary.
44
+ - **Allow all OS temp directories by default.** Rejected for this proposal: the requested default is project-only. A temp location outside the workspace needs the same approval as any other outside write.
45
+ - **Do nothing.** Keeps the existing broad behavior and leaves repository scope to prompt guidance or host configuration.
46
+
47
+ ## Consequences
48
+
49
+ - Add an optional, backward-compatible `workspaceRoot` field to `RunRecord`; new runs set it, old records remain readable, and continuations of older runs derive it from their recorded working directory. No separate workspace registry or output directory is introduced.
50
+ - The native file tools and shell need different enforcement mechanisms: canonical target checks for file mutations and an OS sandbox for shell subprocesses. The same workspace policy and approval semantics must be used by SDK and terminal paths.
51
+ - The `RunRecord` schema is returned over the server protocol, so embedding hosts and sidecar schemas must tolerate the additive field. The Harness remains responsible for computing it; a host cannot nominate an arbitrary wider root.
52
+ - Workspace mode fails closed on unsupported or unavailable sandbox backends. A person can still explicitly authorize one outside operation, or use the existing Full Permission switch where permitted.
53
+ - Standard commands that need to write outside the project (including to `/tmp`) may need an approved one-shot retry. Project-local artifact/output conventions continue to work without extra approval.
54
+
55
+ ## Migration
56
+
57
+ No stored files are rewritten. Parsers accept older run records without `workspaceRoot`; a continuation derives the root from the earlier record's `workingDirectory` and stores it on the new run. New runs pin the effective root after worktree selection. Existing remembered tool grants remain stored but do not satisfy outside-write approvals. The current Full Permission switch remains off/on as configured; it is the only standing choice that may approve a boundary escape, and read-only or unattended facts continue to disable it.
58
+
59
+ ## Checks
60
+
61
+ - Workspace resolution, canonical file-write inspection, session/terminal approvals and sandbox tests cover Git roots, worktrees, non-Git folders, symlink escapes, broad reads, remembered-grant rejection, eligible Full Permission, hard restrictions, fail-closed behavior and one-shot retries. Passed.
62
+ - Harness `npm run typecheck`, full `npm test` (153 files; 1,167 passed, 3 skipped), and `npm run prove` passed on 2026-11-19.
63
+ - The App sidecar contract verifies `runs.find` returns the pinned root. App `npm run typecheck`, `npm test` (571 renderer and 67 sidecar tests passed; 7 development-signing tests passed, 1 skipped), `npm run check:layers`, and `cd src-tauri && cargo test` (169 passed, 1 ignored) passed. Rust compilation emitted warnings.
@@ -0,0 +1,73 @@
1
+ ---
2
+ id: PROP-0038
3
+ title: Annotate inside open shadow roots
4
+ status: Implemented
5
+ created: 2026-10-25
6
+ updated: 2026-10-25
7
+ affects: [13-world-tools.md, 12-storage.md (note target), PROP-0017, PROP-0018, parity]
8
+ ---
9
+
10
+ # PROP-0038: Annotate inside open shadow roots
11
+
12
+ Requested by the owner on 2026-10-25 after the inspector did nothing on reddit.com; they approved
13
+ this design in the same session.
14
+
15
+ ## Problem
16
+
17
+ Sites built from web components keep their content in shadow roots. Reddit's posts, comments and
18
+ feed are `shreddit-*` elements with open shadow roots. The page helper (`annotations/pageScript.ts`)
19
+ refused anything whose root node is not `document`, anything under an element with a shadow root, and
20
+ any custom-element tag (PROP-0017, PROP-0018: "frames, shadow roots and custom elements are never
21
+ picked"). Its text stream (`TreeWalker` over `document.body`) and element lookup
22
+ (`document.getElementsByTagName`) never entered a shadow root. On such sites the inspector drew no
23
+ outline, ignored clicks and said nothing. In WebKit, `getRangeAt` reports a selection inside a shadow
24
+ root as a collapsed point on its host, so text capture could not work there either.
25
+
26
+ ## Proposal
27
+
28
+ 1. **Walk the composed tree.** New helper primitives walk open shadow roots and slotted content in
29
+ rendered order (`composedParent`, `flatChildren`, a bounded composed text stream). Visibility and
30
+ the excluded-content rules are checked on composed ancestors, and `aria-labelledby` ids are looked up
31
+ in the element's own root. Closed shadow roots stay unreadable, and light text a closed component
32
+ does not render is left out. Frames are never entered.
33
+ 2. **Version the target.** Text and element targets captured this way carry `tree: 'composed'`. A
34
+ target without it (every note saved before) is captured, stored and resolved by the document-only
35
+ rules exactly as before, so a saved note never changes what it points at, and a composed note can
36
+ never match a light-DOM node through the old path. The store accepts only the literal `'composed'`
37
+ and never on a page target.
38
+ 3. **Selections across trees.** Selections are read with `Selection.getComposedRanges` (dictionary
39
+ form, then variadic). Boundary points map to stream positions through the composed walk, so a
40
+ selection may start in the page and end inside a component. A selection that spans a visible form
41
+ field or private content is refused. A selection that grows over such content no longer leaves the
42
+ last acceptable selection behind; this also fixes the document-only path. Without
43
+ `getComposedRanges` the helper keeps the document-only capture.
44
+ 4. **Matches and marks.** A composed text match is a list of per-text-node ranges, since a `Range`
45
+ cannot span trees. Element candidates come from the document and every open shadow root, with the
46
+ same 2 000-candidate cap and equality rules. Context at the top of a shadow root is the component
47
+ that holds it. Marks clip to scrollports inside components and follow their scrolls and mutations.
48
+ 5. **Inspector.** The inspector picks the nearest annotatable element on the event's composed path, so
49
+ an icon gives way to its button, and content inside open components is reachable. A custom element
50
+ is pickable when it carries readable text or a label. It says why when it refuses, in a muted chip
51
+ and a toast on click: form fields and private content, embedded frames, or a component whose
52
+ contents are private.
53
+ 6. **Agents.** `page_notes_read` adds that a composed target lies inside a page component, where a
54
+ document-wide selector will not reach it.
55
+
56
+ ## Out of scope
57
+
58
+ Iframes (cross-origin frames are unreachable by page script) and closed shadow roots.
59
+
60
+ ## Migration
61
+
62
+ None. Existing notes have no `tree` and keep the old behaviour. Hosts that validate targets strictly
63
+ accept the optional field (the App's `shared/browserAnnotations.ts`).
64
+
65
+ ## Checks
66
+
67
+ `src/annotations/pageScript.test.ts` (headless Chromium) adds a web-component fixture: picks inside
68
+ open roots, slotted and nested content, duplicate controls told apart by context, text inside and
69
+ across roots, refusal over a field, hints for fields and a closed component, and identical
70
+ legacy/composed captures on a page without components. `store.test.ts` covers the marker. In the App's
71
+ isolated probe instance (real WKWebView), text inside a component and text crossing into one were
72
+ captured, saved, resolved and revealed. Inspector clicks in WKWebView need real pointer input and were
73
+ not exercised there.
@@ -0,0 +1,139 @@
1
+ ---
2
+ id: PROP-0039
3
+ title: Harden workspace writes against inode escapes and unverified retries
4
+ status: Accepted
5
+ created: 2026-10-26
6
+ updated: 2026-10-26
7
+ affects: [INV-GATE-3, INV-GATE-8, INV-TUI-8, 02-sessions-and-runs.md, 07-tools-and-gate.md, 11-terminal.md, 14-surfaces-and-parity.md, parity]
8
+ ---
9
+
10
+ # PROP-0039: Harden workspace writes against inode escapes and unverified retries
11
+
12
+ ## Problem
13
+
14
+ PROP-0037 promises that model-controlled writes stay inside the pinned workspace unless a person
15
+ approves an escape. The current implementation checks canonical pathnames, but Pi performs native
16
+ `write` and `edit` operations afterward using ordinary filesystem calls. A hard link keeps an
17
+ in-workspace pathname while sharing an outside inode, and a parent symlink can change after the
18
+ check. Source review found both cases can bypass the intended approval boundary.
19
+
20
+ The Bash sandbox also exposes the live workspace as a writable path. A macOS integration
21
+ reproduction created a hard link from a file outside the workspace to a name inside it, then ran a
22
+ sandboxed Bash write through the in-workspace name. The command succeeded and the outside alias
23
+ contained the new content. Linux behavior has not yet been reproduced locally.
24
+
25
+ Finally, `workspaceSandbox.ts` infers a sandbox denial from matching text anywhere in captured
26
+ stdout/stderr. A command controls that output; the text can prompt for an unconfined retry even when
27
+ no sandbox denial occurred. Approval is still required, but the prompt's reason is not verified and
28
+ approval replays the entire command.
29
+
30
+ A separate launcher-selection issue was fixed in the 1.2.0 working tree: the sandbox launcher now
31
+ comes only from fixed system paths, with a fake-PATH regression test. This does not resolve the
32
+ remaining findings. No candidate, tag, or publication has been created.
33
+
34
+ ## Affected rules
35
+
36
+ - **INV-GATE-3**, as it stands: “Bash first passes the gate's scope and authorization, then executes
37
+ only inside the OS sandbox; a detected write denial may enter a separate one-shot approval before
38
+ retry. The policy may tighten or deny a call, but cannot waive the boundary. Outside file writes
39
+ and sandbox-denied Bash retries cannot use remembered per-tool approval; only the eligible Full
40
+ Permission switch can answer automatically.” The output-triggered retry is replaced by an
41
+ explicit pre-execution scope request.
42
+ - **INV-GATE-8**, as it stands: “Native reads are bounded by process and operating-system
43
+ permissions, not by the workspace root; absolute and `~` paths are valid. Every run pins its
44
+ canonical `workspaceRoot`. Native `edit` and `write` targets must resolve inside it by default,
45
+ with symlink escapes refused; outside targets require one-call approval and cannot use remembered
46
+ tool grants. Bash, including the initial `!` command, is OS-sandboxed to write only inside that
47
+ root while retaining broad reads. Sandbox denial permits at most one retry after explicit
48
+ approval. Full Permission is the only standing boundary bypass and remains subject to host
49
+ policy, authorization, and read-only, plan, unattended, probe, improver and reflection
50
+ restrictions. Missing enforcement fails closed.” The rule must define containment by the actual
51
+ filesystem effect, not just the path string.
52
+ - **INV-TUI-8**: the terminal must present the same safe write and pre-execution approval behavior
53
+ as SDK sessions.
54
+
55
+ ## Proposal
56
+
57
+ 1. **Keep workspace-only as the default.** Each run continues to pin its canonical workspace root.
58
+ Reads remain broad as today.
59
+ 2. **Enforce native writes at the operation.** Harness supplies the `write` and `edit` tools with
60
+ safe filesystem operations instead of delegating their mutations to Pi's default in-place
61
+ `fsWriteFile`. The operation revalidates the pinned target and performs an atomic replacement
62
+ under the OS-enforced workspace boundary. Replacing the in-workspace directory entry rather
63
+ than truncating a shared inode prevents a hard-link alias from changing an outside file. A
64
+ symlink or parent-directory swap cannot widen the operation's OS write scope. Outside targets
65
+ retain their existing human-only, one-call approval; the helper receives only that approved
66
+ canonical target. Tool names and model-facing schemas stay the same.
67
+ 3. **Fail closed on external hard links for sandboxed Bash.** Before a default Bash call, inspect the
68
+ workspace for regular-file inodes whose link count exceeds the names found inside the workspace.
69
+ If the scan is incomplete or finds a possible outside alias, do not run the command; explain that
70
+ the alias must be removed or copied. The OS sandbox must also prevent the model's sandboxed
71
+ processes from creating a cross-boundary hard link. If a backend cannot establish both
72
+ conditions, it fails closed. A local process outside Harness with the same user's filesystem
73
+ permissions is not controlled by this rule; if protection from such peer processes is required,
74
+ that needs a separate inode-isolated workspace/snapshot design.
75
+ 4. **Ask before broad Bash writes, never infer from output.** Add an explicit
76
+ `workspaceWriteScope` choice to the Harness-owned Bash call, defaulting to `workspace`. A call
77
+ requesting `outside` is approved before it runs, as a human-only, nonrememberable operation; the
78
+ approval presentation must expose the complete command (scrollable in the terminal). The
79
+ eligible Full Permission switch may answer only under its existing restrictions. After approval,
80
+ run that exact command once with broader filesystem access. stdout/stderr text never triggers
81
+ approval or an automatic retry, and a denied command is never replayed after partial effects.
82
+ 5. **Keep other gates intact.** Plan, read-only, unattended, probe, improver and reflection
83
+ restrictions, host policy, authorization, and the tool capability set remain in force. Outside
84
+ writes and broad Bash calls cannot use remembered per-tool grants.
85
+
86
+ ## Alternatives
87
+
88
+ - **Keep pathname checks and the output regex.** Rejected: hard links are invisible to `realpath`,
89
+ native operations race after validation, and command output is not evidence of a sandbox event.
90
+ - **Only reject files with `nlink > 1` for native writes.** Rejected: a link can be added after the
91
+ check, and the native operation remains subject to path swaps.
92
+ - **Run every shell call in a private copy-on-write workspace and commit changes back.** This gives
93
+ stronger inode isolation, including against peer processes, but changes shell visibility,
94
+ writeback/conflict behavior, metadata, storage use, and performance. It remains the alternative
95
+ if protection from same-user processes outside Harness is required.
96
+ - **Remove all outside-write capability.** Rejected for now: the existing contract intentionally
97
+ supports explicitly approved escapes. The proposed pre-execution request preserves that choice
98
+ without guessing from output.
99
+ - **Do nothing.** Leaves the default workspace boundary bypassable.
100
+
101
+ ## Consequences
102
+
103
+ - The public server protocol and stored `RunRecord` layout need no new fields. The Bash tool schema
104
+ gains an optional scope choice; existing calls default to the current workspace-only behavior.
105
+ - SDK sessions and the standalone terminal must register the same safe native tools and apply the
106
+ same pre-execution Bash gate. Terminal approval remains available through its existing inbox.
107
+ - Atomic replacement changes the inode for a written path. The implementation must preserve normal
108
+ file mode behavior where possible and document any platform metadata that cannot be retained.
109
+ - Reject the filesystem root as an active workspace; otherwise every path is inside the pinned root
110
+ and the boundary provides no containment.
111
+ - A workspace containing a possible external hard link cannot use default sandboxed Bash until it
112
+ is repaired. Explicit outside scope remains a separate, visible approval, not a way to silently
113
+ reuse remembered grants.
114
+ - The boundary protects model-controlled operations inside Harness. Other local processes running
115
+ with the same user's filesystem permissions remain outside this proposal's protection. On macOS,
116
+ the OS sandbox denies all hard-link creation by sandboxed Bash, including links entirely inside the
117
+ workspace.
118
+
119
+ ## Migration
120
+
121
+ No stored runs or workspace data are rewritten. Old sessions continue to pin the same workspace
122
+ root. Existing Bash calls omit `workspaceWriteScope` and therefore remain workspace-only; a command
123
+ that needs broader writes must be issued again with an explicit outside scope and approved before
124
+ execution. Existing outside-write approvals remain per-call and are not migrated into standing
125
+ grants.
126
+
127
+ ## Checks
128
+
129
+ - Add adversarial tests for native hard-link writes, symlink/parent swaps between validation and
130
+ mutation, shell writes through pre-existing external hard links, and cross-boundary hard-link
131
+ creation on macOS and Linux.
132
+ - Verify command output containing denial-like text cannot request approval or rerun a command;
133
+ verify explicit outside scope asks before execution and runs at most once after approval.
134
+ - Verify the complete requested command is visible in outside-scope approval details, and Full
135
+ Permission and all read-only, plan, unattended, refinement, authorization, and host policy
136
+ restrictions remain intact in SDK and terminal paths.
137
+ - Run Harness `npm run typecheck`, `npm test`, and `npm run prove`; run the App compatibility checks
138
+ and inspect the relevant terminal behavior. Exercise the sandbox integration tests on macOS and
139
+ Linux before release.
@@ -0,0 +1,87 @@
1
+ ---
2
+ id: PROP-0040
3
+ title: One launch path and command contract across front ends
4
+ status: Accepted
5
+ created: 2026-11-19
6
+ updated: 2026-11-19
7
+ affects: [INV-EXT-1, INV-RUN-1, INV-VAR-4, INV-PLG-11, INV-PAR-1, INV-PAR-2, INV-STO-3, 01-extension-points.md, 02-sessions-and-runs.md, 03-variants.md, 04-prompt.md, 06-plugins-and-capabilities.md, 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
+ ---
9
+
10
+ # PROP-0040: One launch path and command contract across front ends
11
+
12
+ ## Problem
13
+
14
+ The approved App parity and Solo tabs handoff implemented a shared command registry and standard
15
+ prompt sections, but the actual terminal still loads Pi command built-ins, terminal run records
16
+ omit variant pins, session operations differ across front ends, and native browser schemas differ.
17
+ Matching data roots alone does not share credentials: the terminal defaults to a file SecretStore
18
+ while a host may supply its Keychain. Existing compiler-only tests do not establish runtime parity.
19
+
20
+ ## Affected rules
21
+
22
+ - INV-PAR-1: every capability a person uses in a host is a Harness capability with a terminal surface.
23
+ - INV-PAR-2: both surfaces must pass acceptance before a capability is complete.
24
+ - INV-RUN-1 and INV-VAR-4: runs retain account, variant and capability pins.
25
+ - INV-EXT-1: extension-point changes require a proposal; native backends remain tool providers.
26
+ - INV-STO-3: storage layout changes are explicit and owned by one Harness module.
27
+ - INV-PLG-11: plugin categories remain internal; surface availability is optional metadata, not a category.
28
+
29
+ ## Proposal
30
+
31
+ The owner approved “Complete App parity and Solo tabs”, including one shared interactive default,
32
+ on 2026-11-19. This proposal records that design; implementation status is tracked separately.
33
+
34
+ 1. Core commands are browser-safe data in `commands/registry.ts`. `commands.list` resolves the
35
+ effective scope's trusted plugin commands, prompts and skills with identical namespace and
36
+ collision rules. A menu entry alone does not prove command acceptance.
37
+ 2. Saved-history controls cover tree, navigate, fork, clone, rename, last reply and JSONL export.
38
+ Commands requiring a live session use `SessionRunInput.command`: compact, summarized navigation
39
+ and HTML export. They retain normal run lifecycle, busy fencing, cancellation and pins.
40
+ 3. `Launch.standard` supplies shared role, working-folder and connection wording. Tool and prompt
41
+ differences must be attributable to declared add-ons or explicit caller policy, not a front end.
42
+ 4. Interactive defaults are Harness-owned: data root, state directory, neutral default variant
43
+ scope and credential backend. Explicit roots/scopes and existing session/continuation pins win.
44
+ No App-specific discovery, automatic root merge, account substitution, credential downgrade or
45
+ OAuth-store copying is permitted. Adoption of conflicting populated profiles is explicit.
46
+ 5. Both surfaces load Harness-trusted resources and first-party hooks. Terminal-only Pi built-ins
47
+ and `ask_user_question` are removed; attended plan mode uses `ask_user`.
48
+ 6. Browser contracts are backend-neutral and owned by Harness; the isolated and native host
49
+ backends share names, schemas, safety metadata and ref freshness. A backend must report an
50
+ unsupported operation honestly, never reinterpret a snapshot ref as a selector.
51
+ 7. `get_capabilities` is a read-only Harness tool bound to the current run's frozen callable set
52
+ and actual registered schemas. Discovery never grants permission or accepts caller identity.
53
+ 8. Optional `PluginDescriptor.surfaces` / `Plugin.surfaces` metadata is
54
+ `{ preferred: 'host', terminal: 'fallback' | 'unavailable', note }`. Generic host-backed
55
+ capabilities retain Harness ownership; inspection shows fallback/unavailable reasons.
56
+ 9. Shared session references/catalog registration belong to Harness. Existing host transcript
57
+ presentation remains host-owned; native entry identities, not positional message counts,
58
+ connect navigation and fork to that presentation.
59
+
60
+ ## Alternatives
61
+
62
+ - Do nothing: leaves command names that only approximate the advertised capabilities.
63
+ - Match roots manually: rejected by the owner's explicit choice of one shared default.
64
+ - Put browser contracts or session orchestration in the host: violates INV-PAR-1.
65
+ - Merge existing stores automatically: unsafe for account pins, credentials and conflicting variants.
66
+
67
+ ## Consequences
68
+
69
+ Server methods and SDK fields are additive. Existing session histories and account IDs remain valid.
70
+ Terminal run records gain variant identity. Host browser adapters implement the common contract;
71
+ legacy native routes may remain non-model-visible compatibility aliases for one release. Metadata
72
+ labels do not certify acceptance or waive the gate.
73
+
74
+ ## Migration
75
+
76
+ Keep explicit custom roots and historical pins. Seed only an absent default scope through validated
77
+ variant APIs. Shared profile adoption must preserve originals, report conflicts/failure, and never
78
+ silently select an empty replacement. Credentials remain in their owning backend. Shared processes
79
+ must coordinate credential refresh and respect live run owners. Development/disposable profiles
80
+ remain isolated from production. No migration is exercised on owner data during implementation.
81
+
82
+ ## Checks
83
+
84
+ Harness typecheck, full tests and prove; deterministic terminal verification; App renderer/sidecar,
85
+ layer/UI and Rust checks; full browser fixtures; shared UI and both consuming applications' checks.
86
+ Runtime parity compares actual prepared launches, tool schemas and recorded pins. Native WebKit
87
+ acceptance uses an isolated profile. Real-provider/cache checks require separate owner permission.