@xingular/harness 1.1.1 → 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.
- package/CHANGELOG.md +13 -0
- package/README.md +28 -25
- package/dist/cli.js +6675 -2501
- package/dist/sdk/accounts/accounts.d.ts +27 -3
- package/dist/sdk/accounts/accounts.js +78 -24
- package/dist/sdk/accounts/secrets.d.ts +12 -0
- package/dist/sdk/accounts/secrets.js +114 -7
- package/dist/sdk/accounts/store.d.ts +26 -1
- package/dist/sdk/accounts/store.js +1 -1
- package/dist/sdk/agents/builtin.js +15 -1
- package/dist/sdk/agents/planResearch.d.ts +5 -0
- package/dist/sdk/agents/planResearch.js +19 -0
- package/dist/sdk/agents/profiles.d.ts +2 -1
- package/dist/sdk/agents/profiles.js +9 -4
- package/dist/sdk/annotations/pageScript.js +349 -48
- package/dist/sdk/annotations/part.js +34 -23
- package/dist/sdk/annotations/store.d.ts +7 -0
- package/dist/sdk/annotations/store.js +13 -5
- package/dist/sdk/browser/backend.d.ts +16 -0
- package/dist/sdk/browser/backend.js +17 -0
- package/dist/sdk/browser/contracts.d.ts +19 -0
- package/dist/sdk/browser/contracts.js +116 -0
- package/dist/sdk/browser/tools.d.ts +1 -4
- package/dist/sdk/browser/tools.js +14 -91
- package/dist/sdk/cli.js +5 -4
- package/dist/sdk/commands/list.d.ts +3 -0
- package/dist/sdk/commands/list.js +75 -0
- package/dist/sdk/commands/registry.d.ts +250 -0
- package/dist/sdk/commands/registry.js +47 -0
- package/dist/sdk/commands/routes.d.ts +16 -0
- package/dist/sdk/commands/routes.js +33 -0
- package/dist/sdk/core/commandBudget.d.ts +23 -0
- package/dist/sdk/core/commandBudget.js +57 -0
- package/dist/sdk/core/index.js +17 -1
- package/dist/sdk/core/interactiveProfile.d.ts +46 -0
- package/dist/sdk/core/interactiveProfile.js +143 -0
- package/dist/sdk/core/workspace.d.ts +13 -0
- package/dist/sdk/core/workspace.js +88 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +4 -0
- package/dist/sdk/core/workspaceBashTool.js +36 -0
- package/dist/sdk/core/workspaceSandbox.d.ts +31 -0
- package/dist/sdk/core/workspaceSandbox.js +320 -0
- package/dist/sdk/core/workspaceWriteOperations.d.ts +22 -0
- package/dist/sdk/core/workspaceWriteOperations.js +206 -0
- package/dist/sdk/doctor/types.d.ts +2 -2
- package/dist/sdk/harness.d.ts +7 -0
- package/dist/sdk/harness.js +42 -2
- package/dist/sdk/index.d.ts +6 -1
- package/dist/sdk/index.js +3 -0
- package/dist/sdk/pi/runtime.d.ts +2 -1
- package/dist/sdk/pi/runtime.js +2 -2
- package/dist/sdk/plugins/builtin.js +29 -12
- package/dist/sdk/plugins/builtinRegistry.d.ts +10 -3
- package/dist/sdk/plugins/builtinRegistry.js +30 -8
- package/dist/sdk/plugins/catalogue.js +2 -1
- package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
- package/dist/sdk/plugins/commandPrefix.js +21 -0
- package/dist/sdk/plugins/firstParty.d.ts +1 -1
- package/dist/sdk/plugins/firstParty.js +8 -2
- package/dist/sdk/plugins/inventory.js +4 -3
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +2 -1
- package/dist/sdk/plugins/surfaces.d.ts +5 -0
- package/dist/sdk/plugins/surfaces.js +11 -0
- package/dist/sdk/plugins/types.d.ts +15 -0
- package/dist/sdk/prompt/compile.d.ts +14 -0
- package/dist/sdk/prompt/compile.js +65 -29
- package/dist/sdk/prompt/standard.d.ts +17 -0
- package/dist/sdk/prompt/standard.js +21 -0
- package/dist/sdk/server/methods.js +18 -0
- package/dist/sdk/server/remote.js +36 -11
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
- package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
- package/dist/sdk/sessions/continuation.d.ts +3 -0
- package/dist/sdk/sessions/continuation.js +5 -1
- package/dist/sdk/sessions/contracts.d.ts +168 -0
- package/dist/sdk/sessions/contracts.js +59 -1
- package/dist/sdk/sessions/control.d.ts +72 -0
- package/dist/sdk/sessions/control.js +158 -0
- package/dist/sdk/sessions/initialBash.d.ts +7 -0
- package/dist/sdk/sessions/initialBash.js +7 -0
- package/dist/sdk/sessions/planMode.d.ts +14 -3
- package/dist/sdk/sessions/planMode.js +73 -16
- package/dist/sdk/sessions/registry.d.ts +1 -1
- package/dist/sdk/sessions/registry.js +2 -2
- package/dist/sdk/sessions/runStore.d.ts +14 -0
- package/dist/sdk/sessions/runStore.js +35 -0
- package/dist/sdk/sessions/runner.d.ts +40 -2
- package/dist/sdk/sessions/runner.js +161 -13
- package/dist/sdk/sessions/sessions.d.ts +23 -3
- package/dist/sdk/sessions/sessions.js +202 -17
- package/dist/sdk/sessions/subagentService.d.ts +9 -0
- package/dist/sdk/sessions/subagentService.js +63 -4
- package/dist/sdk/sessions/workSlice.d.ts +103 -0
- package/dist/sdk/sessions/workSlice.js +297 -0
- package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
- package/dist/sdk/sessions/workspaceBoundary.js +46 -0
- package/dist/sdk/terminal/browserControl.js +2 -1
- package/dist/sdk/terminal/controller.d.ts +11 -3
- package/dist/sdk/terminal/controller.js +40 -13
- package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
- package/dist/sdk/terminal/opentui/theme.js +87 -0
- package/dist/sdk/terminal/piExtension.d.ts +6 -1
- package/dist/sdk/terminal/piExtension.js +154 -54
- package/dist/sdk/terminal/standalone.d.ts +7 -0
- package/dist/sdk/terminal/standalone.js +72 -13
- package/dist/sdk/terminal/subagentMonitor.d.ts +11 -2
- package/dist/sdk/terminal/subagentMonitor.js +32 -1
- package/dist/sdk/terminal/terminals.d.ts +19 -2
- package/dist/sdk/terminal/terminals.js +245 -35
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +1 -1
- package/dist/sdk/terminal/tui/annotateCommand.js +3 -3
- package/dist/sdk/terminal/tui/commandPages.d.ts +3 -1
- package/dist/sdk/terminal/tui/commandPages.js +3 -0
- package/dist/sdk/terminal/tui/commands.d.ts +2 -0
- package/dist/sdk/terminal/tui/commands.js +205 -124
- package/dist/sdk/terminal/tui/list.d.ts +14 -1
- package/dist/sdk/terminal/tui/list.js +96 -14
- package/dist/sdk/terminal/tui/pageOverlay.js +13 -4
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +1 -1
- package/dist/sdk/terminal/tui/pages/notesPage.d.ts +5 -5
- package/dist/sdk/terminal/tui/pages/notesPage.js +18 -18
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +0 -5
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +9 -3
- package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +1 -0
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +98 -16
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
- package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
- package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
- package/dist/sdk/terminal/tui/piAdapter.js +3 -5
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +2 -0
- package/dist/sdk/terminal/tui/pluginCommands.js +13 -9
- package/dist/sdk/terminal/tui/runtime.js +23 -3
- package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
- package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
- package/dist/sdk/tools/checklist.js +1 -0
- package/dist/sdk/tools/checkpoint.d.ts +27 -0
- package/dist/sdk/tools/checkpoint.js +154 -0
- package/dist/sdk/tools/getCapabilities.d.ts +31 -0
- package/dist/sdk/tools/getCapabilities.js +34 -0
- package/dist/sdk/tools/spawnSubagent.js +4 -3
- package/dist/sdk/usage/analytics.d.ts +20 -0
- package/dist/sdk/usage/analytics.js +151 -0
- package/dist/sdk/usage/ledger.d.ts +38 -0
- package/dist/sdk/usage/ledger.js +142 -0
- package/dist/sdk/usage/limits/adapters.d.ts +11 -0
- package/dist/sdk/usage/limits/adapters.js +349 -0
- package/dist/sdk/usage/limits/capture.d.ts +8 -0
- package/dist/sdk/usage/limits/capture.js +47 -0
- package/dist/sdk/usage/limits/http.d.ts +12 -0
- package/dist/sdk/usage/limits/http.js +51 -0
- package/dist/sdk/usage/limits/normalize.d.ts +15 -0
- package/dist/sdk/usage/limits/normalize.js +211 -0
- package/dist/sdk/usage/limits/service.d.ts +30 -0
- package/dist/sdk/usage/limits/service.js +176 -0
- package/dist/sdk/usage/limits/types.d.ts +65 -0
- package/dist/sdk/usage/limits/types.js +1 -0
- package/dist/sdk/usage/serverMethods.d.ts +3 -0
- package/dist/sdk/usage/serverMethods.js +22 -0
- package/dist/sdk/usage/service.d.ts +32 -0
- package/dist/sdk/usage/service.js +66 -0
- package/dist/sdk/usage/settings.d.ts +7 -0
- package/dist/sdk/usage/settings.js +28 -0
- package/dist/sdk/usage/types.d.ts +60 -0
- package/dist/sdk/usage/types.js +4 -0
- package/dist/terminal-opentui.js +5207 -1883
- package/dist/terminal-pi.js +1658 -271
- package/docs/architecture/02-sessions-and-runs.md +128 -26
- package/docs/architecture/04-prompt.md +50 -12
- package/docs/architecture/06-plugins-and-capabilities.md +24 -7
- package/docs/architecture/07-tools-and-gate.md +104 -24
- package/docs/architecture/08-memory-and-history.md +4 -2
- package/docs/architecture/09-accounts-and-connectors.md +31 -1
- package/docs/architecture/10-server-protocol.md +58 -3
- package/docs/architecture/11-terminal.md +105 -42
- package/docs/architecture/12-storage.md +30 -2
- package/docs/architecture/13-world-tools.md +22 -1
- package/docs/architecture/14-surfaces-and-parity.md +54 -7
- package/docs/architecture/README.md +3 -1
- package/docs/architecture/proposals/PROP-0017-page-annotations.md +6 -2
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +1 -1
- package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
- package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
- package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
- package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
- package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
- package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
- package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
- package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
- package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
- package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +247 -0
- package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
- package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
- package/docs/architecture/proposals/README.md +14 -0
- package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
- package/docs/decisions/ADR-0021-required-command-namespaces.md +1 -1
- package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
- package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
- package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
- package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
- package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
- package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
- package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
- package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
- package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
- package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
- package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
- package/docs/parity.md +80 -24
- package/docs/releases/1.1.1.md +28 -0
- package/docs/releases/1.2.0.md +49 -0
- package/docs/releases/4.0.0.md +10 -9
- package/docs/releases/README.md +35 -30
- package/docs/study/00-index.md +3 -0
- package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
- package/docs/terminal-tui.md +100 -59
- package/package.json +4 -3
|
@@ -13,6 +13,7 @@ records everything the run does as validated events.
|
|
|
13
13
|
|---|---|---|
|
|
14
14
|
| `Sessions` | `sessions/sessions.ts` | Starts a turn: `run(input: SessionRunInput)`, `provide(provider)`. Builds the gate. |
|
|
15
15
|
| `runTurn`, `piSessionFactory`, `loadResources` | `sessions/runner.ts` | Opens the Pi session, loads resources in a fixed order, streams events, settles the run. |
|
|
16
|
+
| compaction checkpoint | `sessions/compactionCheckpoint.ts` | Restores the active request's bounded goal, checklist and plan instructions to model context after compaction. |
|
|
16
17
|
| `RunRegistry`, `ActiveRun` | `sessions/registry.ts` | Live runs: `emit`, `requestApproval`, `requestAnswer(s)`, `onInterrupt`, `onSteer`, `finish`; `listen` for observers. |
|
|
17
18
|
| run store functions | `sessions/runStore.ts` | `saveRun`, `updateRun`, `persistEvent`, `appendEvent`, `readEvents`, `markInterruptedRuns`, `runFamily`, `listRuns`. |
|
|
18
19
|
| `RunRecord`, `RunEvent`, schemas | `sessions/contracts.ts` | The one contract every session shares. |
|
|
@@ -27,15 +28,18 @@ records everything the run does as validated events.
|
|
|
27
28
|
|
|
28
29
|
1. Validate the input (`run.id`, `sessionId`, `text`; an `initialBashCommand` only on a new
|
|
29
30
|
interactive user turn).
|
|
30
|
-
2.
|
|
31
|
+
2. Resolve a continuation when requested; reuse its pinned root or derive one from its recorded
|
|
32
|
+
working directory. For a new run, resolve and pin the root from the effective `cwd` (after
|
|
33
|
+
worktree selection). Select the native history (`selectHistory`) and resolve the account
|
|
34
|
+
(`accounts.resolve`).
|
|
31
35
|
3. Resolve the caller's capabilities, intersect with any narrower requested set, and **freeze**
|
|
32
36
|
them for the run (`capabilities/runSnapshot.ts::freezeRun`).
|
|
33
37
|
4. **Pin** the variant once (`variant/materialise.ts::materialise`).
|
|
34
38
|
5. `saveRun` with status `queued`, the account, `harnessScope` and `harnessVersion`.
|
|
35
39
|
6. Compile the prompt (`sessionLaunch`, page 04): a stable system prompt and an optional context
|
|
36
40
|
update.
|
|
37
|
-
7. `runs.start` the live run; build the tool list (broker,
|
|
38
|
-
`ask_user`, subagent tools, provider tools) and the gate.
|
|
41
|
+
7. `runs.start` the live run; build the tool list (broker, Harness tools including read-only
|
|
42
|
+
`get_capabilities`, the plan-eligible `ask_user`, subagent tools, provider tools) and the gate.
|
|
39
43
|
8. Open Pi through the `SessionFactory`, with resources loaded in order: disk extensions chosen by
|
|
40
44
|
the harness, variant extensions, inline extensions, and the gate last.
|
|
41
45
|
9. Record `nativeSessionId`, register the run with `Subagents`, start `runTurn`, and return
|
|
@@ -54,6 +58,14 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
|
|
|
54
58
|
`reaction.added`, `agent.message`, `checklist.updated`, `artifact.added`, `file.changed`, `usage.updated`,
|
|
55
59
|
`account.status`, `status.changed`, `failed`, `completed`. Each has a payload schema in
|
|
56
60
|
`runEventPayloadSchemas`.
|
|
61
|
+
- **Workspace root** (`RunRecord.workspaceRoot`) is the canonical root whose filesystem effects
|
|
62
|
+
native writes and default-scope Bash may modify: the nearest Git repository or worktree above its
|
|
63
|
+
effective working directory, otherwise that canonical directory. New runs pin it; continuations
|
|
64
|
+
reuse it. Older records may omit it, in which case a continuation derives it from the recorded
|
|
65
|
+
`workingDirectory`. The filesystem root itself cannot be selected as a workspace, because it
|
|
66
|
+
would collapse the write boundary. Native writes revalidate the target and atomically replace it
|
|
67
|
+
inside an OS write scope; Bash scans for external hard-link aliases and runs in the same pinned
|
|
68
|
+
boundary (page 07).
|
|
57
69
|
- **Question sketches** (PROP-0025, ADR-0026; originally PROP-0024, ADR-0025). `question.requested` may include `uiSketch: true`
|
|
58
70
|
and `sketch` text on each choice. If enabled, every choice must have a sketch; otherwise no
|
|
59
71
|
choice may carry one. A sketch is 1–24 LF-separated lines, at most 80 printable ASCII characters
|
|
@@ -93,11 +105,28 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
|
|
|
93
105
|
carries `agent` and any `unavailableTools`. A run that may spawn lists every profile in its
|
|
94
106
|
`subagents` section.
|
|
95
107
|
- **Plan mode** (`plan: true`). The stable system prompt is unchanged. An attended plan run may
|
|
96
|
-
include `ask_user`, subject to the caller's frozen
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
the
|
|
100
|
-
|
|
108
|
+
include `ask_user` and `spawn_subagent` / `wait_subagents`, subject to the caller's frozen
|
|
109
|
+
capabilities. Delegation is limited to named profiles whose effective tool and plugin allowlists
|
|
110
|
+
qualify for read-only research; the child inherits plan mode and cannot write, run commands, ask
|
|
111
|
+
the user, use connectors or spawn children. The gate refuses unsafe calls before approvals and the
|
|
112
|
+
subagent service rechecks profile eligibility before launch. Other calls must be in
|
|
113
|
+
`PLAN_READ_ONLY_TOOLS` (including `get_capabilities` when frozen for the run), be provider tools
|
|
114
|
+
marked `readOnly`, or be explicitly classified by `planModeSafe`. Model-issued `bash` is allowed
|
|
115
|
+
and runs in the sandbox's read-only scope: no writes except a discarded temp folder, no network,
|
|
116
|
+
nothing that widens the scope; the gate refuses `outside` requests and `PLAN_BASH_DENIED` commands
|
|
117
|
+
(PROP-0043). The dynamic plan instruction
|
|
118
|
+
requires an opening `Goal` or `Summary`, evidence-grounded findings when useful, and task-scaled
|
|
119
|
+
steps and verification. A small fix stays concise without omitting its
|
|
120
|
+
outcome or check; cross-cutting work uses ordered steps. It uses alternatives only when requested
|
|
121
|
+
or materially useful; contextual `uiSketch` questions clarify real choices.
|
|
122
|
+
The reply ends with one `<proposed_plan>` block.
|
|
123
|
+
- **Compaction checkpoint** (PROP-0033, ADR-0032). After compaction, an active run's model context
|
|
124
|
+
receives a bounded, ephemeral checkpoint with the current user request and the latest validated
|
|
125
|
+
checklist or applicable plan instructions, when either is available to restore. It is re-added to
|
|
126
|
+
each request while that run continues;
|
|
127
|
+
its state is cleared when the run settles or the session branch changes. The message changes no
|
|
128
|
+
tools, permissions, run events or native history. An interrupted run still uses the durable
|
|
129
|
+
checklist and normal continuation path.
|
|
101
130
|
- **Continuation** (PROP-0007). `continuationOf(root, runId, sessionDir?)` (`runs.continuation`)
|
|
102
131
|
says whether a stopped run can be continued: `resumable`, a `reason` when not (`not_found`,
|
|
103
132
|
`active`, `completed`, `no_history`, `history_missing`), the exact native history to reopen,
|
|
@@ -120,18 +149,52 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
|
|
|
120
149
|
- **Usage** (`usage.updated`). `inputTokens` is uncached input; `cacheReadTokens` and
|
|
121
150
|
`cacheWriteTokens` are separate; `outputTokens` includes `reasoningTokens`. Totals are
|
|
122
151
|
cumulative for the run, not the native session. `contextTokens` is the latest request's size.
|
|
152
|
+
The derived usage ledger (`usage_requests`, page 08) copies these requests for
|
|
153
|
+
`/usage:analysis`; run events remain the only source of truth.
|
|
154
|
+
- **Limit snapshots** (`account.status.limits`). A provider reading carries a window or balance,
|
|
155
|
+
its reset, and its source. It is produced by the usage limits service from provider response
|
|
156
|
+
headers or a documented provider endpoint (page 09), stored in the account's state, and never
|
|
157
|
+
inferred from a made-up cap.
|
|
123
158
|
- **Provider reasoning summaries.** For supported Responses API families, when reasoning is
|
|
124
159
|
enabled the runner requests a `detailed` summary and records only the provider's explicit summary
|
|
125
160
|
(bounded to 4,000 characters) in request-level usage. This does not change reasoning effort or
|
|
126
161
|
guarantee a provider will return a summary; raw reasoning is not used as a substitute.
|
|
127
162
|
|
|
163
|
+
## Session controls and command runs (PROP-0040)
|
|
164
|
+
|
|
165
|
+
`commands/registry.ts` is the browser-safe core command catalogue, shared by front ends.
|
|
166
|
+
`commands.list` combines it with effective plugin, extension, prompt and skill routes (page 10).
|
|
167
|
+
A listed route is not proof that its surface passes acceptance.
|
|
168
|
+
|
|
169
|
+
`sessions/control.ts` owns saved-history operations: tree, navigation without a summary, fork,
|
|
170
|
+
clone, rename, last reply and JSONL export. A `SessionRef` names `sessionDir`, optional
|
|
171
|
+
`sessionFile` and optional `cwd`; the resolved JSONL must be inside that directory. Navigation
|
|
172
|
+
records a `xingular-navigation` entry; choosing a user message returns its text for editing and
|
|
173
|
+
moves before it. Fork and clone create history in an absolute `targetDir`.
|
|
174
|
+
|
|
175
|
+
`SessionRunInput.command` (also `TurnParams.command`) is one of:
|
|
176
|
+
|
|
177
|
+
- `{ name: 'compact', instructions? }`
|
|
178
|
+
- `{ name: 'navigate', entryId, summarize: boolean, instructions? }`
|
|
179
|
+
- `{ name: 'export', path }` (absolute `.html` path)
|
|
180
|
+
|
|
181
|
+
It replaces prompt submission and skips the normal context update. It requires saved history and
|
|
182
|
+
cannot combine with plan mode, continuation, automatic execution, initial Bash or images. It uses
|
|
183
|
+
normal account/variant/capability pins, events and cancellation. Front ends must fence history
|
|
184
|
+
mutations against active work; the current raw saved-history helpers do not themselves establish
|
|
185
|
+
that fence. Stable native entry IDs must connect host transcript projection to navigation/fork,
|
|
186
|
+
not positional message counts. A host can route `/history` to Harness `sessions.navigate` and
|
|
187
|
+
navigate the same saved session; it must not substitute a fork. Shared session catalog registration
|
|
188
|
+
is approved but remains in progress; no completed cross-surface catalog is implied (PAR-008).
|
|
189
|
+
|
|
128
190
|
## Invariants
|
|
129
191
|
|
|
130
|
-
- **INV-RUN-1** A run pins one account, one variant version
|
|
131
|
-
starts. None
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
192
|
+
- **INV-RUN-1** A run pins one account, one variant version, one capability set and one canonical
|
|
193
|
+
`workspaceRoot` when it starts. None changes during the run. A continuation reuses the prior
|
|
194
|
+
root, deriving one from `workingDirectory` only for a legacy record without the field. A pinned
|
|
195
|
+
account that cannot be used fails the run; it is never swapped (`INV-ACC-2`). A side-question
|
|
196
|
+
run is the explicit exception for the variant: it pins no variant and uses the fixed Harness
|
|
197
|
+
instruction plus a redacted main-run context projection (PROP-0019).
|
|
135
198
|
- **INV-RUN-2** A run's capability set is written once (`freezeRun`). A resumed or duplicate launch
|
|
136
199
|
with a different set fails with `capabilities_frozen`. A child run's set is the intersection of
|
|
137
200
|
its parent's, its profile's tools and plugins, and what it asked for; it never widens.
|
|
@@ -141,8 +204,11 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
|
|
|
141
204
|
- **INV-RUN-4** A restarted harness never restarts model work. On `open`, runs left active are
|
|
142
205
|
marked `interrupted` unless another live process owns them (`owner.json`). Recovery of a
|
|
143
206
|
subagent needs the same account, caller, working folder and history branch. Continuing is always
|
|
144
|
-
a new run
|
|
145
|
-
|
|
207
|
+
a new run with `continueFrom`; it pins the earlier run's account, variant version and capability
|
|
208
|
+
set, and the earlier run's record is never reopened. The application asks for it, or the earlier
|
|
209
|
+
run's work-slice policy does when the reply stopped at its budget (PROP-0041); a run started
|
|
210
|
+
without a person (`automatic`), a plan, a subagent, a session command or a worktree never
|
|
211
|
+
continues itself.
|
|
146
212
|
- **INV-RUN-5** Unattended runs (`automatic: true`) load no extension found on disk, read no
|
|
147
213
|
context files, and never ask a person: anything that would need approval is refused. A variant's
|
|
148
214
|
own trusted plugins still load, except for side-question runs, which have no variant or plugin
|
|
@@ -156,39 +222,75 @@ A session that cannot open ends its run as `failed` and returns `nativeSessionId
|
|
|
156
222
|
- **INV-RUN-7** Token accounting follows the usage contract above. Changing what a field means is
|
|
157
223
|
an architecture change.
|
|
158
224
|
- **INV-RUN-8** Plan mode keeps the stable system prompt but has mode-specific tools: an attended
|
|
159
|
-
plan may include `ask_user`, subject to the frozen caller
|
|
160
|
-
automatic, probe, improver and reflection runs omit
|
|
161
|
-
`
|
|
162
|
-
|
|
163
|
-
|
|
225
|
+
plan may include `ask_user`, `spawn_subagent` and `wait_subagents`, subject to the frozen caller
|
|
226
|
+
capabilities; newly resolved normal, automatic, probe, improver and reflection runs omit
|
|
227
|
+
`ask_user`. Plan-mode spawning requires a named profile whose effective explicit tool and plugin
|
|
228
|
+
allowlists qualify for read-only research. The child inherits plan mode and is narrowed to the
|
|
229
|
+
intersection of the parent's frozen capabilities, the profile and the plan research set; it has no
|
|
230
|
+
connectors, user questions, writes, commands or nested subagents. The plan run itself may run
|
|
231
|
+
Bash only in the OS-enforced read-only scope (PROP-0043, ADR-0038). The gate refuses unsafe calls
|
|
232
|
+
before approvals, and the service rechecks before launch. The terminal activates plan-eligible
|
|
233
|
+
tools only for a plan request, then restores its normal set. Provider-cache effects of the tool-list
|
|
234
|
+
difference are not assumed (page 04, `INV-PRM-8`).
|
|
164
235
|
- **INV-RUN-9** Subagent results reach the parent at native turn boundaries, at most once
|
|
165
236
|
automatically (typed receipts in native history). A parent joins outstanding children before it
|
|
166
237
|
completes.
|
|
167
238
|
- **INV-RUN-10** An initial Bash command is allowed only on a new interactive user turn (not
|
|
168
|
-
automatic, plan, resumed, continuing, relation, probe or improver runs), must match the leading `!`
|
|
169
|
-
in the text, and passes the same gate as model-issued Bash.
|
|
239
|
+
automatic, plan, resumed, continuing, relation, probe or improver runs), must match the leading `!`
|
|
240
|
+
command in the text, and passes the same gate as model-issued Bash. It is workspace-scoped by
|
|
241
|
+
default; the explicit terminal syntax `!outside <command>` requests the same human-only,
|
|
242
|
+
pre-execution outside-scope approval as the Bash tool and runs the command at most once.
|
|
170
243
|
- **INV-RUN-11** A side-question run is independent, tool-free and temporary. It receives only a
|
|
171
244
|
bounded, redacted projection of the main run's effective prompt and public events plus the
|
|
172
245
|
surface's visible transcript and selected references. It excludes hidden reasoning and attachment
|
|
173
246
|
bytes, never reads the main native history, and never changes or steers the parent. Its own run
|
|
174
247
|
record and events use the normal store contract (PROP-0019).
|
|
248
|
+
- **INV-RUN-13** A reply is a bounded work slice (PROP-0041). The foundation defaults are 160 tool
|
|
249
|
+
calls, 40 minutes and 320 000 new tokens, whichever comes first. The token count covers new input,
|
|
250
|
+
cache writes and output, never the cached prefix: a few large reads pass any small cap before
|
|
251
|
+
useful work, so the cap is a safety net, not the bound. At the limit the guard ends the slice and
|
|
252
|
+
refuses the next tool call with a request for `checkpoint_write`; a handoff call is never refused,
|
|
253
|
+
including when it is the first call past the limit, and another tool ends the reply. A reply that ends this way is `interrupted` with terminal reason `slice_complete`, and one
|
|
254
|
+
the stall guard ends is `stalled`. The stall guard identifies a call by its name and every
|
|
255
|
+
argument, names a repeated call once and ends the reply on the next repeat, and counts afresh in
|
|
256
|
+
each reply, so a checklist a reply rewrites as its steps complete is not a repeat. A new run
|
|
257
|
+
continues it only up to the policy's slice cap, only
|
|
258
|
+
after a slice that changed a file, passed a check or recorded a finished item, and never after a
|
|
259
|
+
checkpoint that is `blocked`. A run may turn the guard off with `workSlice.enabled: false`, and a
|
|
260
|
+
launch may set `XINGULAR_WORK_SLICE=off` for every run in that process; with it off a reply has no
|
|
261
|
+
boundary — no checkpoint, no continuation, no stall notes — and ends only when the model stops or a
|
|
262
|
+
person interrupts.
|
|
263
|
+
- **INV-RUN-14** A run event stream carries `checkpoint` (the handoff `checkpoint_write` records or
|
|
264
|
+
the harness derives from the run's own evidence when the model wrote none) and `heartbeat`
|
|
265
|
+
(steps, elapsed time, last tool, compactions, slice, and the call budget). A heartbeat older than
|
|
266
|
+
five minutes while the owner process lives marks the run `interrupted` with reason `stalled`; a
|
|
267
|
+
run that never emitted one keeps the 30-minute silence rule. The watchdog never restarts work.
|
|
268
|
+
- **INV-RUN-12** A post-compaction checkpoint is a bounded context projection of the active request,
|
|
269
|
+
the latest validated checklist and applicable plan instructions. It is compiled by
|
|
270
|
+
`prompt/compile.ts`, supplied only to model requests in the active run, and never persists hidden
|
|
271
|
+
reasoning or changes permissions, stable prompt text, native history or run-event schemas. Its
|
|
272
|
+
in-memory state is cleared when the run settles or the active session branch changes
|
|
273
|
+
(PROP-0033, ADR-0032).
|
|
175
274
|
|
|
176
275
|
## Data
|
|
177
276
|
|
|
178
|
-
`<data root>/runs/<id>/`: `run.json
|
|
179
|
-
`
|
|
277
|
+
`<data root>/runs/<id>/`: `run.json` (including the optional, legacy-compatible `workspaceRoot`),
|
|
278
|
+
`events.jsonl`, `owner.json`, `subagents.json`, `context.json`, `caller.json`, `capabilities.json`,
|
|
279
|
+
`mcp-context.json`. Native history lives in
|
|
180
280
|
the session directory the caller passes (`sessionDir`), owned by Pi. Side-question native history
|
|
181
281
|
uses a one-use OS temporary directory, removed when the run settles; its tracked run and events
|
|
182
282
|
remain in the ordinary run store.
|
|
183
283
|
|
|
184
284
|
## Source map
|
|
185
285
|
|
|
186
|
-
`src/sessions/*.ts`, `src/capabilities/runSnapshot.ts`, `src/
|
|
286
|
+
`src/sessions/*.ts`, `src/capabilities/runSnapshot.ts`, `src/core/workspaceBashTool.ts`,
|
|
287
|
+
`src/core/workspaceSandbox.ts`, `src/core/workspaceWriteOperations.ts`, `src/tools/spawnSubagent.ts`.
|
|
187
288
|
Decisions: [ADR-0002](../decisions/ADR-0002-native-subagent-lifecycle.md) (superseded),
|
|
188
289
|
[ADR-0003](../decisions/ADR-0003-shared-asynchronous-subagents.md),
|
|
189
290
|
[ADR-0022](../decisions/ADR-0022-plan-only-question-tools.md),
|
|
190
291
|
[ADR-0023](../decisions/ADR-0023-contextual-side-question-runs.md),
|
|
191
|
-
[ADR-0026](../decisions/ADR-0026-contextual-question-wireframes.md)
|
|
292
|
+
[ADR-0026](../decisions/ADR-0026-contextual-question-wireframes.md),
|
|
293
|
+
[ADR-0033](../decisions/ADR-0033-plan-mode-research-delegation.md).
|
|
192
294
|
|
|
193
295
|
## Native session names (PROP-0010)
|
|
194
296
|
|
|
@@ -16,11 +16,13 @@ keeps provider caching effective across turns.
|
|
|
16
16
|
| `render(env, pack)` → `string` | One string for a session that takes a single prompt. |
|
|
17
17
|
| `sessionLaunch(env, caller, launch, historyFile, variant)` → `{ system, update, pack }` | SDK sessions: stable prefix plus an update with only the dynamic sections that changed since the last delivered snapshot. |
|
|
18
18
|
| `deliveredSnapshot(sessionFile)` | Reads the last delivered snapshot on the active history branch; a compaction forces a fresh one. |
|
|
19
|
+
| `renderCompactionCheckpoint` | Compiles a bounded current-request, checklist and plan-state message for post-compaction model requests. |
|
|
19
20
|
| `saveForSession`, `copyToRun` | Terminal sessions keep the pack they started with and copy it to each run. |
|
|
20
21
|
| `record`, `load`, `packPath` | The pack each run was given, at `runs/<id>/context.json`. |
|
|
21
22
|
| `toolGroups`, `fit`, `clip` | The tool manifest by group; cutting text to a budget at a paragraph boundary. |
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
Assembly is in `prompt/compile.ts`; shared standard-section data is in `prompt/standard.ts`.
|
|
25
|
+
A `ContextPack` holds `sections: Section[]` (each with `id`, `title`,
|
|
24
26
|
`body`, `sources`, `budget`, `size`, `cut`), `toolGroups`, `harness` (scope and fingerprint),
|
|
25
27
|
`profile`, `compiledAt` and `delivery` (`systemSectionIds`, `updatedSectionIds`).
|
|
26
28
|
|
|
@@ -29,14 +31,22 @@ All in `prompt/compile.ts`. A `ContextPack` holds `sections: Section[]` (each wi
|
|
|
29
31
|
`SECTION_ORDER`: `harnessIdentity` 5, `system` 25, `guardrails` 40, `memory` 45, `references`
|
|
30
32
|
50, `subagents` 64, `scripts` 66, `wiki` 80, `tools` 90, `reporting` 95. Application sections
|
|
31
33
|
sit among them by their `order`; plan mode uses `plan` at 25. Ties keep insertion order.
|
|
32
|
-
When a run may spawn, `subagents` lists every
|
|
33
|
-
project and
|
|
34
|
+
When a run may spawn, the dynamic `subagents` section lists every profile it can start (built-in,
|
|
35
|
+
global, project and variant c5 names) and replaces the variant's own list (PROP-0029). Normal-mode
|
|
36
|
+
guidance in that section explains when delegation is worth its overhead, profile selection,
|
|
37
|
+
self-contained briefs, independent parallel work, and parent ownership of integration. Plan mode
|
|
38
|
+
lists only effective profiles eligible for read-only research and requires a named profile; keeping
|
|
39
|
+
this section dynamic leaves the stable system prompt unchanged across modes. The `tools`
|
|
34
40
|
section has a Progress paragraph whenever `checklist_write` is available: it asks for a checklist
|
|
35
|
-
early and kept current,
|
|
41
|
+
early and kept current, then requests a final update before the reply. Only fully completed work is
|
|
42
|
+
marked completed; unfinished or blocked steps remain accurate (PROP-0006).
|
|
36
43
|
|
|
37
44
|
The fixed `harness-identity` section says `You are an AI agent running in <productName>.` and uses
|
|
38
|
-
`env.productName` (default `Xingular Agent`).
|
|
39
|
-
|
|
45
|
+
`env.productName` (default `Xingular Agent`). `Launch.standard: { cwd, project?: { name } | null }` requests shared role and working-folder
|
|
46
|
+
sections from `prompt/standard.ts`; the compiler supplies common connections, file and annotation
|
|
47
|
+
guidance for the effective tools. Terminal preparation defaults to standard sections (explicit
|
|
48
|
+
`standard: null` opts out); the host interactive path requests the same sections. Hosts may add
|
|
49
|
+
attributed add-on and task context, not a duplicate standard role or connection policy (PROP-0040).
|
|
40
50
|
|
|
41
51
|
Budgets (characters): variant sections 30,000 each (already capped at save, so never cut here);
|
|
42
52
|
references 12,000; Wiki pointer 2,500; tools 8,000; reporting 2,000; application sections their
|
|
@@ -69,17 +79,34 @@ compile ──► pack ──► stable sections ──► system prompt (+ "Con
|
|
|
69
79
|
`dynamic: true`.
|
|
70
80
|
- An update lists only the dynamic sections that changed, and announces a withdrawn one.
|
|
71
81
|
`references` is always resent when present, because it belongs to the current request.
|
|
82
|
+
- After successful compaction, the foundation checkpoint extension detects the compacted context and
|
|
83
|
+
uses `renderCompactionCheckpoint` to append one hidden, ephemeral context message to each model
|
|
84
|
+
request while the active run continues, when a checklist or applicable plan instructions exist.
|
|
85
|
+
It contains only the current request and available state. It is not written to native history, and its state is
|
|
86
|
+
discarded when the run settles or the branch changes.
|
|
72
87
|
- The session appends the update as a hidden custom message and saves its snapshot in the
|
|
73
88
|
message details (`xingularContext`); recording a pack does not mark it delivered.
|
|
74
89
|
- Terminal sessions use `compile` + `render` once, pass it as `--append-system-prompt`, and keep
|
|
75
90
|
that pack for the life of the session.
|
|
76
|
-
-
|
|
77
|
-
permits access, names the configured data root, and describes the working folder as a
|
|
78
|
-
location.
|
|
91
|
+
- Native file guidance states that absolute and `~` paths work for reads when the operating
|
|
92
|
+
system permits access, names the configured data root, and describes the working folder as a
|
|
93
|
+
default location. Native writes and Bash filesystem effects default to the run's pinned project
|
|
94
|
+
or worktree root; outside file targets require one-call approval, and Bash is sandboxed unless
|
|
95
|
+
the eligible user explicitly enables Full Permission. Edits and commands remain subject to the
|
|
96
|
+
gate.
|
|
79
97
|
- A side-question launch attributes its fixed no-tool instruction to the `side-questions` plugin.
|
|
80
98
|
Its launch suppresses tool guidance entirely. The main run's effective prompt and current context
|
|
81
99
|
update are included in the separately bounded, redacted context message (PROP-0019).
|
|
82
100
|
|
|
101
|
+
## Launch parity status (2026-11-19)
|
|
102
|
+
|
|
103
|
+
Shared section generation is present in source; `surfaceParity.test.ts` checks compiler equality.
|
|
104
|
+
That does not verify actual prepared launches, registered schemas, credentials, variant pins or
|
|
105
|
+
provider-cache reuse. PROP-0040 also requires one Harness-owned interactive default for roots,
|
|
106
|
+
variant scope and credential backend. Adoption and runtime acceptance remain in progress; explicit
|
|
107
|
+
roots/scopes and continuation pins take precedence. Matching `--data` alone cannot reconcile a
|
|
108
|
+
file SecretStore with a host Keychain. See [parity](../parity.md).
|
|
109
|
+
|
|
83
110
|
## Invariants
|
|
84
111
|
|
|
85
112
|
- **INV-PRM-1** The prompt is assembled only in `src/prompt/compile.ts`. Nothing else builds model
|
|
@@ -99,9 +126,20 @@ compile ──► pack ──► stable sections ──► system prompt (+ "Con
|
|
|
99
126
|
- **INV-PRM-8** Whether a prompt or callable tool-list change keeps the provider's cache is measured
|
|
100
127
|
with real requests from the application, only with the account owner's permission. Tests do not
|
|
101
128
|
stand in for it.
|
|
102
|
-
- **INV-PRM-9** Native file guidance describes the
|
|
103
|
-
|
|
104
|
-
|
|
129
|
+
- **INV-PRM-9** Native file guidance describes the boundary accurately: absolute and `~` paths
|
|
130
|
+
are valid for read-only file tools, which remain bounded by OS permissions rather than the
|
|
131
|
+
workspace root. Native file writes and Bash filesystem effects are workspace-scoped by default;
|
|
132
|
+
the working folder itself is not the boundary. Side-question runs with no callable tools omit
|
|
133
|
+
tool guidance.
|
|
134
|
+
- **INV-PRM-10** Compaction checkpoints are assembled by this compiler, bounded, and delivered only
|
|
135
|
+
as ephemeral context while their active run continues. They do not change the stable system prompt
|
|
136
|
+
or native history, and do not carry hidden reasoning (PROP-0033, ADR-0032). A work-slice handoff is
|
|
137
|
+
the same kind of bounded projection: the `checkpoint` event is rendered into the continuation
|
|
138
|
+
section by `continuationBody`, never into the system prompt (PROP-0041).
|
|
139
|
+
- **INV-PRM-11** The Progress group names `checkpoint_write` when it is in the frozen capability
|
|
140
|
+
set, with the same budget as the other tool guidance, and says only that a bounded reply records a
|
|
141
|
+
handoff when its budget is reached. It does not describe the limits themselves, which the guard
|
|
142
|
+
states at the boundary.
|
|
105
143
|
|
|
106
144
|
## Relation to DESIGN-0001
|
|
107
145
|
|
|
@@ -17,7 +17,7 @@ callable result for one run.
|
|
|
17
17
|
| `Plugins` (`loading`, `loaded`) | `plugins/plugins.ts` | Chooses the paths a session or terminal loads; records what each extension registered. |
|
|
18
18
|
| discovery | `plugins/discover.ts` | Finds items with Pi's own resolver, which runs no extension code. |
|
|
19
19
|
| attachments (`load`, `save`, `attached`, `decided`, `set`) | `plugins/attachments.ts` | The one store of what is switched on, per scope. |
|
|
20
|
-
| `BuiltinPluginRegistry`, `BuiltinPluginModule` | `plugins/builtinRegistry.ts`, `plugins/builtin.ts` | Registers built-in modules and their descriptors, world parts, server handlers and terminal
|
|
20
|
+
| `BuiltinPluginRegistry`, `BuiltinPluginModule` | `plugins/builtinRegistry.ts`, `plugins/builtin.ts` | Registers built-in modules and their descriptors, world parts, server handlers and plugin-owned terminal commands. Harness core commands live in `commands/registry.ts`, shared by both surfaces. |
|
|
21
21
|
| `HARNESS_PLUGINS` | `plugins/builtin.ts` | Descriptor view of the registered Harness parts and feature plugins. |
|
|
22
22
|
| `FIRST_PARTY_PLUGINS` | `plugins/firstParty.ts` | `output-trim`, `budget-guard`: inline extensions shipped switched off. `lessons`: switched off; its contribution turns on reflection after a run (page 08, PROP-0008) and loads no Pi code. |
|
|
23
23
|
| `Hooks` | `plugins/hooks.ts` | Runs a package's hooks file after a write. |
|
|
@@ -29,14 +29,26 @@ callable result for one run.
|
|
|
29
29
|
## Contracts
|
|
30
30
|
|
|
31
31
|
- **Loading.** `Plugins.loading({ cwd, agentDir, caller, contributions, install? })` returns
|
|
32
|
-
`extensionPaths`, `skillPaths`, `promptPaths`, `themePaths`, `builtins` (
|
|
32
|
+
`extensionPaths`, `skillPaths`, `promptPaths`, `themePaths`, `builtins` (legacy shape; no Pi CLI built-ins selected), `hooks`,
|
|
33
33
|
`found`, `detached`, `projectCode`, `packageCode`. A session opens Pi with its own discovery off
|
|
34
34
|
and only these paths; a terminal receives them as `--extension`, `--skill`,
|
|
35
35
|
`--prompt-template` and `--theme` after `--no-extensions --no-skills --no-prompt-templates
|
|
36
36
|
--no-themes`. Pi still reads `AGENTS.md` and `SYSTEM.md` itself.
|
|
37
|
+
- **Surface metadata (PROP-0040).** `PluginDescriptor.surfaces` and `Plugin.surfaces` optionally
|
|
38
|
+
carry `{ preferred: 'host', terminal: 'fallback' | 'unavailable', note: string }`.
|
|
39
|
+
`plugins/surfaces.ts` formats the note and badge. Inspection explains what the host adds and
|
|
40
|
+
what the terminal does instead; this is not a category, attachment switch or permission.
|
|
41
|
+
- **Shared resources (PROP-0040).** Both surfaces load Harness-selected resources and enabled
|
|
42
|
+
first-party hooks, including output trim and budget guard. Terminal preparation exposes these
|
|
43
|
+
through its protected bridge. Pi CLI-only llama.cpp, codemode, tool-search and MCP built-ins are
|
|
44
|
+
not selected or advertised as extra terminal capabilities. This does not remove Harness MCP.
|
|
37
45
|
- **Attachments.** `config/plugin-attachments.json` holds `global`, `agents`, `projects` (each
|
|
38
46
|
`{ on, off }`) and `settings` per plugin. The narrowest scope that says something wins: agent,
|
|
39
47
|
then project, then everywhere. With no entry an item keeps its default.
|
|
48
|
+
- **Package metadata.** A Pi package may declare `"harness": { "extends": [...], "hooks": "./hooks.mjs", "commandPrefix": "my-tools" }`.
|
|
49
|
+
`commandPrefix` is optional; in the terminal, commands otherwise use a normalized package name as
|
|
50
|
+
their owner prefix. Prefixes use lowercase letters, digits and hyphens, starting with a letter;
|
|
51
|
+
`plugin` and `skill` are reserved. See page 11 for the command route and collision rules.
|
|
40
52
|
- **Hooks.** A package declares `"harness": { "extends": [...], "hooks": "./hooks.mjs" }`. Events:
|
|
41
53
|
`wiki.page.saved`, `history.run.ended`. A hook has 30 seconds; its errors are kept in
|
|
42
54
|
`plugin-hooks.json`. `ctx.call(connection, tool, args)` reaches only a connected app that is on
|
|
@@ -48,7 +60,10 @@ callable result for one run.
|
|
|
48
60
|
capability. Automatic or refinement-triggered continuations with it are rejected rather than
|
|
49
61
|
weakening the frozen set. The `side-questions` descriptor owns the fixed instruction for the
|
|
50
62
|
restricted side-question run; it has no tools, providers, connectors, subagents or variant code
|
|
51
|
-
(PROP-0019).
|
|
63
|
+
(PROP-0019). In plan mode, delegation is limited to research children: the resolved profile must
|
|
64
|
+
have explicit tool and plugin allowlists confined to the research set, and the child's frozen
|
|
65
|
+
capabilities are intersected with the parent and profile. A profile name or its instructions alone
|
|
66
|
+
never grants eligibility (INV-RUN-8).
|
|
52
67
|
|
|
53
68
|
## Invariants
|
|
54
69
|
|
|
@@ -78,9 +93,11 @@ callable result for one run.
|
|
|
78
93
|
parts are required and refuse to be switched off; switching something on grants no permission.
|
|
79
94
|
A side-question run also has no variant plugin code or tool guidance (PROP-0019).
|
|
80
95
|
- **INV-PLG-10** Every Harness-managed built-in feature is registered by `BuiltinPluginRegistry`.
|
|
81
|
-
Its descriptor, world tools, server handlers and terminal
|
|
82
|
-
|
|
83
|
-
|
|
96
|
+
Its descriptor, world tools, server handlers and any plugin-owned terminal commands share one
|
|
97
|
+
owner. First-class Harness terminal commands are registered by the terminal command registry and
|
|
98
|
+
do not depend on a feature plugin's command metadata or attachment state. A module's world part
|
|
99
|
+
releases resources through the existing session and Harness lifecycle. This registry does not
|
|
100
|
+
load third-party Pi code or bypass its trust checks.
|
|
84
101
|
- **INV-PLG-11** Built-in plugin categories are a documentation ownership taxonomy. They are not a
|
|
85
102
|
`PluginDescriptor` field, a public response field or a second attachment scope.
|
|
86
103
|
- **INV-CAP-1** A capability set only narrows. `intersect` never adds access; a run's set is
|
|
@@ -119,7 +136,7 @@ metadata or availability:
|
|
|
119
136
|
| Memory | Wiki, history and trajectory | Storage and run records remain Foundation-owned services |
|
|
120
137
|
| Automation | Subagents, ask-user, checklist, lessons and refinement | Run lifecycle, capability narrowing and approval gate remain Foundation-owned |
|
|
121
138
|
| Integrations | Connected apps/MCP and Hub | Connector credentials and plugin installation remain behind Foundation services |
|
|
122
|
-
| Operations | Doctor and
|
|
139
|
+
| Operations | Doctor, worktrees and usage | Diagnostics, repository operations and usage analytics remain Harness-managed services |
|
|
123
140
|
|
|
124
141
|
## Terminal resource inspection
|
|
125
142
|
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
A run's tools come from four places: the harness's own tools, the connected-apps broker,
|
|
6
6
|
subagent tools, and the application's tool providers. Every call, whatever its source, passes one
|
|
7
|
-
per-call gate
|
|
7
|
+
per-call gate. Native writes also obey the run's pinned workspace boundary, with shell writes
|
|
8
|
+
contained by an OS sandbox; the gate then applies application policy, standing approvals and the
|
|
9
|
+
person without letting remembered per-tool grants widen that boundary.
|
|
8
10
|
|
|
9
11
|
## Components
|
|
10
12
|
|
|
@@ -14,39 +16,89 @@ per-call gate that asks the application's policy, then standing approvals, then
|
|
|
14
16
|
| `dispatch` | `tools/dispatch.ts` | One entry point for every History, Wiki and skill call, from a Pi tool, the server or a terminal. |
|
|
15
17
|
| `harnessTools` | `tools/harnessTools.ts` | The definitions as `ToolSpec`s for one session. |
|
|
16
18
|
| `askUserTool` (`ask_user`) | `tools/askUser.ts` | Stops an attended plan run and asks up to five related questions with choices and concise 1–2 word labels; absent from newly resolved normal runs. |
|
|
17
|
-
| `checklistTool` (`checklist_write`) | `tools/checklist.ts` | Writes the run's whole checklist as a `checklist.updated` event (PROP-0006). Read-only for the gate, so plan mode allows it. Terminal sessions register the same tool; it reaches the run through the `checklist` telemetry call. The prompt's Progress group asks the model to keep it current
|
|
18
|
-
| `subagentTools` | `tools/spawnSubagent.ts` | `spawn_subagent` (requires a short `title`, PROP-0030)
|
|
19
|
+
| `checklistTool` (`checklist_write`) | `tools/checklist.ts` | Writes the run's whole checklist as a `checklist.updated` event (PROP-0006). Read-only for the gate, so plan mode allows it. Terminal sessions register the same tool; it reaches the run through the `checklist` telemetry call. The prompt's Progress group asks the model to keep it current and write one final update before replying; unfinished work is not automatically marked complete. |
|
|
20
|
+
| `subagentTools` | `tools/spawnSubagent.ts` | `spawn_subagent` (requires a short `title`, PROP-0030) and `wait_subagents`; normal-mode descriptions guide selective, bounded delegation, while plan-mode spawns require a named eligible read-only research profile. |
|
|
19
21
|
| `annotationsPart` (`page_notes_list`, `page_notes_read`, `page_notes_mark_fixed`) | `annotations/part.ts` | World tools over the page notes a person shared with the session or agent (PROP-0017). `page_notes_mark_fixed` records the agent's claim that it fixed a note it was sent; it never resolves a note or changes grants (PROP-0018). |
|
|
20
22
|
| `webTools` | `web/tools.ts` | `web_search` (Brave, key from the secret store), `web_fetch` (checked public reads). An application provides them as a provider. |
|
|
21
23
|
| gate | `sessions/sessions.ts::gate`, `sessions/runner.ts` | `ToolGate { ask, check }`, loaded as the last extension (`xagent-approvals`). |
|
|
22
24
|
| `Approvals`, `decide`, `grant`, `approvalKey` | `sessions/approvals.ts` | Standing approvals. |
|
|
23
25
|
|
|
24
|
-
Harness tools: `
|
|
25
|
-
`wiki_search`, `wiki_read`, `wiki_list`, `wiki_write`
|
|
26
|
-
`ask_user` (attended plan runs and pinned continuations only),
|
|
26
|
+
Harness tools: `get_capabilities` (read-only current-run discovery), `history_search`, `history_read`,
|
|
27
|
+
`trajectory_search`, `trajectory_read`, `wiki_search`, `wiki_read`, `wiki_list`, `wiki_write`
|
|
28
|
+
(not in the default set), `skill_load`, `ask_user` (attended plan runs and pinned continuations only),
|
|
29
|
+
`checklist_write`. Broker:
|
|
27
30
|
`mcp_list_tools`, `mcp_call_tool`. Native Pi tools: `read`, `grep`, `find`,
|
|
28
31
|
`ls`, `edit`, `write`, `bash`.
|
|
29
32
|
|
|
33
|
+
## Cross-surface registration (PROP-0040)
|
|
34
|
+
|
|
35
|
+
The terminal registers Harness History/trajectory, Wiki-read and skill tools through
|
|
36
|
+
`Terminals.ownTools` and dispatches them over the session socket; they are model tools, not merely
|
|
37
|
+
shell commands. Enabled first-party hooks load through the protected `firstParty.list` bridge and
|
|
38
|
+
`terminal/piExtension.ts`. Attended planning uses the shared `ask_user`; the terminal-only question
|
|
39
|
+
alias is removed.
|
|
40
|
+
|
|
41
|
+
`get_capabilities` is implemented as a read-only Harness tool. Structured sessions register it from
|
|
42
|
+
the current run's frozen capability snapshot and live Pi tool/schema inventory. The terminal
|
|
43
|
+
extension (`terminal/piExtension.ts`) registers the same schema from Pi's active and registered tools;
|
|
44
|
+
when plan mode is active it reports the plan's allowed tool set. `sessions/planMode.ts` includes it in
|
|
45
|
+
the shared read-only allowlist. Host sessions use this Harness tool rather than defining a duplicate.
|
|
46
|
+
It reports availability, never permission, and every call remains subject to the gate.
|
|
47
|
+
|
|
30
48
|
## Native file paths
|
|
31
49
|
|
|
32
50
|
The read-only `read`, `grep`, `find` and `ls` tools accept paths relative to the working folder,
|
|
33
|
-
absolute paths, and `~` paths. The working folder is a default location, not a
|
|
34
|
-
|
|
35
|
-
guidance names the configured data root.
|
|
36
|
-
|
|
51
|
+
absolute paths, and `~` paths. The working folder is a default location, not a read boundary; the
|
|
52
|
+
operating system's access for the Harness process decides what can be read. The compiled file
|
|
53
|
+
guidance names the configured data root. Each run pins `workspaceRoot`: the nearest Git root or
|
|
54
|
+
worktree above its effective working directory, or the canonical working directory when there is no
|
|
55
|
+
repository. The filesystem root itself is rejected because it would collapse the write boundary.
|
|
56
|
+
`edit` and `write` resolve targets canonically, revalidate the pinned target at mutation,
|
|
57
|
+
and atomically replace the directory entry in a helper process constrained by the OS sandbox. This
|
|
58
|
+
prevents hard-link writes from changing another alias; normal file mode is retained where possible,
|
|
59
|
+
but ACLs and extended attributes are not guaranteed to survive replacement. An outside target
|
|
60
|
+
requires a human-only one-call approval (or an eligible Full Permission answer) and is not covered by
|
|
61
|
+
remembered tool grants.
|
|
62
|
+
|
|
63
|
+
Bash, including an initial `!` command, runs in an OS-enforced sandbox that permits broad reads but
|
|
64
|
+
writes only inside the root. Before default-scope Bash, Harness scans the workspace for regular-file
|
|
65
|
+
inodes with links outside it; an incomplete scan or possible external alias blocks the command, which
|
|
66
|
+
must be repaired or copied. The sandbox also prevents its own processes from creating cross-boundary
|
|
67
|
+
hard links; macOS denies hard-link creation entirely, including within the workspace. A local process
|
|
68
|
+
outside Harness running as the same user is outside this protection.
|
|
69
|
+
The Bash tool's optional `workspaceWriteScope` defaults to `workspace`; `outside` requests a
|
|
70
|
+
human-only one-call approval before the exact command runs once with broader filesystem access. The
|
|
71
|
+
approval shows the full escaped command in scrollable details and fails closed if the terminal
|
|
72
|
+
cannot show both the details and the choices. The terminal uses `!outside <command>` for the same
|
|
73
|
+
explicit request on a direct initial command.
|
|
74
|
+
stdout/stderr never proves a sandbox denial: denial text cannot request approval, and a command is
|
|
75
|
+
never replayed after partial effects. Full Permission is the explicit eligible-run bypass.
|
|
76
|
+
Unsupported or unavailable sandbox enforcement fails closed. A side-question run has an empty
|
|
77
|
+
capability set and no tools (PROP-0019).
|
|
37
78
|
|
|
38
79
|
## The gate, per call
|
|
39
80
|
|
|
81
|
+
For native `edit` and `write`, the canonical target check is added to policy scope before approval;
|
|
82
|
+
the registered tool can mutate only through the policy-bound atomic helper. Bash workspace scope
|
|
83
|
+
scans for external hard links and then runs under the OS sandbox. An explicit outside scope is
|
|
84
|
+
approved before execution and runs once; stdout/stderr never triggers approval or retry. The
|
|
85
|
+
eligible Full Permission switch may answer the explicit request under its existing restrictions, but
|
|
86
|
+
a remembered tool grant cannot.
|
|
87
|
+
|
|
40
88
|
```text
|
|
41
89
|
child run and tool outside its snapshot ─► refuse
|
|
42
|
-
plan mode and tool not research-safe
|
|
90
|
+
plan mode and tool/call not research-safe ─► refuse (including ineligible spawn profiles, outside-scope or denied Bash; before approvals)
|
|
91
|
+
plan-mode Bash ─► read-only OS sandbox, never widened, run once
|
|
92
|
+
canonicalize native write target / verify pinned root
|
|
43
93
|
policy.scope(call)
|
|
44
94
|
not allowed and (automatic or no approval possible) ─► refuse with reason
|
|
45
95
|
policy.authorize(call) throws ─► refuse
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
96
|
+
outside native file target ─► human-only one-call approval; eligible Full Permission may answer
|
|
97
|
+
Bash workspace scope ─► hard-link scan, OS sandbox, run once
|
|
98
|
+
Bash outside scope ─► pre-execution human-only approval, then run once unconfined
|
|
99
|
+
trigger probe, improver, reflection or unattended ─► refuse anything requiring a person
|
|
100
|
+
run.requestApproval(...) ─► standing approvals may answer where eligible, else the person
|
|
101
|
+
denied ─► refuse; never replay a command
|
|
50
102
|
policy.authorize(call) again ─► run or refuse
|
|
51
103
|
```
|
|
52
104
|
|
|
@@ -60,23 +112,49 @@ the switch and global tools.
|
|
|
60
112
|
|
|
61
113
|
- **INV-GATE-1** Every tool call of every run passes the gate. No tool source bypasses it,
|
|
62
114
|
including extension-registered tools (which ask before every call) and the initial Bash command.
|
|
115
|
+
- **INV-TOOL-9** `checkpoint_write` records one bounded handoff for the active run and is read-only
|
|
116
|
+
and plan-safe: no field changes files, and the record is the `checkpoint` run event (PROP-0041).
|
|
117
|
+
- **INV-TOOL-10** Bash keeps one command budget on every surface: 120 seconds when the call says
|
|
118
|
+
nothing, 300 seconds as the ceiling without a `reason`, 900 seconds as the maximum, and a timeout
|
|
119
|
+
returns the partial output with a narrowing instruction instead of blocking the reply.
|
|
63
120
|
- **INV-GATE-2** The gate is the last extension loaded, after disk, variant and inline extensions, so
|
|
64
121
|
it sees the final input of every call.
|
|
65
|
-
- **INV-GATE-3** Order is fixed: capability and plan-mode refusals,
|
|
66
|
-
|
|
122
|
+
- **INV-GATE-3** Order is fixed: capability and plan-mode refusals, canonicalize native file-write
|
|
123
|
+
targets, consult the policy's scope and authorize, combine mandatory outside-write approval with
|
|
124
|
+
that scope, then eligible standing approvals or the person, then authorize again. Native mutations
|
|
125
|
+
revalidate the authorized target and use atomic replacement inside an OS-enforced write scope.
|
|
126
|
+
Default Bash scans for external hard links, then runs only inside the OS sandbox. `workspaceWriteScope:
|
|
127
|
+
'outside'` requests human-only approval before running that exact command once with broader access.
|
|
128
|
+
Command output never proves a sandbox denial and never triggers approval or replay; earlier
|
|
129
|
+
side-effects are not repeated. The policy may tighten or deny a call, but cannot waive the boundary.
|
|
130
|
+
Outside file writes and broad Bash calls cannot use remembered per-tool approval; only the eligible
|
|
131
|
+
Full Permission switch can answer automatically under its existing restrictions. In plan mode, Bash
|
|
132
|
+
runs only in the read-only scope (PROP-0043): no writes but a discarded temp folder, no network,
|
|
133
|
+
no signals outside the sandbox, no macOS mach services; Full Permission and `outside` never apply.
|
|
67
134
|
- **INV-GATE-4** Refinement runs (`probe`, `improver`) never ask a person; what would need one is
|
|
68
135
|
refused, never queued (`INV-REF-4`).
|
|
69
136
|
- **INV-GATE-5** SDK tools are registered only if their names are in the run's frozen capability
|
|
70
|
-
set (`INV-CAP-1`).
|
|
71
|
-
|
|
72
|
-
|
|
137
|
+
set (`INV-CAP-1`). `get_capabilities` is a read-only Harness tool on structured and terminal
|
|
138
|
+
surfaces; it reports the frozen callable set and does not grant access. The terminal may retain
|
|
139
|
+
question-tool definitions in its private Pi inventory, but normal mode deactivates them; a plan
|
|
140
|
+
request activates only registered questions under its plan-mode gate.
|
|
73
141
|
- **INV-GATE-6** Tool attachment bytes never enter the run-event stream; only references are
|
|
74
142
|
recorded.
|
|
75
143
|
- **INV-GATE-7** Tool descriptions name the product with `{product}` (filled by `describeTool`),
|
|
76
144
|
never an application's name (`INV-BND-2`).
|
|
77
|
-
- **INV-GATE-8** Native
|
|
78
|
-
|
|
79
|
-
|
|
145
|
+
- **INV-GATE-8** Native reads are bounded by process and operating-system permissions, not by the
|
|
146
|
+
workspace root; absolute and `~` paths are valid. Every run pins its canonical `workspaceRoot`.
|
|
147
|
+
Native `edit` and `write` mutations revalidate the authorized canonical target and atomically
|
|
148
|
+
replace it under an OS-enforced scope; outside targets require human-only one-call approval and
|
|
149
|
+
cannot use remembered tool grants. Default Bash scans the workspace for possible outside hard-link
|
|
150
|
+
aliases and is OS-sandboxed to write only inside the root while retaining broad reads; the sandbox
|
|
151
|
+
prevents its own processes from creating cross-boundary hard links, and macOS denies all hard-link
|
|
152
|
+
creation in the sandbox. An incomplete scan or missing
|
|
153
|
+
enforcement fails closed. An explicit `workspaceWriteScope: 'outside'` request is approved before
|
|
154
|
+
execution and runs once; command output never triggers approval or retry. The terminal exposes the
|
|
155
|
+
same choice as `!outside <command>`. Full Permission is the only standing boundary bypass and
|
|
156
|
+
remains subject to host policy, authorization, read-only, plan, unattended, probe, improver and
|
|
157
|
+
reflection restrictions. The rule does not protect against a peer process running as the same user.
|
|
80
158
|
|
|
81
159
|
## Data
|
|
82
160
|
|
|
@@ -85,7 +163,9 @@ the switch and global tools.
|
|
|
85
163
|
## Source map
|
|
86
164
|
|
|
87
165
|
`src/tools/*.ts`, `src/web/*.ts`, `src/sessions/sessions.ts`, `src/sessions/runner.ts`,
|
|
88
|
-
`src/sessions/
|
|
166
|
+
`src/sessions/workspaceBoundary.ts`, `src/sessions/initialBash.ts`, `src/core/workspaceBashTool.ts`,
|
|
167
|
+
`src/core/workspaceSandbox.ts`, `src/core/workspaceWriteOperations.ts`, `src/sessions/approvals.ts`,
|
|
168
|
+
`src/sessions/policy.ts`. Decision: [ADR-0036](../decisions/ADR-0036-workspace-write-operation-boundary.md).
|
|
89
169
|
|
|
90
170
|
## Session naming (PROP-0010)
|
|
91
171
|
|