@xingular/harness 0.1.6 → 2.0.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 (131) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/NOTICE.md +38 -0
  3. package/README.md +139 -28
  4. package/dist/cli.js +9598 -2201
  5. package/dist/terminal-pi.js +808 -16
  6. package/docs/README.md +15 -0
  7. package/docs/decisions/ADR-0001-owned-terminal.md +87 -0
  8. package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
  9. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +68 -0
  10. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +49 -0
  11. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  12. package/docs/terminal-tui.md +344 -0
  13. package/package.json +11 -4
  14. package/src/accounts/accounts.test.ts +197 -1
  15. package/src/accounts/accounts.ts +266 -28
  16. package/src/cli.ts +7 -3
  17. package/src/core/bus.test.ts +22 -0
  18. package/src/core/bus.ts +17 -2
  19. package/src/harness.ts +27 -4
  20. package/src/hub/catalog.json +123 -0
  21. package/src/hub/cli.ts +59 -0
  22. package/src/hub/hub.test.ts +205 -0
  23. package/src/hub/hub.ts +256 -0
  24. package/src/hub/schema.ts +81 -0
  25. package/src/index.ts +12 -2
  26. package/src/mcp/connections.ts +39 -12
  27. package/src/mcp/service.test.ts +49 -3
  28. package/src/mcp/service.ts +14 -3
  29. package/src/mcp/types.ts +10 -0
  30. package/src/memory/api.ts +16 -2
  31. package/src/memory/blocks.ts +3 -1
  32. package/src/memory/caller.ts +13 -1
  33. package/src/memory/curation.test.ts +206 -0
  34. package/src/memory/curation.ts +64 -0
  35. package/src/memory/dispatch.ts +5 -0
  36. package/src/memory/maintenance.test.ts +17 -1
  37. package/src/memory/maintenance.ts +367 -18
  38. package/src/memory/operations.ts +12 -0
  39. package/src/memory/proposals.ts +16 -8
  40. package/src/memory/recall.test.ts +11 -0
  41. package/src/memory/recall.ts +11 -3
  42. package/src/memory/trajectory.test.ts +178 -0
  43. package/src/memory/trajectory.ts +220 -0
  44. package/src/memory/wiki.ts +2 -1
  45. package/src/memory/wikiIndex.ts +3 -2
  46. package/src/plugins/builtin.ts +4 -2
  47. package/src/plugins/catalogue.test.ts +1 -1
  48. package/src/server/methods.ts +43 -2
  49. package/src/server/server.test.ts +20 -1
  50. package/src/sessions/approvals.test.ts +49 -0
  51. package/src/sessions/approvals.ts +26 -4
  52. package/src/sessions/contracts.ts +29 -3
  53. package/src/sessions/conversation.test.ts +83 -0
  54. package/src/sessions/lineageJoin.ts +1 -1
  55. package/src/sessions/policy.ts +4 -0
  56. package/src/sessions/questionBatches.test.ts +110 -0
  57. package/src/sessions/registry.ts +145 -27
  58. package/src/sessions/runStore.ts +14 -0
  59. package/src/sessions/runner.ts +45 -4
  60. package/src/sessions/sessions.test.ts +137 -4
  61. package/src/sessions/sessions.ts +51 -15
  62. package/src/sessions/subagentService.test.ts +159 -0
  63. package/src/sessions/subagentService.ts +236 -0
  64. package/src/sessions/subagents.ts +97 -0
  65. package/src/skills/registry.ts +16 -10
  66. package/src/terminal/accountsMenu.test.ts +225 -0
  67. package/src/terminal/accountsMenu.ts +382 -0
  68. package/src/terminal/control.test.ts +23 -0
  69. package/src/terminal/control.ts +23 -0
  70. package/src/terminal/controller.ts +134 -7
  71. package/src/terminal/hubMenu.ts +24 -0
  72. package/src/terminal/launch.test.ts +5 -14
  73. package/src/terminal/launch.ts +2 -42
  74. package/src/terminal/piExtension.lifecycle.test.ts +55 -0
  75. package/src/terminal/piExtension.ts +91 -6
  76. package/src/terminal/socket.test.ts +23 -0
  77. package/src/terminal/socket.ts +55 -20
  78. package/src/terminal/standalone.test.ts +37 -0
  79. package/src/terminal/standalone.ts +28 -7
  80. package/src/terminal/terminal.test.ts +220 -16
  81. package/src/terminal/terminals.ts +234 -16
  82. package/src/terminal/trajectory.test.ts +66 -0
  83. package/src/terminal/trajectory.ts +44 -0
  84. package/src/terminal/tui/application.test.ts +290 -0
  85. package/src/terminal/tui/application.ts +653 -0
  86. package/src/terminal/tui/commands.test.ts +278 -0
  87. package/src/terminal/tui/commands.ts +443 -0
  88. package/src/terminal/tui/dialogs.ts +301 -0
  89. package/src/terminal/tui/editor.test.ts +113 -0
  90. package/src/terminal/tui/editor.ts +109 -0
  91. package/src/terminal/tui/keybindings.test.ts +30 -0
  92. package/src/terminal/tui/keybindings.ts +59 -0
  93. package/src/terminal/tui/piAdapter.ts +62 -0
  94. package/src/terminal/tui/planMode.test.ts +10 -0
  95. package/src/terminal/tui/planMode.ts +12 -0
  96. package/src/terminal/tui/presentation.test.ts +79 -0
  97. package/src/terminal/tui/questions.test.ts +41 -0
  98. package/src/terminal/tui/questions.ts +47 -0
  99. package/src/terminal/tui/runtime.socket.test.ts +178 -0
  100. package/src/terminal/tui/runtime.test.ts +225 -0
  101. package/src/terminal/tui/runtime.ts +403 -0
  102. package/src/terminal/tui/screen.test.ts +143 -0
  103. package/src/terminal/tui/screen.ts +121 -0
  104. package/src/terminal/tui/sessionUi.ts +24 -0
  105. package/src/terminal/tui/settings.test.ts +150 -0
  106. package/src/terminal/tui/settings.ts +188 -0
  107. package/src/terminal/tui/skillInvocation.test.ts +71 -0
  108. package/src/terminal/tui/skillInvocation.ts +51 -0
  109. package/src/terminal/tui/status.test.ts +48 -0
  110. package/src/terminal/tui/status.ts +82 -0
  111. package/src/terminal/tui/theme.ts +185 -0
  112. package/src/terminal/tui/tools.test.ts +145 -0
  113. package/src/terminal/tui/tools.ts +142 -0
  114. package/src/terminal/tui/trajectoryPanel.test.ts +99 -0
  115. package/src/terminal/tui/trajectoryPanel.ts +226 -0
  116. package/src/terminal/tui/transcript.test.ts +39 -0
  117. package/src/terminal/tui/transcript.ts +135 -0
  118. package/src/terminal/tui/ui.test.ts +313 -0
  119. package/src/terminal/tui/ui.ts +166 -0
  120. package/src/terminal/tui/welcome.ts +102 -0
  121. package/src/terminal/tui/workingStatus.test.ts +44 -0
  122. package/src/terminal/tui/workingStatus.ts +238 -0
  123. package/src/tools/askUser.test.ts +69 -0
  124. package/src/tools/askUser.ts +31 -17
  125. package/src/tools/definitions.ts +42 -1
  126. package/src/tools/maintenance.ts +29 -0
  127. package/src/tools/memoryTools.ts +1 -1
  128. package/src/tools/registryWrite.test.ts +101 -0
  129. package/src/tools/registryWrite.ts +182 -0
  130. package/src/tools/spawnSubagent.ts +47 -0
  131. package/src/tools/types.ts +2 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 2.0.0 - 2026-10-18
