@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
|
@@ -55,7 +55,9 @@ rebuildable SQLite index.
|
|
|
55
55
|
lessons; nothing is evicted.
|
|
56
56
|
- The `wiki` pointer section says how many lessons there are when there are any.
|
|
57
57
|
- **Index.** Every finished run is indexed when it ends; `open` and `rebuildIndex()` sync from
|
|
58
|
-
`runs/`.
|
|
58
|
+
`runs/`. The same pass writes the **usage ledger**: one `usage_requests` row per model request
|
|
59
|
+
from the run's `usage.updated` events, and one `usage_indexed` marker per run (PROP-0042).
|
|
60
|
+
`/usage:analysis` queries only that ledger; it is derived and rebuilt from run events.
|
|
59
61
|
|
|
60
62
|
## Invariants
|
|
61
63
|
|
|
@@ -84,7 +86,7 @@ rebuildable SQLite index.
|
|
|
84
86
|
<data root>/wiki/ home.md, library/, projects/<slug>/
|
|
85
87
|
<data root>/wiki-history/ earlier versions of notes
|
|
86
88
|
<data root>/legacy/ an earlier Wiki's memory blocks, facts, revisions, Inbox (moved once)
|
|
87
|
-
<data root>/index.sqlite derived: pages, links, runs, recall passages (FTS5)
|
|
89
|
+
<data root>/index.sqlite derived: pages, links, runs, recall passages (FTS5), usage rows
|
|
88
90
|
<data root>/projects.json read only: the application owns it
|
|
89
91
|
```
|
|
90
92
|
|
|
@@ -67,7 +67,7 @@ skills, prompts, rules and Pi packages.
|
|
|
67
67
|
## Data
|
|
68
68
|
|
|
69
69
|
```text
|
|
70
|
-
<state dir>/accounts/ registry, per-account Pi agent folders, _shared/pi/, audit log
|
|
70
|
+
<state dir>/accounts/ registry, per-account Pi agent folders, _shared/pi/, audit log, per-account state (health, plan, limits)
|
|
71
71
|
<state dir>/secrets.json default SecretStore (owner-only)
|
|
72
72
|
<state dir>/connections.json connected apps, no secrets
|
|
73
73
|
<state dir>/hub/catalog.json catalog cache
|
|
@@ -89,6 +89,36 @@ at 64 tokens, and records usage through the normal run writer. It never substitu
|
|
|
89
89
|
MCP live diagnostics connect and list tools on the selected scoped connector, without calling
|
|
90
90
|
connector tools or starting sign-in. Disposable grants and clients are closed afterwards.
|
|
91
91
|
|
|
92
|
+
## Provider limits (PROP-0042)
|
|
93
|
+
|
|
94
|
+
A limit reading says what a provider itself reported: a plan window, a credit balance, a rate
|
|
95
|
+
limit, or a configured organization limit. Three sources are used, in order:
|
|
96
|
+
|
|
97
|
+
1. **Response headers** on the account's own model requests. Each account runtime's providers are
|
|
98
|
+
wrapped so `onResponse` sees status and headers; a terminal session's own runtime forwards only
|
|
99
|
+
the limit-bearing headers to the parent over the control-key-protected session socket.
|
|
100
|
+
`usage/limits/normalize.ts` understands `anthropic-ratelimit-*`, Anthropic unified plan windows,
|
|
101
|
+
`x-codex-*` and `x-ratelimit-*`, plus `Retry-After` on a 429. Raw headers are never stored.
|
|
102
|
+
2. **The provider's own usage endpoint**, read with `Models.getAuth(provider)` so OAuth refresh
|
|
103
|
+
stays in Pi's serialized credential path: OpenRouter `GET /api/v1/key`, DeepSeek
|
|
104
|
+
`GET /user/balance`, Anthropic's organization `rate_limits` for an admin API key (configured
|
|
105
|
+
limits, not usage), ChatGPT/Codex `GET https://chatgpt.com/backend-api/wham/usage`, and
|
|
106
|
+
OpenCode Go `GET https://opencode.ai/zen/go/v1/usage`. A Codex request carries the account id
|
|
107
|
+
from the access token's JWT claim; an OpenCode Go request carries the account's API key.
|
|
108
|
+
The request is a bounded HTTPS GET that refuses redirects, caps its body, and never puts a
|
|
109
|
+
credential in an error. An endpoint reading replaces every limit for that provider; a header
|
|
110
|
+
reading only merges the windows it saw.
|
|
111
|
+
3. **Unavailable**, with a reason. No percentage is invented; local usage is shown instead.
|
|
112
|
+
|
|
113
|
+
Undocumented endpoints require the usage plugin's `experimentalProbes` setting. Readings are
|
|
114
|
+
cached for `refreshMinutes` (default 10) and refreshed on a page open or an explicit refresh, never
|
|
115
|
+
by a background timer. They are stored in the account's existing state (`limits`,
|
|
116
|
+
`providerLimits`), never in a new file, and no credential is written. A reading carries both `usedPercent` and the additive
|
|
117
|
+
`remainingPercent`. The Limits page is a centered dialog: each window is a label and reset line
|
|
118
|
+
above a quota-left bar, green at 50% or more left, amber from 20–49%, and red below 20%. It adds
|
|
119
|
+
the local seven-day ledger without a label, so a provider's zero reading and this app's own use
|
|
120
|
+
are not confused.
|
|
121
|
+
|
|
92
122
|
## Terminal connection setup
|
|
93
123
|
|
|
94
124
|
The unified browser exposes existing connection save/test/sign-in/sign-out/remove services through
|
|
@@ -33,7 +33,7 @@ harness → host { v: 1, id, call, params } host → harness { v: 1
|
|
|
33
33
|
- `harness.methods` lists every method. Groups in the table: `accounts`, `harnesses`, `runs`,
|
|
34
34
|
`connections`, `plugins`, `wiki`, `refine`, `capabilities`, `hub`, `terminal`, `approvals`,
|
|
35
35
|
`harness`, `subagents`, `agents`, `sessions`, `sideQuestions`, `library`, `recall`, `context`,
|
|
36
|
-
`worktrees`, `annotations`.
|
|
36
|
+
`worktrees`, `annotations`, `commands`, `usage`.
|
|
37
37
|
- Host calls (only with the matching `--host-*` flag): `secrets.get|set|delete`,
|
|
38
38
|
`policy.scope|authorize|approval|connections`, `tools.call`. The host registers tools with
|
|
39
39
|
`tools.register` and names with `directory.set`, and describes its parts with
|
|
@@ -41,16 +41,69 @@ harness → host { v: 1, id, call, params } host → harness { v: 1
|
|
|
41
41
|
- `refine.start` takes `{ task, k?, mode?, improver?, executor?, baseVersion?, retainWorkspaces?, id? }`;
|
|
42
42
|
`refine.candidates` returns each execution with `workspace: string | null` (page 05, PROP-0002, PROP-0003).
|
|
43
43
|
- `runs.checklist { runId }` returns the run's latest checklist, `[]` when it wrote none (PROP-0006).
|
|
44
|
+
- Run records include optional nullable `workspaceRoot`, the canonical root whose files a run may
|
|
45
|
+
modify by default (page 02). New Harness runs set it; older records may omit it. Hosts must
|
|
46
|
+
tolerate the additive field and must not nominate or widen the root.
|
|
44
47
|
- `agents.list { cwd? }` returns `{ profiles, problems }`; `agents.get { cwd?, name }` one profile;
|
|
45
48
|
`agents.create { cwd?, name, scope: 'global' | 'project', from? }` writes the template or a copy
|
|
46
49
|
and refuses an existing file; `agents.remove { cwd?, name, scope }` deletes a person's own file.
|
|
47
50
|
`subagents.spawn` takes `agent` as a profile name and returns `agent` and `unavailableTools`
|
|
48
51
|
(PROP-0029). It takes an optional `title` (at most six words); without one the child's title is
|
|
49
52
|
the first line of its brief (PROP-0030).
|
|
50
|
-
- `runs.continuation { runId, sessionDir? }` returns a `Continuation
|
|
51
|
-
`continueFrom` (page 02, PROP-0007)
|
|
53
|
+
- `runs.continuation { runId, sessionDir? }` returns a `Continuation` (its `checkpoint` is the last
|
|
54
|
+
work-slice handoff), and `sessions.run` accepts `continueFrom` (page 02, PROP-0007) and `workSlice`
|
|
55
|
+
(PROP-0041). `harness.status` reports `recovery.interruptedRunIds`.
|
|
56
|
+
- `workSlice { enabled?, maxToolCalls?, maxMinutes?, maxNewTokens?, maxSlices?, continue? }` on
|
|
57
|
+
`sessions.run` bounds that reply; absent uses 160 calls, 40 minutes, 320 000 new tokens, 8 slices and
|
|
58
|
+
automatic continuation. A token cap counts new input, cache writes and output, never the cached
|
|
59
|
+
prefix. `enabled: false` turns the guard off for that run; `XINGULAR_WORK_SLICE=off` in the
|
|
60
|
+
launching process turns it off for every run in it, and nothing is persisted. The policy is
|
|
61
|
+
carried into the continuation. A value outside its range is refused with `invalid_request` before
|
|
62
|
+
the run record is written.
|
|
63
|
+
- The run-event stream adds `checkpoint` (the bounded handoff) and `heartbeat` (steps, elapsed time,
|
|
64
|
+
last tool, compactions, slice, call budget). Hosts must accept both; an unknown event type is still
|
|
65
|
+
relayed in order (INV-RUN-3).
|
|
52
66
|
- Errors carry a stable `code`, a message and an optional hint (`core/errors.ts`).
|
|
53
67
|
|
|
68
|
+
## Usage (PROP-0042)
|
|
69
|
+
|
|
70
|
+
| Method | Input | Reply |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `usage.summary` | `{ scope?: "session" \| "account" \| "project" \| "all", sessionId?, accountId?, projectId?, period?: "today" \| "7d" \| "30d" \| "all", timezoneOffsetMinutes? }` | `UsageSummary`: totals, cache hit rate, latency, day/model/provider/account/session breakdowns, unpriced count, ledger time |
|
|
73
|
+
| `usage.limits` | `{ accountId?, refresh?: boolean }` | `UsageLimitsReport`: per account and provider, the reading source, reason, observed time and limits |
|
|
74
|
+
| `usage.sync` | `{}` | `{ runs, indexed, lastIndexedAt }` |
|
|
75
|
+
|
|
76
|
+
The methods are contributed by the built-in `usage` plugin module and read only derived or stored
|
|
77
|
+
data; `refresh: true` is the only form that may contact a provider, once per due provider. The
|
|
78
|
+
terminal reaches the same service through protected `terminal.usage.summary|limits`, whose scope
|
|
79
|
+
comes from the terminal session, never from the request.
|
|
80
|
+
|
|
81
|
+
## Commands and session controls (PROP-0040)
|
|
82
|
+
|
|
83
|
+
`commands.list { cwd?, accountId?, agentId?, projectId? }` returns `ListedCommand[]`: `name`,
|
|
84
|
+
optional `aliases`, `args`, `description`, `owner`, plus `group`, `source`
|
|
85
|
+
(`core | plugin | extension | prompt | skill`) and optional core `kind` (`session | page | local`).
|
|
86
|
+
Core metadata comes from `commands/registry.ts`; effective plugin contributions supply other routes.
|
|
87
|
+
Namespace/collision rules are shared; discovery neither runs a command nor proves surface acceptance.
|
|
88
|
+
|
|
89
|
+
For the methods below, `ref` means `{ sessionDir, sessionFile?, cwd? }`.
|
|
90
|
+
|
|
91
|
+
| Method | Input | Reply |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| `sessions.tree` | `ref` | `SessionTree`: file, leaf, entries and user-message fork points |
|
|
94
|
+
| `sessions.navigate` | `ref + { entryId }` | `{ leafId, editorText? }`; no summary/model request |
|
|
95
|
+
| `sessions.fork` | `ref + { entryId, targetDir }` | `{ sessionFile, editorText }` |
|
|
96
|
+
| `sessions.clone` | `ref + { targetDir }` | `{ sessionFile }` |
|
|
97
|
+
| `sessions.rename` | `ref + { name }` | `{ name }` |
|
|
98
|
+
| `sessions.lastReply` | `ref` | `{ text: string | null }` |
|
|
99
|
+
| `sessions.export` | `ref + { path }` | `{ path }`; absolute `.jsonl` branch export |
|
|
100
|
+
| `sessions.reload` | `{}` | `{ reloaded: true }`; reloads persistent hooks; structured turns load resources fresh |
|
|
101
|
+
|
|
102
|
+
`sessions.run` also accepts `command` for compact, navigation with optional summary, or HTML
|
|
103
|
+
export instead of prompt submission (page 02). These retain tracked run lifecycle and pins.
|
|
104
|
+
Saved-history helpers currently validate file scope but do not themselves fence active work;
|
|
105
|
+
host adapters must not infer concurrency safety from method availability.
|
|
106
|
+
|
|
54
107
|
## Invariants
|
|
55
108
|
|
|
56
109
|
- **INV-SRV-1** `src/server/methods.ts` is the contract for every non-Node host. Adding a method
|
|
@@ -129,6 +182,8 @@ from preparation, never from the request.
|
|
|
129
182
|
| `terminal.browser.connections.appClients` | `{}` | Existing available application OAuth catalog IDs |
|
|
130
183
|
| `terminal.browser.connections.save` | `{ input: ConnectionInput }` | Existing safe `Connection` record |
|
|
131
184
|
| `terminal.browser.connections.test\|signIn\|signOut\|remove` | `{ id }` | Existing connection service result |
|
|
185
|
+
| `terminal.usage.summary\|limits` | `{ scope, period, timezoneOffsetMinutes }` / `{ refresh? }` | Existing usage service result, scoped to this terminal's account and project |
|
|
186
|
+
| `terminal.usage.headers` | `{ provider, status, headers }` | `{}`; only limit-bearing headers, throttled, stored as an account limit reading |
|
|
132
187
|
|
|
133
188
|
Protected `plugins.install { source }` and `plugins.remove { pluginId }` delegate to the package
|
|
134
189
|
service. Optional matching callbacks extend `PluginControl`; hosts without them receive a clear
|
|
@@ -34,32 +34,56 @@ Screen: transcript above the composer, centred dialogs, full-screen resource bro
|
|
|
34
34
|
`--conditions=browser` and `dist/terminal-opentui.js`; no global `pi` is needed.
|
|
35
35
|
- The `piExtension` path is the final prepared extension argument; the runtime loads it as the
|
|
36
36
|
final trusted inline factory.
|
|
37
|
+
- Each terminal `begin` returns the run's pinned `workspaceRoot` to that extension. Native file
|
|
38
|
+
writes use the same revalidated atomic helper and OS write scope as SDK sessions. Terminal Bash,
|
|
39
|
+
including initial `!` commands, defaults to the workspace sandbox and external-hard-link scan;
|
|
40
|
+
`!outside <command>` requests human-only approval before that exact command runs once; its full
|
|
41
|
+
escaped command is available in scrollable approval details, and an undersized terminal denies
|
|
42
|
+
the request. The eligible Full Permission switch is the only standing boundary bypass; remembered
|
|
43
|
+
per-tool grants do not widen it, and command output never triggers approval or replay.
|
|
37
44
|
- The terminal compiles its prompt once (`compile` + `render`) and keeps that pack; each run
|
|
38
|
-
records a copy (page 04).
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
records a copy (page 04). The shared compaction checkpoint extension reintroduces the active
|
|
46
|
+
request and latest checklist into post-compaction model context until the run settles.
|
|
47
|
+
- Normal mode keeps `ask_user` out of the active tool set. An attended plan request enables the
|
|
48
|
+
shared tool alongside its read-only set and restores the normal set on success, failure or
|
|
49
|
+
interruption. There is no terminal-only question alias (PROP-0040).
|
|
50
|
+
- A plan request keeps `bash` in its active set; each call runs in the sandbox's read-only scope
|
|
51
|
+
(PROP-0043). A user `!` command is refused while a plan request runs.
|
|
52
|
+
- Current standalone source defaults: `~/.xingular-harness/{data,state}`; `npm run dev` uses
|
|
53
|
+
`~/.xingular-harness-dev/{data,state}`. The standalone development launch uses a file SecretStore
|
|
54
|
+
under its resolved development state directory, even when its profile names a host backend; it
|
|
55
|
+
does not use or alter host credentials. `--variant <scope>` explicitly selects a variant head.
|
|
56
|
+
PROP-0040 approves a shared Harness-owned interactive profile, neutral default scope and
|
|
57
|
+
credential backend; adoption and runtime verification remain in progress. Until that lands,
|
|
58
|
+
matching roots/scopes is explicit and matching roots alone does not share host Keychain secrets.
|
|
59
|
+
- `Launch.standard` supplies the shared role and folder text. History, Wiki and skill model tools
|
|
60
|
+
use the session socket; enabled output-trim/budget-guard hooks load through `firstParty.list`.
|
|
61
|
+
Pi CLI built-ins (llama.cpp, codemode, tool-search and MCP) are not loaded as a terminal-only
|
|
62
|
+
resource path. Harness MCP remains available.
|
|
44
63
|
- An empty conversation shows a centered welcome using `env.productName` (default `Xingular Agent`):
|
|
45
64
|
the first letter of a multiword name is the orange block mark and its remaining words are letter-spaced
|
|
46
65
|
in blue. The welcome adds a greeting, tagline and `/help` hint without replacing the composer or
|
|
47
66
|
status bar. Explicit host product names use the same generic formatting.
|
|
48
67
|
- `xagent --worktree [name]` (`-w`) starts in a new managed worktree of the current repository,
|
|
49
68
|
or in the named one, and prunes older managed worktrees (PROP-0016). A session that names a
|
|
50
|
-
worktree holds it for its whole life. `/worktree`
|
|
51
|
-
the frontend there (`TerminalRelaunch.cwd`),
|
|
52
|
-
working folder.
|
|
53
|
-
- Slash-command aliases share one registry entry: `/session (resume)`
|
|
54
|
-
|
|
69
|
+
worktree holds it for its whole life. `/worktree` opens the worktree page; selecting
|
|
70
|
+
one switches folders by asking the host to restart the frontend there (`TerminalRelaunch.cwd`),
|
|
71
|
+
as a new conversation: Pi keeps one history per working folder.
|
|
72
|
+
- Slash-command aliases share one registry entry: `/session (resume)` opens the full-screen, searchable
|
|
73
|
+
saved-session page with unnumbered title and metadata rows; `/history (tree)` navigates branches in
|
|
74
|
+
the current session, and `/btw (side)` asks a side
|
|
55
75
|
question through the Harness `SideQuestions` service. It uses the same account/model/effort,
|
|
56
76
|
mirrors the main run's redacted prompt and public evidence, starts a separate tool-free run, and
|
|
57
77
|
leaves the main conversation untouched. The dock streams, scrolls and copies the complete answer.
|
|
58
78
|
Aliases remain callable and searchable, but help and palette show only the canonical
|
|
59
|
-
entry.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
entry. `/usage:` and `/usage:analysis` open the usage page's Analysis tab, and `/usage:limit`
|
|
80
|
+
opens its Limits tab (PROP-0042); both are plugin-owned namespaced routes. The usage page is a
|
|
81
|
+
centered dialog: each window is a label and reset line above a quota-left bar coloured green at
|
|
82
|
+
50% or more left, amber from 20–49%, and red below 20%. `commands.list`
|
|
83
|
+
publishes the effective routes; the browser-safe core catalogue is `commands/registry.ts`. First-class Harness commands are unprefixed and live in that registry,
|
|
84
|
+
independently of plugin command metadata. Every plugin-owned command uses
|
|
85
|
+
`/<owner-prefix>:<command>`; the namespace root is offered only by plugins that declare a default
|
|
86
|
+
command. Prompt templates and `/skill:<name>` keep their existing forms.
|
|
63
87
|
|
|
64
88
|
## Invariants
|
|
65
89
|
|
|
@@ -80,20 +104,37 @@ Screen: transcript above the composer, centred dialogs, full-screen resource bro
|
|
|
80
104
|
revoked code needs review and a fresh terminal.
|
|
81
105
|
- **INV-TUI-6** `sessions.run` stays the embedding and unattended path. The terminal keeps a
|
|
82
106
|
persistent child instead of opening a session per turn.
|
|
83
|
-
- **INV-TUI-7**
|
|
84
|
-
plugin
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
107
|
+
- **INV-TUI-7** Harness core commands use unprefixed names and are registered independently of
|
|
108
|
+
feature-plugin command metadata. This includes `/doctor`, `/worktree`, `/trajectory`, `/subagents`
|
|
109
|
+
and `/agents`; `/history` remains session-branch navigation, and `/mcp` remains a Connections
|
|
110
|
+
shortcut. Every plugin-owned terminal command uses `/<owner-prefix>:<command>`, for required and
|
|
111
|
+
optional built-ins and Pi extensions alike. Completions, help and dispatch use the same stable
|
|
112
|
+
owner prefix. Prefixes are unique to an owner; a prefix collision or duplicate command within an
|
|
113
|
+
owner is rejected with owner diagnostics. `/skill:<name>` remains reserved for skill invocation.
|
|
114
|
+
For one release, the former owner-qualified and `/plugin:<command>` forms of promoted Harness
|
|
115
|
+
commands remain hidden compatibility aliases; aliases are not listed in help or completion.
|
|
116
|
+
- **INV-TUI-8** Terminal sessions use the Harness-pinned workspace root and the same write
|
|
117
|
+
boundary as SDK sessions. Native file mutations use revalidated atomic replacement under an OS
|
|
118
|
+
scope; default Bash scans for external hard-link aliases and runs inside the sandbox. The terminal
|
|
119
|
+
cannot widen the boundary through its socket or native extension. `!outside <command>` requests
|
|
120
|
+
human-only approval before one execution; the terminal shows the complete escaped command and
|
|
121
|
+
denies the request if it cannot display details and choices together. stdout/stderr cannot trigger
|
|
122
|
+
approval or replay. Missing enforcement fails closed. Full Permission bypasses the boundary only
|
|
123
|
+
for eligible interactive
|
|
124
|
+
user runs and does not override hard policy denials, read-only or plan mode, unattended work, or
|
|
125
|
+
refinement restrictions.
|
|
89
126
|
|
|
90
127
|
## Source map
|
|
91
128
|
|
|
92
129
|
`src/terminal/**`. Decisions: ADR-0001, [ADR-0004](../decisions/ADR-0004-fullscreen-terminal-layout.md)
|
|
93
|
-
(superseded), ADR-0006, [ADR-0021](../decisions/ADR-0021-required-command-namespaces.md)
|
|
130
|
+
(superseded), ADR-0006, [ADR-0021](../decisions/ADR-0021-required-command-namespaces.md)
|
|
131
|
+
(superseded by [ADR-0031](../decisions/ADR-0031-plugin-command-owner-namespaces.md)),
|
|
94
132
|
[ADR-0024](../decisions/ADR-0024-xagent-command.md),
|
|
95
133
|
[ADR-0027](../decisions/ADR-0027-connected-sketch-display.md),
|
|
96
|
-
[ADR-0028](../decisions/ADR-0028-xingular-agent-product-identity.md)
|
|
134
|
+
[ADR-0028](../decisions/ADR-0028-xingular-agent-product-identity.md),
|
|
135
|
+
[ADR-0031](../decisions/ADR-0031-plugin-command-owner-namespaces.md),
|
|
136
|
+
[ADR-0034](../decisions/ADR-0034-first-class-harness-terminal-commands.md),
|
|
137
|
+
[ADR-0036](../decisions/ADR-0036-workspace-write-operation-boundary.md). Experiments:
|
|
97
138
|
EXP-0001, EXP-0002 in `../experiments/`.
|
|
98
139
|
|
|
99
140
|
## Session name in the working line (PROP-0010)
|
|
@@ -166,7 +207,9 @@ Every choice uses one shared measured layout: a marker gutter, a one-third label
|
|
|
166
207
|
gap, and the remaining description cell. Column boundaries align across all rows at every terminal
|
|
167
208
|
width, including compact widths. Text wraps within its cell; a missing description keeps its cell
|
|
168
209
|
and columns never stack. Recommendation text uses `(Rec.)` when the label column is fewer than 14
|
|
169
|
-
cells. Below 60 terminal columns, the dock uses a compact hint.
|
|
210
|
+
cells. Below 60 terminal columns, the dock uses a compact hint. Multi-select choices use `✓`
|
|
211
|
+
when selected and `○` when unselected, matching checklist glyphs; single-choice options remain
|
|
212
|
+
numbered.
|
|
170
213
|
|
|
171
214
|
The dock body has bounded height and vertical scrolling; question tabs and answer/action controls
|
|
172
215
|
stay outside that scrolling region. PageUp/PageDown scroll the body and Ctrl+Home/End jump to its
|
|
@@ -200,21 +243,20 @@ contract is unchanged. See [PROP-0025](proposals/PROP-0025-contextual-question-w
|
|
|
200
243
|
PTY verification is retained in `docs/evidence/terminal-wireframe-normalization/`; it establishes
|
|
201
244
|
cell topology for bounded fixtures, not every emulator/font or live-model sketch quality.
|
|
202
245
|
|
|
203
|
-
##
|
|
246
|
+
## Web annotations commands (PROP-0017)
|
|
204
247
|
|
|
205
|
-
`/
|
|
206
|
-
reopen, share with this session or stop sharing, and delete. `/
|
|
207
|
-
opens a visible capture browser (its own window and profile, separate from the agent's browser),
|
|
208
|
-
|
|
209
|
-
terminal. A note is private until shared; this session's agent then reads it with `page_notes_list`
|
|
248
|
+
`/annotate:notes` lists the Web annotations kept in the data root, with search, and offers reveal, edit, resolve or
|
|
249
|
+
reopen, share with this session or stop sharing, and delete. `/annotate:` opens the default capture pane;
|
|
250
|
+
`/annotate:annotate [url]` is its explicit command form. It opens a visible capture browser (its own window and profile, separate from the agent's browser), where the person can annotate the whole page,
|
|
251
|
+
select text, or click an element there. An annotation is private until shared; this session's agent then reads it with `page_notes_list`
|
|
210
252
|
and `page_notes_read`.
|
|
211
253
|
|
|
212
|
-
|
|
254
|
+
The annotate pane (PROP-0018) is a full-screen page beside the window being inspected.
|
|
213
255
|
|
|
214
256
|
- **Ways to start it:**
|
|
215
|
-
- `/
|
|
216
|
-
- `/
|
|
217
|
-
- `/
|
|
257
|
+
- `/annotate:` or `/annotate:annotate [url]`: the capture browser
|
|
258
|
+
- `/annotate:annotate --app <DevTools address | port> [name]`: an app's own windows over its DevTools port
|
|
259
|
+
- `/annotate:annotate --bridge [name]`: app windows that load the page bridge script, which the pane shows
|
|
218
260
|
- **The inspector** (`i`) outlines components on hover. A click or a text drag opens a popover in the page with Create annotation, Ask agent to fix, and Proceed now.
|
|
219
261
|
- **Sections:** Queue, Sent and fixed (with the agent's summary), and Saved.
|
|
220
262
|
- **Other keys:** `s` sends the queue as one run of this session, confirming notes that came from a page-world script first; `x` takes a note out of the queue; `t` picks a window.
|
|
@@ -229,25 +271,46 @@ The gate treats it as read-only, plan mode allows it, and terminal children inhe
|
|
|
229
271
|
transcript shows each write as a checklist block (`✓` done, `●` in progress (warning yellow), `○` pending) under a
|
|
230
272
|
`Checklist · n of m done` header instead of a tool row; a failed or malformed call stays a tool row.
|
|
231
273
|
|
|
274
|
+
## Work-slice checkpoint (PROP-0041)
|
|
275
|
+
|
|
276
|
+
Terminal replies carry the same work-slice guard as structured runs: 160 tool calls, 40 minutes or
|
|
277
|
+
320 000 new tokens, then a refusal that asks for `checkpoint_write`. The extension registers the shared
|
|
278
|
+
tool and sends it as `checkpoint` telemetry, which the controller records as `checkpoint` on the
|
|
279
|
+
active run, so an App reading the same session sees the handoff. Terminal replies are not
|
|
280
|
+
auto-continued: at the boundary the person decides, which is what the terminal's own turn model
|
|
281
|
+
already does. The run record says `interrupted` with terminal reason `slice_complete` (or `stalled`
|
|
282
|
+
when the guard ended it), so a host can continue it; a checkpoint card in the transcript is not built
|
|
283
|
+
yet (PAR-004). Start the terminal with `XINGULAR_WORK_SLICE=off` to launch a reply with no
|
|
284
|
+
boundary at all; it is not persisted, so the next launch without it restores the guard.
|
|
285
|
+
|
|
232
286
|
## Subagent activity monitor
|
|
233
287
|
|
|
234
288
|
During an active parent run, the terminal polls a private read-only monitor once per second. It
|
|
235
289
|
projects the flat set of child and nested-child runs with task, status, elapsed time, the latest
|
|
236
290
|
tool name, the child's agent profile (name and colour, PROP-0029), the title the parent gave it
|
|
237
|
-
(PROP-0030),
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
291
|
+
(PROP-0030), counts from the child's own checklist, the pinned account label, effective model and
|
|
292
|
+
effort, and cumulative usage totals. Model and effort come from the volatile launch selection; the
|
|
293
|
+
latest provider-reported model supersedes the launch model when usage is available. Usage is an
|
|
294
|
+
explicit projection of token, cache, cost, request-count and context-window totals. Per-request
|
|
295
|
+
payloads and reasoning summaries do not enter the monitor. The child's own `session_name` is not
|
|
296
|
+
projected; it names the child's session, not its row. Tool summaries, other arguments, output and
|
|
297
|
+
checklist item text never enter the monitor. The latest completed tool name remains visible across
|
|
298
|
+
one-second snapshots until new tool or response activity replaces it. The monitor exposes no
|
|
299
|
+
controls to steer or stop children.
|
|
242
300
|
|
|
243
301
|
The live rows sit under the status line, after one blank row, with no heading. Each row reads, in
|
|
244
302
|
order: the status mark (`○` queued, a running row that shows the working spinner's frame in the profile's colour (warning for a copy of the parent), `●` waiting in the accent,
|
|
245
303
|
`✓` done, `✕` failed, `!` stopped), the profile name in its colour (`subagent`, muted, for a copy
|
|
246
304
|
of the parent), the title the parent gave the child (PROP-0030), and `n of m tasks` when the child
|
|
247
305
|
keeps a checklist. Active rows come first, at most three, then `+N more · /subagents`; a narrow
|
|
248
|
-
terminal cuts the title first. `/subagents` opens the searchable full roster with
|
|
249
|
-
|
|
250
|
-
|
|
306
|
+
terminal cuts the title first. `/subagents` opens the searchable full roster, with a colored
|
|
307
|
+
profile and normal-color title on its first line, then muted account, model, effort and usage
|
|
308
|
+
metadata on its second line. One blank row separates each two-line entry. Narrow rows truncate this
|
|
309
|
+
lower-priority summary without hiding the title.
|
|
310
|
+
At parent settlement, the terminal makes a final monitor read and keeps the latest parent's rows
|
|
311
|
+
visible until the next parent run starts. The projection remains volatile and read-only, is scoped to
|
|
312
|
+
the latest parent run in the terminal session, and is cleared on session replacement or terminal
|
|
313
|
+
disposal. It is not a persisted event or public server method.
|
|
251
314
|
|
|
252
315
|
## Agent profiles (PROP-0029)
|
|
253
316
|
|
|
@@ -25,10 +25,12 @@ index.
|
|
|
25
25
|
plugins/<name>/ packages kept with the data (06)
|
|
26
26
|
trash/plugins/ removed packages (06)
|
|
27
27
|
hub/ installed documents and provenance (09)
|
|
28
|
-
runs/<id>/ run.json, events.jsonl, owner.json, subagents.json, context.json, caller.json, capabilities.json, mcp-context.json (02)
|
|
28
|
+
runs/<id>/ run.json (including optional legacy-compatible workspaceRoot), events.jsonl, owner.json, subagents.json, context.json, caller.json, capabilities.json, mcp-context.json (02)
|
|
29
|
+
# `checkpoint` and `heartbeat` are run events in the same events.jsonl; a bounded reply emits one
|
|
30
|
+
# heartbeat per 30 seconds (about 60 KB an hour) and no side file (PROP-0041).
|
|
29
31
|
config/ plugin-attachments.json and settings the harness reads (06)
|
|
30
32
|
agents/<name>.md a person's global agent profiles; agents/profiles.ts owns it (02, PROP-0029)
|
|
31
|
-
index.sqlite derived index (FTS5) (08)
|
|
33
|
+
index.sqlite derived index (FTS5, recall, usage ledger) (08, PROP-0042)
|
|
32
34
|
projects.json read only: the application owns it
|
|
33
35
|
|
|
34
36
|
<state dir>/
|
|
@@ -48,6 +50,25 @@ index.
|
|
|
48
50
|
harness.log standalone terminal diagnostics
|
|
49
51
|
```
|
|
50
52
|
|
|
53
|
+
The interactive profile is a credential-free, versioned selection file at
|
|
54
|
+
`~/.xingular-harness/profile.json`, owned by `src/core/interactiveProfile.ts`. It selects the
|
|
55
|
+
interactive defaults: data root, state directory, default variant scope, and a credential-backend
|
|
56
|
+
descriptor. With no selected profile, the defaults are `~/.xingular-harness/data`,
|
|
57
|
+
`~/.xingular-harness/state`, scope `default`, and the state directory's owner-only file secret
|
|
58
|
+
store. A host may provide a stable host-backed secret adapter instead; the profile stores only its
|
|
59
|
+
identifier, never credentials. If that adapter is unavailable, startup fails rather than falling
|
|
60
|
+
back to a different store.
|
|
61
|
+
|
|
62
|
+
Explicit roots or variant scopes take precedence over the selected profile; the selected profile
|
|
63
|
+
precedes caller-supplied legacy defaults. Explicit adoption creates the profile file without
|
|
64
|
+
replacing an existing selection and does not create, copy, merge, or migrate data roots or
|
|
65
|
+
credentials. Existing account, variant, and session pins remain authoritative for their saved
|
|
66
|
+
runs; the profile selects defaults for new interactive work. `scripts/dev.mjs` and a development
|
|
67
|
+
interactive profile use `~/.xingular-harness-dev/{data,state}` and a separate profile file, not the
|
|
68
|
+
production defaults. The standalone development launch always selects a file SecretStore under its
|
|
69
|
+
resolved development state directory, even if that profile names a host backend; it does not use or
|
|
70
|
+
alter host credentials.
|
|
71
|
+
|
|
51
72
|
Side-question runs use the ordinary `runs/<id>/` records. Their temporary Pi native history is
|
|
52
73
|
created under the operating system temporary directory and removed when the run ends; it is not
|
|
53
74
|
retained in the data root or state directory.
|
|
@@ -68,6 +89,13 @@ retained in the data root or state directory.
|
|
|
68
89
|
as it was when a migration fails, and the failure is reported in `Recovery.migrationError`.
|
|
69
90
|
- **INV-STO-6** Writes of shared JSON files are atomic (`core/fs.ts::atomicWrite`, `writeJson`).
|
|
70
91
|
- **INV-STO-7** Files holding trust or secrets are owner-only (`0600`).
|
|
92
|
+
- **INV-STO-8** `core/interactiveProfile.ts` owns the credential-free selection of interactive
|
|
93
|
+
roots, default variant scope, and credential-backend descriptor. Explicit roots/scopes win; a
|
|
94
|
+
selected profile wins over legacy defaults. Adoption never replaces a selection or merges roots,
|
|
95
|
+
and a missing host credential adapter never silently downgrades to a file store. The standalone
|
|
96
|
+
development launch explicitly selects its isolated file store; this is not a fallback for normal
|
|
97
|
+
interactive profiles. Profile defaults do not replace the account, variant, or other pins on saved
|
|
98
|
+
runs.
|
|
71
99
|
|
|
72
100
|
## Source map
|
|
73
101
|
|
|
@@ -18,6 +18,21 @@ synthetic page. Their input runs only after live-check confirmation, and their r
|
|
|
18
18
|
released on completion, timeout or cancellation. Computer interaction needs a host-provided
|
|
19
19
|
isolated surface; without one it is blocked.
|
|
20
20
|
|
|
21
|
+
## Shared browser contract and native WebKit limits (PROP-0040)
|
|
22
|
+
|
|
23
|
+
`browser/contracts.ts` owns the backend-neutral names and input schemas for `browser_*` tools;
|
|
24
|
+
providers adapt those definitions rather than inventing host-specific selectors. The isolated Harness
|
|
25
|
+
backend supports accessibility snapshots and snapshot-scoped refs. A native WebKit host backend
|
|
26
|
+
currently supports navigation, tab management, visible-text reads and page-level scrolling without a
|
|
27
|
+
ref. It does not support accessibility snapshots, snapshot refs or ref-based click/type/select/scroll,
|
|
28
|
+
browser screenshots, browser waits or keyboard presses.
|
|
29
|
+
|
|
30
|
+
For an unsupported operation the native provider returns an explicit `browser_unsupported` refusal
|
|
31
|
+
with “Nothing was done”; it never treats a snapshot ref as a selector and never silently switches to
|
|
32
|
+
the isolated browser. The isolated Harness browser is an independent backend, not an automatic
|
|
33
|
+
fallback for the native provider. A host plugin's `surfaces` description labels that fallback and its
|
|
34
|
+
limits; it does not assert full browser parity.
|
|
35
|
+
|
|
21
36
|
Plugin ownership and the Foundation boundary are recorded in PROP-0012, ADR-0014 and PROP-0020.
|
|
22
37
|
World providers are assembled through `BuiltinPluginRegistry`; no eighth extension point is added.
|
|
23
38
|
|
|
@@ -39,7 +54,13 @@ terminal, or in a host's own web view running the same page helper (`annotations
|
|
|
39
54
|
- A queued note is shared with its session.
|
|
40
55
|
- `annotations/delivery.ts` sends a batch as one instruction, and sends notes the person asked for while the session was busy when its run ends.
|
|
41
56
|
- The agent reports a fix with `page_notes_mark_fixed`, the only page-note tool that writes. It never resolves a note or changes grants.
|
|
42
|
-
- **Targets.**
|
|
57
|
+
- **Targets.** Element targets prefer semantic role/name/text. A visually empty element may still be
|
|
58
|
+
annotated when it has a specific CSS selector (ID, test ID, classes, and a structural path when
|
|
59
|
+
needed); bare tag selectors are not enough. Reveal checks for one live match and preserves any
|
|
60
|
+
captured semantic/context evidence, otherwise reporting ambiguous or unresolved. Text annotations
|
|
61
|
+
continue to use quote plus context, not screen coordinates.
|
|
62
|
+
- Besides the browser window, capture can use an app's own windows:
|
|
43
63
|
- **DevTools port:** an app started with a DevTools port, on a loopback address only. It uses the app's existing windows, routes nothing, and never closes the app.
|
|
44
64
|
- **Page bridge:** a loopback server whose script an app loads while it is developed (`annotations/bridge.ts`), for web views without a DevTools port.
|
|
65
|
+
- **Web components (PROP-0038).** The helper walks the composed tree: open shadow roots and slotted content can be picked, selected and revealed, and such targets carry `tree: 'composed'`. Targets without it resolve by the document-only rules as before. Closed shadow roots and frames stay out of reach, and the inspector says why it refuses something.
|
|
45
66
|
- **Trust.** In Chromium targets the helper runs in an isolated script world, so the page cannot forge a comment. A send from the bridge, or from a host web view without isolation, waits for the person to confirm it.
|
|
@@ -27,14 +27,39 @@ terminal command or page, a host screen.
|
|
|
27
27
|
|
|
28
28
|
- A capability is reachable through server methods (page 10) and, where a model uses it, through a
|
|
29
29
|
tool that passes the gate (page 07). Both front ends use the same methods; neither has a private
|
|
30
|
-
path to Harness state.
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
path to Harness state. Foundation context behavior, including bounded checkpoint restoration after
|
|
31
|
+
compaction (PROP-0033), is shared by terminal and embedded sessions; a host does not reimplement it.
|
|
32
|
+
- Workspace write scope is Harness-owned on both surfaces. Each run pins a canonical root after
|
|
33
|
+
worktree selection; reads retain OS-permission scope, while native file writes and shell
|
|
34
|
+
filesystem effects default to that root; the filesystem root itself is not a valid workspace.
|
|
35
|
+
Native mutations revalidate their canonical target and atomically replace the file under an OS
|
|
36
|
+
write scope. Default Bash scans for external hard-link
|
|
37
|
+
aliases and runs under an OS sandbox that prevents its own processes from creating cross-boundary
|
|
38
|
+
hard links; on macOS the sandbox denies hard-link creation entirely, including within the
|
|
39
|
+
workspace. `workspaceWriteScope: 'outside'` (terminal `!outside <command>`) requests a human-only
|
|
40
|
+
approval before one execution, showing the complete escaped command in scrollable terminal details
|
|
41
|
+
and denying if the terminal is too small. Output never triggers approval or retry. Hosts may
|
|
42
|
+
tighten or deny policy but cannot silently waive the boundary. Only the eligible Full Permission
|
|
43
|
+
switch may answer automatically under its existing restrictions. A same-user peer process outside
|
|
44
|
+
Harness is not controlled by this rule. `workspaceRoot` is additive and legacy run records may
|
|
45
|
+
omit it.
|
|
46
|
+
- Harness core terminal commands use unprefixed names and are registered independently of feature
|
|
47
|
+
plugin command metadata. This includes `/doctor`, `/worktree`, `/trajectory`, `/subagents` and
|
|
48
|
+
`/agents`; `/history` remains session-branch navigation, and `/mcp` remains a Connections shortcut.
|
|
49
|
+
Every plugin-owned terminal command uses `/<owner-prefix>:<command>`, for required and optional
|
|
50
|
+
built-ins and Pi extensions alike. Built-in prefixes are stable registry metadata; Pi package
|
|
51
|
+
extensions use a normalized package name or the package's `harness.commandPrefix`, and loose
|
|
52
|
+
extensions use their normalized extension name. Prefix collisions and duplicate commands within
|
|
53
|
+
one owner are rejected with owner diagnostics. Built-in plugin modules may declare a default
|
|
54
|
+
command for their namespace root. The former owner-qualified and `/plugin:<command>` forms of
|
|
55
|
+
promoted Harness commands remain hidden compatibility aliases for one release. Prompt templates
|
|
56
|
+
and `/skill:<name>` keep their existing forms. Built-in plugin categories remain documented in
|
|
57
|
+
page 06, not public metadata.
|
|
35
58
|
- A capability may be limited to a run mode when Harness resolves the callable set; the register
|
|
36
59
|
records that restriction for both surfaces. `ask_user` is available only in attended plan runs,
|
|
37
|
-
|
|
60
|
+
with no terminal-only question alias (PROP-0040). Plan-mode delegation
|
|
61
|
+
is limited to named profiles whose effective tool and plugin allowlists qualify for read-only
|
|
62
|
+
research; both terminal and host use the same gate and child-capability narrowing.
|
|
38
63
|
- Question choice sketches use one optional validated event contract: up to 80 printable ASCII
|
|
39
64
|
columns by 24 LF-separated lines (1,943 bytes maximum; page 02). Both surfaces use the same
|
|
40
65
|
literal ASCII source, persisted unchanged, in one shared preview with access to overflow; neither
|
|
@@ -56,6 +81,27 @@ terminal command or page, a host screen.
|
|
|
56
81
|
- Side questions use one Harness service on both surfaces. Each caller supplies its visible
|
|
57
82
|
transcript projection; Harness adds the parent run's effective prompt and public events, then
|
|
58
83
|
starts an independent tool-free run.
|
|
84
|
+
- PROP-0040 defines one shared launch/command contract: `Launch.standard`, `commands.list`,
|
|
85
|
+
saved-history controls and tracked `SessionRunInput.command` runs. Hosts present these rather
|
|
86
|
+
than approximating navigation with a fork. A listed command or handler is not proof of acceptance.
|
|
87
|
+
The current host `/session` picker reads a host-owned session catalog rather than a shared Harness
|
|
88
|
+
catalog (PAR-008), and read-only command pages do not stand in for unsupported management methods.
|
|
89
|
+
The register records command routes individually; parity remains open until each route passes
|
|
90
|
+
acceptance.
|
|
91
|
+
- Read-only `get_capabilities` is implemented in structured sessions and the terminal. Structured
|
|
92
|
+
sessions report tools filtered by the run's frozen capability set and actual registered schemas;
|
|
93
|
+
the terminal reports Pi's active tools and schemas, applying its plan-mode allowed set when active.
|
|
94
|
+
It is in the shared plan-mode allowlist and grants no permission. Hosts use this Harness tool rather
|
|
95
|
+
than defining a duplicate.
|
|
96
|
+
- `browser/contracts.ts` owns shared backend-neutral browser schemas. A native WebKit host backend
|
|
97
|
+
still lacks accessibility snapshots and snapshot-ref interactions, browser screenshots, waits and
|
|
98
|
+
keyboard input; unsupported calls return an explicit refusal before effects and do not trigger an
|
|
99
|
+
automatic backend switch (page 13, PAR-015).
|
|
100
|
+
- Shared interactive defaults, profile adoption, credentials and a cross-surface session catalog
|
|
101
|
+
remain in progress under PROP-0040. Existing pins and explicit profile choices win; adoption must
|
|
102
|
+
not merge stores, copy credentials or silently downgrade the secret backend.
|
|
103
|
+
- `PluginDescriptor.surfaces` / `Plugin.surfaces` optionally describe a host preference, terminal
|
|
104
|
+
fallback/unavailability and reason. This labels add-ons, not plugin categories or permissions.
|
|
59
105
|
- The register of capabilities and their surfaces is [`docs/parity.md`](../parity.md). It is
|
|
60
106
|
descriptive; the invariants below are binding.
|
|
61
107
|
- A host keeps its own register of host-only surfaces. The Harness names no host surface.
|
|
@@ -86,4 +132,5 @@ None of its own. Each capability stores its data as its own page says.
|
|
|
86
132
|
`src/harness.ts` (services), `src/world/world.ts` (world parts), `src/plugins/builtin.ts`
|
|
87
133
|
(first-party descriptors), `src/terminal/` (terminal surfaces), `src/server/methods.ts` (methods).
|
|
88
134
|
Decision: [PROP-0015](proposals/PROP-0015-one-capability-surface.md),
|
|
89
|
-
[ADR-0017](../decisions/ADR-0017-one-capability-surface.md)
|
|
135
|
+
[ADR-0017](../decisions/ADR-0017-one-capability-surface.md),
|
|
136
|
+
[ADR-0036](../decisions/ADR-0036-workspace-write-operation-boundary.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Harness architecture specification
|
|
2
2
|
|
|
3
|
-
**Status:** binding. **As of:** 2026-10-
|
|
3
|
+
**Status:** binding. **As of:** 2026-10-26, checked against `src/` on branch `release/1.0.0`.
|
|
4
4
|
|
|
5
5
|
This folder is the core specification of `@xingular/harness`. Code must conform to it. A change
|
|
6
6
|
that would alter what it says needs a proposal the user approves first (see
|
|
@@ -123,3 +123,5 @@ proposal, or a correction to the other document).
|
|
|
123
123
|
| D-14 | 12-storage layout | Page 12 lists browser settings under `<state dir>/browser/`, while `browser/config.ts` stores configuration in `<state dir>/browser.json`; browser profiles and downloads use the `browser/` directory. The layout needs an owner decision before either side is changed. |
|
|
124
124
|
| D-15 | Terminal sketch verification status — resolved 2026-10-24 by PROP-0028 | Pages 11 and 14 and `terminal-tui.md` said connected-sketch implementation verification was pending, while retained PTY evidence and PAR-014 recorded it as verified. Updated the docs to distinguish deterministic fixture verification from owner visual acceptance, every-emulator rendering and live-model sketch quality. |
|
|
125
125
|
| D-16 | Terminal slash-command highlighting — resolved 2026-10-24 | `terminal-tui.md` specified accent coloring for recognized leading commands while typing, but the OpenTUI composer only styled attachment labels. User-message bubbles also lacked command-token styling. The renderer now uses the active command registry for both surfaces. |
|
|
126
|
+
| D-17 | `PROP-0039`, `ADR-0036`, `INV-GATE-3/8` | Implementation is in progress in the 1.2.0 worktree: native writes revalidate canonical targets and atomically replace files under an OS write scope; default Bash fails closed on external hard-link aliases and runs in a sandbox that prevents new cross-boundary links; outside-scope Bash requires approval before one execution and command output never triggers approval or replay. The filesystem root is rejected as a workspace, and approval details expose the complete command. Launcher selection uses fixed system paths. Same-user peer processes remain outside this boundary. Focused macOS tests, full Harness CI, App compatibility checks, and PTY verification at 40x20, 80x24, and 100x30 pass. Linux sandbox integration remains unverified locally because this Darwin host has no `bwrap` and Colima is stopped; both CI workflows now install bubblewrap and `scripts/ci.sh` fails if it is absent, but an Ubuntu run is still required. No candidate, tag, or publication exists. |
|
|
127
|
+
| D-18 | `core/index.ts` migration 5 | The `run_stats` table has no writer in the Harness. PROP-0042's `usage_requests` ledger is the analytics source; whether to drop the older table is open. |
|
|
@@ -3,7 +3,7 @@ id: PROP-0017
|
|
|
3
3
|
title: Page annotations as a Harness capability, captured in the headed browser or a host's web view
|
|
4
4
|
status: Implemented
|
|
5
5
|
created: 2026-10-23
|
|
6
|
-
updated: 2026-10-
|
|
6
|
+
updated: 2026-10-25
|
|
7
7
|
affects: [INV-STO-3, INV-SRV-1, 07-tools-and-gate.md, 10-server-protocol.md, 11-terminal.md, 12-storage.md, 13-world-tools.md, 14-surfaces-and-parity.md]
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -41,7 +41,11 @@ grants, history }`, the format of the App store, so existing notes import unchan
|
|
|
41
41
|
- `source`: `{ url, title, capturedAt }` plus an optional opaque `surface` string from the capturing
|
|
42
42
|
front end.
|
|
43
43
|
- `target`: `page`, `text { exact, prefix, suffix, start, end }` (Unicode code points over
|
|
44
|
-
normalised page text), or `element { tag, role, name, text, context, selector }`.
|
|
44
|
+
normalised page text), or `element { tag, role, name, text, context, selector }`. Element capture
|
|
45
|
+
prefers role/name/text; when an otherwise empty visual element has no semantic label, it may use
|
|
46
|
+
a specific CSS selector (ID, test ID, classes, and a structural path when needed), never a bare
|
|
47
|
+
tag. Resolution uses that selector only when it identifies one allowed element and the captured
|
|
48
|
+
semantics/context still agree; stale or duplicate targets remain unresolved or ambiguous.
|
|
45
49
|
- `status`: `open` or `resolved`. `version` increases on every change; update and delete name the
|
|
46
50
|
version they expect (compare-and-swap). The last 100 change receipts are kept, without earlier
|
|
47
51
|
bodies. At most 10,000 notes.
|
|
@@ -51,7 +51,7 @@ A note gains an optional `delivery`:
|
|
|
51
51
|
- ⌘/Ctrl+Enter is Proceed now; with Shift it is queue.
|
|
52
52
|
- Everything is drawn in a closed shadow root.
|
|
53
53
|
- The page never receives the press or click on what is inspected, nor anything typed in the popover.
|
|
54
|
-
- Inputs, secrets, `[data-sensitive]` elements, frames, shadow roots and custom elements are never picked, as in PROP-0017.
|
|
54
|
+
- Inputs, secrets, `[data-sensitive]` elements, frames, shadow roots and custom elements are never picked, as in PROP-0017. (Open shadow roots and readable custom elements became pickable in [PROP-0038](PROP-0038-annotate-open-shadow-roots.md).)
|
|
55
55
|
- The inspector stays on after each comment.
|
|
56
56
|
- A new operation, `next`, returns `{ active, documentId, url, title, result }`, one comment at a time.
|
|
57
57
|
- `toast` shows a short status in the page.
|