6
+
7
+ - Let a connected app sign in with an OAuth client the application registered itself (`oauthClient: 'app'`), supplied through `HarnessOptions.oauthClients` and never stored; `connections.appClients` reports which catalog entries a build can sign in for. See [ADR-0005](docs/decisions/ADR-0005-app-provided-oauth-clients.md).
8
+ - Invoke a skill in the terminal as `$name` instead of `/skill:name`: the completion offers the loaded skills at a `$`, and a leading `$name` is sent to the model as that skill. A typed `/skill:name` still works, and `$` followed by a number or an unknown name stays ordinary text.
9
+ - Keep a stored key or sign-in when a terminal that began before it was saved ends, and let several terminals of one account share its auth.json across processes: a terminal saves only what its own Pi changed, and the last terminal out removes the file.
10
+ - Give every session bounded `trajectory_search` and `trajectory_read` tools for inspecting recorded run events without exposing credentials, attachments, or provider reasoning.
11
+ - Show terminal notices, such as mode changes, errors and the keyboard list, as rows in the conversation instead of above the composer; queued messages stay in the dock.
12
+ - Step the terminal's thinking effort with Shift+Up and Shift+Down within the levels the model supports. Shift+Tab toggles a read-only plan mode that withdraws changing tools until it is switched back.
13
+ - Show the product lockup above the terminal transcript only until the chat has a user message; a resumed session with history starts without it, and a header from a trusted extension is never hidden.
14
+ - Keep the terminal composer on the last rows in fullscreen while the transcript scrolls above it; `tuiMode: regular` keeps the flowing layout, and leaving fullscreen copies the conversation into scrollback.
15
+ - Add one native asynchronous subagent service for SDK, RPC and standalone terminal callers, with selective waits, parent joins, typed history receipts and explicit-resume recovery.
16
+ - Preserve capability ceilings and route child approvals/questions through the owning terminal; release pending interactions before SDK abort.
17
+ - Show a stable rotating work verb with an animated status glyph and keep the completion duration until the next turn.
18
+
19
+ - Harness owns the standalone terminal frontend, using persistent Pi 1.2.0 sessions and the inspected Oh My Pi 18.11.3 presentation.
20
+ - Add titanium and light themes, native session navigation, local command help and completion, account/plugin/Hub controls, and trusted extension UI hosting.
21
+ - Keep account isolation, exact prepared context and resource selection, the final tool gate, native histories and Harness run recording.
22
+ - Support grouped questions with atomic answers, cancellation and restored draft focus.
23
+ - Isolate stale plugin UI callbacks across session replacement and resource reload; restore terminal modes after fatal asynchronous failures and cleanup errors.
24
+
25
+ Implementation and verification limits are recorded in [the terminal reference](docs/terminal-tui.md).
package/NOTICE.md ADDED
@@ -0,0 +1,38 @@
1
+ # Third-party notices
2
+
3
+ The Harness terminal presentation adapts the titanium color palette, five-row Pi logo,
4
+ diagonal gradient and related terminal presentation conventions from Oh My Pi 18.11.3,
5
+ particularly `@oh-my-pi/pi-tui/src/theme/defaults/titanium.json` and
6
+ `@oh-my-pi/pi-tui/src/prompt/welcome.ts`.
7
+
8
+ Upstream: https://github.com/can1357/oh-my-pi
9
+
10
+ The adapted portions are included under the following upstream license. Harness-specific
11
+ product identity and runtime integration are maintained in this package. Dependencies retain
12
+ their own licenses and notices.
13
+
14
+ ```text
15
+ MIT License
16
+
17
+ Copyright (c) 2025 Mario Zechner
18
+ Copyright (c) 2025-2026 Can Bölük
19
+ Copyright (c) 2026 Stencil Labs, Inc.
20
+
21
+ Permission is hereby granted, free of charge, to any person obtaining a copy
22
+ of this software and associated documentation files (the "Software"), to deal
23
+ in the Software without restriction, including without limitation the rights
24
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25
+ copies of the Software, and to permit persons to whom the Software is
26
+ furnished to do so, subject to the following conditions:
27
+
28
+ The above copyright notice and this permission notice shall be included in all
29
+ copies or substantial portions of the Software.
30
+
31
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37
+ SOFTWARE.
38
+ ```
package/README.md CHANGED
@@ -8,15 +8,35 @@ needs to work for someone over time, and nothing about any particular applicatio
8
8
  | Accounts | `src/accounts/` | Several isolated Pi accounts and pools, sign-in, model lists, health and limits. A session keeps the account it started with. |
9
9
  | Sessions | `src/sessions/` | Pi SDK turns, run records and `events.jsonl`, interrupt, approvals, questions, recovery after a crash. |
10
10
  | Prompt | `src/prompt/` | The system prompt compiled from sections with budgets and profiles; a stable prefix, and changing state delivered as updates in native history. |
11
- | Memory | `src/memory/` | The Wiki: pages, facts, memory blocks, revisions, proposals with an evidence gate, undo, an Inbox, recall over past runs, and sleep-time consolidation. |
11
+ | Memory | `src/memory/` | The Wiki: pages, facts, memory blocks, revisions, proposals with an evidence gate, undo, an Inbox, history recall, run trajectory inspection, and sleep-time consolidation. |
12
12
  | Skills | `src/skills/` | Skills, prompts, and rules: a person's own in the data root, and built-in ones shipped with the harness or the application. |
13
13
  | Plugins | `src/plugins/` | What a Pi session loads, chosen by the harness and never by Pi's own discovery; trust for a working folder's code; the list of every plugin and what reaches one caller. |
14
14
  | Tools | `src/tools/` | Tool definitions, the memory tools, `ask_user`; a gate that asks the application's policy, then standing approvals, then the person. |
15
15
  | Connected apps | `src/mcp/` | MCP connections, OAuth, per-session grants, redaction, a trace of what each call returned. |
16
- | Terminal | `src/terminal/` | Interactive Pi sessions with isolated accounts, compiled instructions, a telemetry and tool extension, and the session socket with the `xagent-wiki` and `xagent-mcp` commands. |
16
+ | Terminal | `src/terminal/` | A Harness-owned terminal frontend over persistent Pi sessions, isolated accounts, compiled instructions, the tool gate and telemetry bridge, native history, plugin UI, `/plugins`, `/hub`, `/accounts`, and the existing session socket. |
17
17
  | Server | `src/server/` | The same API over newline-delimited JSON, for a host that is not a Node program. |
18
18
 
19
19
  It was split out of Xingular Agent, which is now an application built on it.
20
+ The [documentation index](docs/README.md) links current terminal architecture and decisions.
21
+
22
+ ### Session options for applications
23
+
24
+ - Interactive sessions offer `spawn_subagent` and `wait_subagents` by default. `subagents: null` disables them; `{ maxDepth }` configures native nesting (default one, maximum three), independently of the host caller depth. Unattended sessions remain disabled unless the host explicitly supplies subagent options. A frozen capability set can narrow these tools further.
25
+ - `harness.subagents.spawn({ parentRunId, brief, tools?, wait? })` opens a fresh child of the same caller with no wider capabilities. It returns `{ runId, nativeSessionId }` once open; `wait: true` also waits for settlement. `harness.subagents.wait({ parentRunId, runIds? })` joins selected direct children, or the current children when omitted, and returns their outcomes. `results` reads the same bounded outcome records without waiting. RPC exposes `subagents.spawn`, `subagents.wait`, and `subagents.results`; `sessions.spawnSubagent` remains a compatibility alias.
26
+ - The model's `spawn_subagent` returns immediately by default; `wait: true` returns an inline result. `wait_subagents` joins selected children. The SDK and standalone terminal share this execution service. Terminal calls use its private control channel, including when connected apps are disabled.
27
+ - Parents receive results at native turn boundaries and join outstanding children before completing. Typed native-history receipts prevent duplicate automatic delivery; explicit waits can reread results. Ownership is recorded before startup so an explicit resume can recover even a lost spawn return. Startup reservations without a run become interrupted outcomes. A restarted Harness never restarts model work automatically. Recovery requires the same recorded account, caller, working folder, and selected history branch. Session IDs are opaque; consumers follow `parentRunId` and `relation`.
28
+ - `providers: false` runs a session with the harness's own tools only.
29
+ - On the caller, `vaultAccess: 'propose'` writes no memory directly, and `recallExcludeAgents` hides those agents' conversations from history and trajectory tools.
30
+ - `maintenanceRunTrigger: false` (a harness option) leaves memory to explicit proposals and scheduled merges.
31
+
32
+ Every session also gets `trajectory_search` and `trajectory_read` from the built-in History plugin.
33
+ Search lists runs in the current data root, including active runs, with filters and a continuation
34
+ cursor. Read returns pages of the canonical execution events, including captured prompt/context,
35
+ tool, decision, retry, compaction, and usage evidence. Active runs show the latest events saved so
36
+ far; settled reads stop at the first outcome. Payloads are bounded and marked when truncated, and
37
+ the tools omit account identifiers, credential fields, attachment bytes, native adapter payloads,
38
+ and provider reasoning text or summaries.
39
+ They report recorded evidence without scoring runs, and do not backfill older records.
20
40
 
21
41
  ## Using it from Node
22
42
 
@@ -64,9 +84,14 @@ An application adds what it knows through six points:
64
84
  The harness provides the web tools itself: `webTools({ secrets })` gives `web_search` (Brave Search,
65
85
  key read from the secret store) and `web_fetch` (checked reads of public pages). An application
66
86
  passes it to `harness.sessions.provide` and switches the names on for each agent.
87
+ `registryTools({ harness })` gives `registry_write` (a skill, rule, or prompt) and `plugin_write`
88
+ (a plugin). Each writes for the calling agent only: the item is on for that agent, and a plugin's
89
+ code is trusted once written. An item others already use goes to the Inbox instead.
67
90
  3. **`ToolPolicy`**. `scope` says whether a call is inside what the run may do (or needs one
68
- approval); `authorize` says whether the tool is still switched on; `approval` adds facts for
69
- standing approvals; `connections` narrows the connected apps a session reaches.
91
+ approval). A decision with `humanOnly` is for a person alone: the always-approve switch and
92
+ remembered answers do not apply to it. `authorize` says whether the tool is still switched on;
93
+ `approval` adds facts for standing approvals; `connections` narrows the connected apps a session
94
+ reaches.
70
95
  4. **`SecretStore`**. Where credentials live (a keychain, a vault). Keys are
71
96
  `<account id>/<name>`.
72
97
  5. **`Directory`**. Names for the application's ids, shown in what the harness writes.
@@ -111,8 +136,10 @@ working folder brings.
111
136
  does nothing. A tool an extension registered is offered to the model and asks before every
112
137
  call. A command it registered runs when a message starts with it.
113
138
  - **The gate runs last.** In an SDK session it is an inline extension, loaded after those on
114
- disk; in a terminal the harness's extension is the last `--extension`. A plugin that changes a
115
- tool call's input does so before the gate sees it.
139
+ disk. A terminal retains its final prepared `--extension` bridge argument; the owned frontend
140
+ loads that bridge as the final trusted inline factory. A plugin that changes a tool call's
141
+ input does so before the gate sees it. Every resource reload revalidates the parent's original
142
+ trusted selection; changed or revoked code requires review and a fresh terminal.
116
143
  - **A required part can be extended.** A package names the part it adds to and, optionally, a
117
144
  hooks file: `"harness": { "extends": ["memory"], "hooks": "./hooks.mjs" }`. The harness runs
118
145
  hooks itself (`src/plugins/hooks.ts`), in its own process, because most memory is written while
@@ -138,8 +165,8 @@ working folder brings.
138
165
  - **A person can do the same from a terminal.** In a terminal session, `/plugins` lists what the
139
166
  session loads and switches a plugin, or one thing it brings, for the session's project or for
140
167
  everyone, and trusts code after showing its files. The session's shell can read the session
141
- token from its environment, so a change is taken only with a second key that the harness's
142
- extension claims once as it loads (`control.claim`) and keeps in its own memory; the socket's
168
+ token from its environment, so a change is taken only with a second key that the trusted
169
+ terminal process claims once (`control.claim`) and shares with its bridge in memory; the socket's
143
170
  `plugins.list` is open to the session, and `plugins.attach`, `plugins.detach`, `plugins.trust`
144
171
  and `plugins.untrust` refuse without that key. A change applies when the session restarts.
145
172
  Outside a session, `xingular-harness plugins list | show | install | remove | update | attach |
@@ -162,9 +189,10 @@ working folder brings.
162
189
  one caller, each item attributed to a plugin, with `unattributed` naming any prompt section,
163
190
  tool group or tool no plugin accounts for.
164
191
 
165
- A terminal session's `pi` command has four extensions of its own (`builtin:mcp`, `codemode`,
166
- `tool-search`, `llama.cpp`). They are passed by name unless Pi's settings switch them off. An SDK
167
- session does not have them.
192
+ A terminal session can load Pi's four existing builtins (`builtin:mcp`, `codemode`,
193
+ `tool-search`, `llama.cpp`). The Harness resource selection passes enabled builtins by name,
194
+ and the pinned compatibility adapter supplies their implementations to the persistent SDK
195
+ runtime. The separate per-turn SDK execution path does not load these terminal builtins.
168
196
 
169
197
  ## Using it from another language
170
198
 
@@ -201,7 +229,7 @@ has no knowledge of the application feature that may call it.
201
229
  `npm run prove` starts that server on a throwaway data root, with no application present, and
202
230
  exercises accounts, memory, skills, the prompt, connected apps, and a recorded session.
203
231
 
204
- ## Run it as a standalone Pi terminal
232
+ ## Run it as a standalone Harness terminal
205
233
 
206
234
  After the CLI package is published to npm or your company's npm registry, install and launch it:
207
235
 
@@ -210,26 +238,69 @@ npm install --global @xingular/harness
210
238
  xingular-harness
211
239
  ```
212
240
 
213
- The machine needs Node 22.19 or newer. On macOS and Linux, the `pi` command must be on `PATH`;
214
- on Windows, Harness runs the pinned Pi CLI package through the active Node runtime. On first
215
- launch, the harness creates a `Default` Pi account; Pi handles provider sign-in.
241
+ The machine needs Node 22.19 or newer. Harness runs its own terminal frontend through the
242
+ active Node runtime on every platform, using its pinned Pi SDK; no separate global `pi`
243
+ installation is required. On first launch, it creates a `Default` isolated account. Use
244
+ `/accounts` or `/login` to sign in.
216
245
 
217
- To build and run from a source checkout instead:
246
+ Provider sign-in progress lives in the running Harness process. An embedding application can call
247
+ `accounts.loginStatus` after reconnecting to recover the current device code or prompt by account;
248
+ the status carries a revision so it can be safely merged with streamed login events. Progress is
249
+ never written to account files, and a completed or cancelled attempt no longer exposes its code.
250
+
251
+ To build and run from a source checkout, use the development command:
218
252
 
219
253
  ```sh
220
254
  npm install
221
- npm run build
222
- node dist/cli.js
255
+ npm run dev
223
256
  ```
224
257
 
225
- This opens Pi's interactive terminal in the current working directory. The harness adds its
226
- compiled context, isolated account, approval gate, Wiki commands, and terminal extension while
227
- Pi provides the interface.
258
+ `npm run dev` rebuilds the CLI and opens the Harness terminal in the current working directory.
259
+ It uses the normal Harness data and state directories. Press `/quit` or Ctrl+C to close it.
260
+ For separate development data, pass the usual `--data <dir>` and `--state <dir>` arguments:
261
+ `npm run dev -- --data <dir> --state <dir>`.
262
+
263
+ Building a checkout does not update an existing global `xingular-harness` installation.
264
+ To replace that command with this checkout, run `npm pack`, then install the exact tarball
265
+ filename it prints with `npm install --global ./<tarball-filename>`. This is a local install;
266
+ it does not publish a release. Close an already-running terminal session and launch the command
267
+ again to load the new frontend. A package version alone cannot distinguish an unreleased local
268
+ build from an older installed build with the same version.
269
+
270
+ This opens the Harness-owned terminal frontend in the current working directory. Its
271
+ presentation follows the inspected Oh My Pi 18.11.3 titanium and light palettes, centered welcome,
272
+ colored text statusline and curved `╰─` prompt, with Harness identity and existing capabilities. Harness
273
+ owns screen composition, editing/input dispatch, scrolling, command routing and plugin UI;
274
+ Pi supplies the persistent execution runtime, native history and rich content components.
275
+ The existing isolated account, compiled context, approval gate, telemetry and Wiki/socket
276
+ commands remain behind the terminal. No Pi `InteractiveMode` is constructed.
277
+
278
+ `/resume` stays inside the prepared history and working folder; `/import` accepts an explicitly
279
+ selected native JSONL file only for the same working folder. Cancel an active response before
280
+ changing or reloading a session. Full OMP visual parity is not established by the current
281
+ verification. `/permissions` reviews device-local Pi terminal grants and the Full Permission switch;
282
+ tool grants apply across terminal sessions sharing this Harness state, and Full Permission requires
283
+ confirmation. `/trajectory` opens recorded runs for the current native conversation, with event
284
+ navigation and a detail inspector. See [terminal architecture and evidence](docs/terminal-tui.md),
285
+ [the decision](docs/decisions/ADR-0001-owned-terminal.md), and [third-party notices](NOTICE.md).
286
+
287
+ ### `/accounts` in the terminal
288
+
289
+ `/accounts` manages the Pi accounts the same way the app's Accounts screen does: add, rename,
290
+ check, make default, sign in (browser or API key), sign out, remove a provider or an account,
291
+ manage pools, and read the activity log. Each change is made by the person at the terminal; a
292
+ command the model runs in the shell cannot make it.
293
+
294
+ A running session stays on the account it started with. To use another account for this
295
+ session, choose **Use for this session**: the terminal child restarts and the same conversation
296
+ resumes on that account. Removing an account that a running terminal is using is refused. Only
297
+ terminals in this process are counted, so an account used by another running `xingular-harness` window can
298
+ still be removed; that session then asks for another account the next time it starts.
228
299
 
229
300
  The default data and device state directories are `~/.xingular-harness/data` and
230
301
  `~/.xingular-harness/state`. Override them with `--data <dir>` and `--state <dir>`. Session
231
- history is stored per working directory and can be reopened with Pi's `/resume` command. The
232
- explicit `terminal` command is an alias for the default launch. Use `--help` to see the commands;
302
+ history is stored per working directory and can be reopened with the terminal's `/resume`
303
+ command. The explicit `terminal` command is an alias for the default launch. Use `--help` to see the commands;
233
304
  `serve` remains the host-facing RPC service for integrations such as Xingular Agent/App.
234
305
 
235
306
  ## Storage
@@ -239,7 +310,7 @@ explicit `terminal` command is an alias for the default launch. Use `--help` to
239
310
  wiki/ home.md, library/, projects/<slug>/, facts/, blocks/, revisions, inbox, log
240
311
  registry/ skills/, prompts/, rules/ (a person's own; never copied)
241
312
  plugins/<name>/ packages kept with a person's data; each is found as an installed plugin
242
- runs/<id>/ run.json, events.jsonl, context.json, caller.json
313
+ runs/<id>/ run.json, events.jsonl, context.json, caller.json, subagents.json (reserved child IDs)
243
314
  config/ context profiles, what is switched on for whom (plugin-attachments.json),
244
315
  settings the harness reads
245
316
  index.sqlite a rebuildable index of Wiki entries and runs (FTS5)
@@ -253,6 +324,7 @@ explicit `terminal` command is an alias for the default launch. Use `--help` to
253
324
  plugin-hooks.json what each hooks file listens for and how its last run went
254
325
  connections.json connected apps (secrets are in the SecretStore)
255
326
  run/ the session socket and the terminal commands
327
+ harness.log diagnostics from the standalone terminal, kept off its screen
256
328
  ```
257
329
 
258
330
  The files are the source of truth; `index.sqlite` can be deleted and rebuilt
@@ -261,14 +333,53 @@ The files are the source of truth; `index.sqlite` can be deleted and rebuilt
261
333
  ## Commands
262
334
 
263
335
  ```sh
264
- npm run typecheck
265
- npm test # unit tests and the golden prompt/memory fixtures in tests/golden
336
+ npm run ci # typecheck, unit/golden tests, and standalone proof; matches GitHub CI
266
337
  npm run build # dist/cli.js (the xingular-harness command) and dist/terminal-pi.js
267
- npm run prove # the standalone proof above
268
338
  ```
269
339
 
270
- Node 22.13 or newer (for `node:sqlite`).
340
+ Node 22.19 or newer.
271
341
 
272
342
  ## Images
273
343
 
274
344
  `SessionRunInput.requiresImageInput` optionally requires a vision-capable resolved Pi model before a prompt is delivered. The check includes direct `images` input, and the generic tool wrapper rejects image results on text-only models. Direct prompt images use Pi's `{ type: 'image', data, mimeType }` content shape. Applications own file formats, attachment selection, extraction and image preparation; the Harness only transports typed image content and validates model capability.
345
+
346
+ ## Curated Hub
347
+
348
+ `xingular-harness hub list [--refresh]`, `hub show publisher/name@version`, and
349
+ `hub install publisher/name@version` browse and install exact catalog versions. `/hub` offers the
350
+ same review in the interactive terminal, using its private control key for installation. Both the
351
+ terminal and embedding applications use `hub.list`, `hub.get`, `hub.install`, and `hub.readDocument`.
352
+ `hub.get { id, version, preview: true }` verifies data payload bytes without installing them.
353
+
354
+ Registry bundles import complete skills or single Markdown prompts/rules, disabled. Pi packages
355
+ reuse the existing installer and require an exact npm version or full GitHub commit. Documents
356
+ are saved as inert JSON for a compatible host to interpret; the harness does not apply them.
357
+ Installation grants no attachment, trust, credentials, or permission. Writes are serialized and
358
+ existing registry files are never overwritten.
359
+
360
+ Installed documents and provenance live under `<data root>/hub/`; the catalog cache is
361
+ `<state dir>/hub/catalog.json`. An offline snapshot ships with the package. Explicit refresh keeps
362
+ the last valid catalog when the network or schema fails. The prepared public distribution repository
363
+ is `../Hub`; publication remains separate from local installation and testing. Run its build with
364
+ `--sync-harness` to regenerate this package's offline snapshot after reviewing catalog changes.
365
+
366
+ Standalone defaults stay separate from a host application's folders. Use explicit `--data` and
367
+ `--state` to target the same library. CLI hub commands construct the harness without opening the
368
+ data root, so they do not migrate the Wiki or settle another process's runs.
369
+
370
+
371
+ ## External curation
372
+
373
+ An embedding application may set `externalMaintenance: true`, supply trusted `CallerContext`
374
+ `vaultAccess` (`self` or `curator`), and register `maintenanceTools`/`MAINTENANCE_PLUGIN`.
375
+ Self callers directly edit only their own writable persona/notes; shared knowledge and text-resource
376
+ writes become persistent proposals. Curator tools read original evidence, compare captured target
377
+ revisions, read all host-assigned requests together, and apply reconciled Wiki proposals as one
378
+ undoable change set. Resource proposals keep their own receipts; executable proposals remain inert
379
+ until the user reviews/trusts them. Later user edits are never overwritten.
380
+ `maintenance.list`, `maintenance.review` and `maintenance.retry` let the host dispatch its own
381
+ recorded sessions. Curator runs do not recursively queue maintenance. Optional assigned IDs freeze
382
+ which requests a batch may claim. These fields are trusted host context, never model arguments.
383
+ `maintenance_read_batch` reads those assigned requests together; `maintenance_apply_batch` records
384
+ one decision for each and applies the evidence-checked Wiki set atomically. Standalone callers that
385
+ omit this option retain the existing lifecycle and direct-write contract.