@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
package/docs/parity.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Capability parity register
|
|
2
2
|
|
|
3
|
-
**Status:** descriptive register, as of 2026-
|
|
3
|
+
**Status:** descriptive register, as of 2026-11-19. The binding rules are
|
|
4
4
|
[14 Surfaces and parity](architecture/14-surfaces-and-parity.md) (`INV-PAR-1`–`INV-PAR-4`).
|
|
5
5
|
|
|
6
6
|
Every capability a person can use is a Harness capability. The standalone terminal (`xagent`)
|
|
@@ -12,44 +12,98 @@ Host-only surfaces (presentation a terminal cannot show, `INV-PAR-4`) are not li
|
|
|
12
12
|
host keeps its own register. The App's is
|
|
13
13
|
[`App/docs/architecture/app-only-surfaces.md`](../../App/docs/architecture/app-only-surfaces.md).
|
|
14
14
|
|
|
15
|
-
Status: **parity**
|
|
16
|
-
|
|
15
|
+
Status: **parity** only where both surfaces passed acceptance; **implemented** means source routes
|
|
16
|
+
exist but acceptance is not certified; **terminal only**, **host only**, **partial**, **planned**,
|
|
17
|
+
and **host-backed** (needs a host object; terminal fallback named). A slash-command row marked
|
|
18
|
+
implemented is not a parity claim; acceptance is tracked per command.
|
|
17
19
|
|
|
18
20
|
## Register
|
|
19
21
|
|
|
20
22
|
| Capability | Harness owner | Method or tool | Terminal surface | App surface | Status | Gap |
|
|
21
23
|
|---|---|---|---|---|---|---|
|
|
22
24
|
| Sessions and turns | `sessions/` | `sessions.run`, `terminal.*` | the terminal itself | Solo chat | parity | — |
|
|
23
|
-
| Plan mode | `sessions/planMode.ts` | `plan: true` | `/plan`, Shift+Tab, plan card | plan request, PlanCard | parity | — |
|
|
24
|
-
|
|
|
25
|
+
| Plan mode | `sessions/planMode.ts` | `plan: true` | `/plan`, Shift+Tab, plan card; bounded plan/checklist context is restored after compaction | plan request, PlanCard; shared Harness checkpoint behavior | parity | — |
|
|
26
|
+
| Capability discovery | `tools/getCapabilities.ts` | read-only `get_capabilities` | terminal extension reports Pi's active tools and schemas; shared plan allowlist includes it | structured Harness run uses the same tool; no duplicate App-owned tool | implemented; acceptance not recertified | — |
|
|
27
|
+
| Bash command mode | `sessions/sessions.ts`, `sessions/initialBash.ts` | `initialBashCommand`; Bash `workspaceWriteScope` | `!command` defaults to workspace; `!outside command` asks before running once | same `!command` and `!outside command` composer semantics | parity | — |
|
|
28
|
+
| Workspace-scoped writes | `core/workspace.ts`, `sessions/workspaceBoundary.ts`, `core/workspaceBashTool.ts`, `core/workspaceSandbox.ts`, `core/workspaceWriteOperations.ts` | pinned non-root `RunRecord.workspaceRoot`; native `edit`/`write`; Bash scope | revalidated atomic native writes; external-hard-link scan and Bash sandbox; complete escaped outside command in scrollable approval details (deny if too small); no output-triggered retry | same Harness gate and full approval action in scrollable App details; App policy can tighten scope; Full Permission remains the eligible explicit bypass | parity | — |
|
|
25
29
|
| Side questions | `sessions/sideQuestions.ts` | `sideQuestions.start/read/interrupt`; terminal `terminal.sideQuestions.*` | `/btw` contextual dock with scroll and copy | side-question dock through the shared service | parity | — |
|
|
26
30
|
| Approvals and standing approvals | `sessions/approvals.ts` | `approvals.*` | decision dock, `/permissions` | approvals dock, settings | parity | — |
|
|
27
|
-
| Questions (`ask_user`) | `tools/askUser.ts` | `ask_user
|
|
28
|
-
| Subagents | `sessions/subagentService.ts` | `spawn_subagent` (requires `title`, PROP-0030), `subagents
|
|
29
|
-
| Agent profiles | `agents/profiles.ts` | `spawn_subagent { agent }`, `agents.list/get/create/remove`; terminal `terminal.agents.*` | `/agents` page: browse, create, edit in `$EDITOR`, copy, delete |
|
|
31
|
+
| Questions (`ask_user`) | `tools/askUser.ts` | shared `ask_user` tool | plan-mode dock: strict aligned columns, bounded body scroll, 80×24 source sketch viewport; connected structural projection with high-confidence boundary normalization (PROP-0026, PROP-0028) | plan-mode form accepts the same 80×24 ASCII source contract with literal preview and accessible overflow; no typography change required | parity; terminal projection verified in isolated fixtures | — |
|
|
32
|
+
| Subagents | `sessions/subagentService.ts` | `spawn_subagent` (requires `title`, PROP-0030), `subagents.*`; plan mode allows only named eligible read-only research profiles | `/subagents` page and live rows under the status line (mark, profile, parent-set title, `n of m tasks`); plan-mode research delegation uses the same Harness gate | reply trajectory; plan-mode research delegation uses the same Harness gate | parity | — |
|
|
33
|
+
| Agent profiles | `agents/profiles.ts` | `spawn_subagent { agent }`, `agents.list/get/create/remove`; terminal `terminal.agents.*` | `/agents` page: browse, create, edit in `$EDITOR`, copy, delete | Solo `/agents` lists profiles; profile details and management are not wired | partial | PAR-010 |
|
|
30
34
|
| Run checklist | `tools/checklist.ts` | `checklist_write`, `runs.checklist`; terminal `checklist` telemetry | registered in terminal sessions and their subagents; each write shows as a checklist block in the transcript; a subagent row shows its `n of m tasks` | not shown | terminal done; App planned | PAR-001 |
|
|
31
35
|
| Continuation of a stopped run | `sessions/continuation.ts` | `continueFrom`, `runs.continuation` | not offered (`/resume` reopens history only) | not offered | planned | PAR-003 |
|
|
36
|
+
| Bounded replies and checkpoints (PROP-0041) | `sessions/workSlice.ts`, `tools/checkpoint.ts`, `sessions/runner.ts` | `checkpoint_write`, `workSlice`, `runs.continuation.checkpoint`, `checkpoint`/`heartbeat` events | guard on every terminal reply with the shared tool; the handoff is recorded on the run; no checkpoint card or slice control yet | not wired | implemented; terminal card, App presentation and `/slices` open | PAR-004 |
|
|
32
37
|
| Accounts | `accounts/` | `accounts.*` | `/accounts` | Accounts | parity | — |
|
|
33
38
|
| Models and effort | `accounts/choices.ts` | — | `/model`, `/effort` | composer pickers | parity | — |
|
|
34
39
|
| Skills | `plugins/`, `tools/dispatch.ts` | `skill_load` | `$name`, `/skill:name`, browser Skills tab | Capability, composer | parity | — |
|
|
35
40
|
| Plugins and Hub | `plugins/`, `hub/` | `plugins.*`, `hub.*` | resource browser | Capability | parity | — |
|
|
36
41
|
| Connected apps (MCP) | `mcp/` | `connections.*`, broker tools | resource browser Connections tab | Connections | parity | — |
|
|
37
42
|
| Web search and page reading | `web/` | `web_search`, `web_fetch` | world tools | world tools | parity | — |
|
|
38
|
-
| Isolated browser | `browser/` | `browser_*` | world tools, headed on request, `/settings` Browser tab |
|
|
39
|
-
|
|
|
40
|
-
| Managed worktrees | `worktrees/` (PROP-0016) | `worktrees.*` | `--worktree`, `/worktree`, `xagent worktree` |
|
|
41
|
-
| Wiki notes (model tools) | `wiki/`, `tools/` | `wiki_*` | `xagent-wiki` shell
|
|
42
|
-
| History and trajectory (model tools) | `history/` | `history_*`, `trajectory_*` |
|
|
43
|
+
| Isolated browser | `browser/` | shared `browser_*` schemas | isolated world tools, headed on request, `/settings` Browser tab | native WebKit: navigate, tabs, visible-text read and page scroll without refs; unsupported operations refuse explicitly | partial; native backend gap | PAR-015 |
|
|
44
|
+
| Web annotations | `annotations/` (PROP-0017, PROP-0018, PROP-0038) | `annotations.*`, `annotations.capture.*`, `page_notes_*` | `/annotate:` pane (also `/annotate:annotate`), `/annotate:notes` saved list | website tab Annotate panel (inspector, queue to the focused thread, app windows through `annotations.capture.*`) | parity in the working tree; native WKWebView gestures unaccepted | PAR-011 |
|
|
45
|
+
| Managed worktrees | `worktrees/` (PROP-0016) | `worktrees.*` | `--worktree`, `/worktree`, `xagent worktree` | Solo `/worktree` lists records only; Solo starts sessions in the project folder and has no worktree level | partial | PAR-012 |
|
|
46
|
+
| Wiki notes (model tools) | `wiki/`, `tools/` | `wiki_*` | `Terminals.ownTools` registers Wiki-read tools through the session socket; `xagent-wiki` remains a person-facing shell utility | structured Harness tools | implemented on both; acceptance not recertified | PAR-002: acceptance not recertified |
|
|
47
|
+
| History and trajectory (model tools) | `history/` | `history_*`, `trajectory_*` | `Terminals.ownTools` registers model tools through the session socket; `/trajectory` page; `/history` navigates session branches | structured tools and trajectory views | implemented on both; acceptance not recertified | PAR-002: acceptance not recertified |
|
|
43
48
|
| Wiki browsing | `wiki/` | `wiki.*` | none | Wiki | host only | PAR-005 |
|
|
44
49
|
| Variants and refinement | `variant/`, `refine/` | `harnesses.*`, `refine.*` | browser Variant tab (read-only), `xagent refine` | Harness screen | host only | PAR-004 |
|
|
45
|
-
| Output trim and budget guard plugins | `plugins/firstParty.ts` |
|
|
50
|
+
| Output trim and budget guard plugins | `plugins/firstParty.ts` | trusted first-party hooks | `firstParty.list` loads enabled hooks in `terminal/piExtension.ts` | structured Harness sessions load enabled hooks | implemented on both; acceptance not recertified | PAR-006: acceptance not recertified |
|
|
46
51
|
| Doctor | `doctor/` | `doctor.*` | `/doctor` | diagnostics | parity | — |
|
|
47
52
|
| Run inspection | `sessions/runStore.ts` | `runs.*` | `/trajectory`, `/log` | run views, analytics | parity | — |
|
|
48
|
-
|
|
|
49
|
-
|
|
|
53
|
+
| Usage analytics | `usage/` (PROP-0042) | `usage.summary`, `usage.sync` | `/usage:`, `/usage:analysis` page (Analysis tab) | not wired | terminal implemented; host planned | PAR-016 |
|
|
54
|
+
| Provider limits | `usage/limits/` (PROP-0042) | `usage.limits` | `/usage:limit` page (Limits tab) | not wired | terminal implemented; host planned | PAR-016 |
|
|
55
|
+
| Session catalog (sessions per folder) | `sessions/` saved-history controls; shared catalog not implemented | `sessions.*` controls; no cross-surface catalog method | `/session` selects native Pi histories in the current folder | `/session` reads `bridge.agent.threads(SOLO_ID)`, maps each thread to its project folder, and filters by current effective account; `all` broadens only this App list | planned; catalogs differ | PAR-008 |
|
|
56
|
+
| Folder choice and recent folders | project/worktree selection remains surface-specific | launch `cwd`, `--worktree`, `/worktree` | starts in launch folder; explicit worktree commands | Solo sidebar is Project › Session; new sessions use the project's folder, with no folder/worktree level | planned; no shared recent-folder picker | PAR-009 |
|
|
50
57
|
| Computer control | — | `computer_*` (host tools) | unavailable, with reason | macOS bridge (host-backed) | host-backed | PAR-007 |
|
|
51
58
|
| Shared files vault | — | `files_*` (host tools) | none | Files | host only | PAR-007 |
|
|
52
59
|
|
|
60
|
+
## Core slash-command surfaces (PROP-0040)
|
|
61
|
+
|
|
62
|
+
These are the fixed `CORE_COMMANDS` entries. The App column records the current Solo source route,
|
|
63
|
+
not a claim that it has passed acceptance. `commands.list`, a handler-completeness test, and source
|
|
64
|
+
presence do not certify parity. Each command needs its own acceptance evidence; dynamic
|
|
65
|
+
plugin/extension, prompt-template and skill commands are listed by `commands.list` but are not in
|
|
66
|
+
this fixed table.
|
|
67
|
+
|
|
68
|
+
| Command | Terminal surface | App Solo route in source | Acceptance / remaining gap |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| `/help` | Command list and palette | Searchable command picker; selection fills the composer | Not certified per command |
|
|
71
|
+
| `/plan` | Plan request / mode toggle | Plan request; bare form toggles persistent plan mode; model Bash runs read-only (PROP-0043) | Not certified per command |
|
|
72
|
+
| `/btw` (`/side`) | Contextual side-question dock | Shared side-question service; bare form dismisses the dock | Not certified per command |
|
|
73
|
+
| `/new` | New conversation | Replaces focused tab with a draft; archives its saved session | Not certified per command |
|
|
74
|
+
| `/stop` | Interrupt current reply | Stops the focused session's reply | Not certified per command |
|
|
75
|
+
| `/session` (`/resume`) | Search/select native saved history in the current folder | Lists App Solo threads by folder and effective account; `all` widens only within that App list | PAR-008: separate catalogs; no native-history path opening; not certified |
|
|
76
|
+
| `/history` (`/tree`) | Navigate branches in the current native session | Calls `session.navigate` with stable native entry ID; same-session navigation, optional summary, no fork fallback | Route uses Harness `sessions.navigate`; per-command acceptance pending |
|
|
77
|
+
| `/fork` | Fork from a user message | Uses session tree/fork and opens the new session | Not certified per command |
|
|
78
|
+
| `/clone` | Clone the current branch | Uses session clone and opens the copy | Not certified per command |
|
|
79
|
+
| `/model` | Choose model | App model picker updates session runtime | Not certified per command |
|
|
80
|
+
| `/effort` | Choose reasoning effort | Updates session runtime effort | Not certified per command |
|
|
81
|
+
| `/thinking` | Toggle thinking display | Toggles transcript thinking visibility | Not certified per command |
|
|
82
|
+
| `/name` | Name the native session | Renames the saved session | Not certified per command |
|
|
83
|
+
| `/compact` | Compact current context | Runs Harness compact command | Not certified per command |
|
|
84
|
+
| `/copy` | Copy last reply | Copies last reply to the clipboard | Not certified per command |
|
|
85
|
+
| `/export` | Export HTML or JSONL | Runs Harness session export; relative paths resolve from the project folder | Not certified per command |
|
|
86
|
+
| `/trajectory` | Inspect recorded runs | Opens trajectory view for the requested or latest run | Not certified per command |
|
|
87
|
+
| `/reload` | Reload trusted resources and keybindings | Reloads Harness resources and refreshes command discovery | Not certified per command |
|
|
88
|
+
| `/accounts` | Accounts page | Opens App Accounts | Not certified per command |
|
|
89
|
+
| `/permissions` | Permissions page | Opens App approval settings | Not certified per command |
|
|
90
|
+
| `/harness` | Harness resource browser | Opens App Harness screen | Not certified per command |
|
|
91
|
+
| `/skills` | Skills browser shortcut | Opens Capability skills | Not certified per command |
|
|
92
|
+
| `/connections` | Connections browser | Opens App connectors | Not certified per command |
|
|
93
|
+
| `/mcp` | Connections browser shortcut | Opens the same App connectors view | Not certified per command |
|
|
94
|
+
| `/tools` | Tools page | Opens Capability tools | Not certified per command |
|
|
95
|
+
| `/plugins` | Plugins page | Opens Capability plugins | Not certified per command |
|
|
96
|
+
| `/hub` | Hub browser | Opens Capability Hub | Not certified per command |
|
|
97
|
+
| `/components` | Components browser | Opens App Harness components | Not certified per command |
|
|
98
|
+
| `/settings` | Terminal settings | Opens App settings | Not certified per command |
|
|
99
|
+
| `/doctor` | Doctor checks, including explicitly confirmed live probes | Runs local readiness checks only | Not certified; App route does not expose live checks |
|
|
100
|
+
| `/worktree` | Managed-worktree page and actions | Lists worktrees; Solo has no typed create/status/remove methods wired, and no worktree level | PAR-012; management actions unavailable; not certified |
|
|
101
|
+
| `/subagents` | Live monitor and roster | Opens latest run's trajectory, not a dedicated subagent roster | Not certified; surfaces differ |
|
|
102
|
+
| `/agents` | Browse/create/edit/copy/delete profiles | Lists profiles only; detail/create/remove methods are not wired into Solo | PAR-010; management actions unavailable; not certified |
|
|
103
|
+
| `/log` | Harness diagnostics and current run events | Opens latest run's trajectory, not a separate log reader | Not certified; surfaces differ |
|
|
104
|
+
| `/hotkeys` | Keyboard controls | Opens App shortcut settings | Not certified per command |
|
|
105
|
+
| `/quit` | Restore terminal and exit | Closes the focused Solo tab; does not exit the App | Not certified per command |
|
|
106
|
+
|
|
53
107
|
The terminal-only display amendments [PROP-0026](architecture/proposals/PROP-0026-connected-sketch-display.md)
|
|
54
108
|
and [PROP-0028](architecture/proposals/PROP-0028-normalize-question-wireframes.md) permit connected
|
|
55
109
|
structural glyphs, frame-attached standalone dividers, and high-confidence boundary normalization
|
|
@@ -63,16 +117,18 @@ or live-model sketch quality.
|
|
|
63
117
|
| ID | Gap | Planned change |
|
|
64
118
|
|---|---|---|
|
|
65
119
|
| PAR-001 | Checklist absent from the App | The terminal registers the tool and renders a checklist block; the App renders it too. |
|
|
66
|
-
| PAR-002 | Wiki,
|
|
120
|
+
| PAR-002 | Acceptance of terminal-model History/Wiki/skill tools | Source gap resolved: `Terminals.ownTools` registers History/trajectory, Wiki-read and skill tools over the session socket; `xagent-wiki` is a user-facing shell utility, not the model's only route. Acceptance has not been recertified in this documentation pass. |
|
|
67
121
|
| PAR-003 | Continuation unused | `/resume` lists interrupted runs and continues one with `continueFrom`; the App offers Continue. |
|
|
68
122
|
| PAR-004 | Refinement and adoption only in the App | Variant tab actions: start, candidates, adopt, trust. |
|
|
69
123
|
| PAR-005 | Wiki browsing only in the App | A `/wiki` page over `wiki.*`. |
|
|
70
|
-
| PAR-006 |
|
|
124
|
+
| PAR-006 | Acceptance of terminal first-party hooks | Source gap resolved: enabled hooks are returned by protected `firstParty.list` and loaded by `terminal/piExtension.ts`. Acceptance has not been recertified in this documentation pass. |
|
|
71
125
|
| PAR-007 | Host tools without a Harness owner | Decide each: computer control stays host-backed (terminal shows unavailable); the files vault becomes a Harness capability or is dropped. |
|
|
72
|
-
| PAR-008 | Separate session catalogs |
|
|
73
|
-
| PAR-009 |
|
|
74
|
-
| PAR-010 | Agent
|
|
75
|
-
| PAR-011 |
|
|
76
|
-
| PAR-012 | Managed
|
|
77
|
-
| PAR-014 | Connected terminal sketch display | Closed by [PROP-0026 verification](evidence/terminal-connected-sketches/README.md) and extended by [PROP-0028 verification](evidence/terminal-wireframe-normalization/README.md): production PTY fixtures cover connected corners/tees, title-bearing rules, missing and whitespace-shifted side edges, internal table widths, frame-attached dividers, resize/panning and unchanged raw persistence/answers. Harness and host checks passed. Host literal rendering remains permitted; no host implementation change was required. This is fixture verification, not an every-font or live-model guarantee. |
|
|
126
|
+
| PAR-008 | Separate session catalogs | Proposal approved; shared catalog is not implemented. Terminal `/session` selects native Pi history in the current folder. App `/session` reads Solo `agent.threads`, maps threads through Solo project groups, and filters to the current effective account and folder; `/session all` broadens only within that App catalog. It cannot open an arbitrary native session path. No cross-surface catalog or visibility guarantee exists. |
|
|
127
|
+
| PAR-009 | Shared folder/recent-project choice | Terminal starts from its launch `cwd` and can switch through its worktree surface. App Solo uses Project › Session and starts new sessions in the selected project's folder; it has no folder/worktree level or shared recent-folder picker. |
|
|
128
|
+
| PAR-010 | Agent profile management in Solo | App Solo `/agents` can list profiles. Although the renderer allowlist includes `agents.get`, Solo does not wrap it; `agents.create/remove` are not exposed there. Profile details and management actions are unavailable, unlike terminal `/agents`. |
|
|
129
|
+
| PAR-011 | Web annotations | Harness, terminal and App source done (PROP-0017, PROP-0018, 2026-10-24): the App calls `annotations.*`, imports its old notes once, uses the `page_notes_*` tools, and has the Annotate panel. Open: acceptance of the inspector and selection gestures in the running App's WKWebView. PROP-0038 (2026-10-25): both front ends share the page helper, so open shadow roots work in the terminal's capture browser and the App's tabs alike; composed text capture, save, resolve and reveal were exercised in an isolated App WKWebView, inspector clicks were not. |
|
|
130
|
+
| PAR-012 | Managed worktree management in Solo | Harness and terminal provide full worktree operations (PROP-0016). Solo `/worktree` lists records only: its renderer adapter does not wire typed `worktrees.create`, `status` or `remove` calls, and Solo session creation stays at the project folder with no worktree level. Handoff, branch, prune, restore and setup-trust actions are also absent from this Solo surface. |
|
|
78
131
|
| PAR-013 | Expanded question wireframes and terminal layout | Closed by [PROP-0025 verification](evidence/terminal-question-wireframes/README.md): four-size production PTY acceptance covers aligned compact columns, body scrolling, pinned controls, Shift+arrow sketch panning and live resizing. Host contracts accept 80×24 literal ASCII sketches (1,943 bytes); six isolated browser tests include exact-boundary content, accessible overflow and unchanged selection/answers. This is controlled fixture acceptance, not live-provider or native Tauri evidence. |
|
|
132
|
+
| PAR-014 | Connected terminal sketch display | Closed by [PROP-0026 verification](evidence/terminal-connected-sketches/README.md) and extended by [PROP-0028 verification](evidence/terminal-wireframe-normalization/README.md): production PTY fixtures cover connected corners/tees, title-bearing rules, missing and whitespace-shifted side edges, internal table widths, frame-attached dividers, resize/panning and unchanged raw persistence/answers. Harness and host checks passed. Host literal rendering remains permitted; no host implementation change was required. This is fixture verification, not an every-font or live-model guarantee. |
|
|
133
|
+
| PAR-016 | Usage analytics and provider limits in the App | The terminal has `/usage:analysis` and `/usage:limit` over `usage.*`. The App presents the same capability: an analytics view and a per-account provider limit view. |
|
|
134
|
+
| PAR-015 | Native WebKit browser-tool coverage | The shared browser schema is wider than the native backend. Native WebKit supports navigation, tabs, visible-text reads and scrolling without refs. Accessibility snapshots, snapshot-ref interactions (including click/type/select/ref-scroll), browser screenshots, waits and keyboard presses return an explicit `browser_unsupported` refusal before effects; there is no automatic switch to the isolated Harness browser. See page 13 and the native backend's `surfaces` note. |
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Xingular Harness 1.1.1
|
|
2
|
+
|
|
3
|
+
The first published release of the 1.1 line, and npm `latest`. It follows the published 1.0.0
|
|
4
|
+
baseline. The 1.1.0 tag was pushed, but its release run stopped before publishing, so nothing was
|
|
5
|
+
published under 1.1.0.
|
|
6
|
+
|
|
7
|
+
## Agent profiles and named subagents
|
|
8
|
+
|
|
9
|
+
- A subagent can start from a named profile: the built-in `worker` and `explorer`, a person's
|
|
10
|
+
`<data root>/agents/<name>.md`, a repository's `.xingular/agents/<name>.md`, or a variant's c5
|
|
11
|
+
subagent. A profile narrows the child's tools and plugins and may choose its variant, model and
|
|
12
|
+
effort (PROP-0029, ADR-0030).
|
|
13
|
+
- The parent names each subagent. `spawn_subagent` requires a short `title`; `subagents.spawn`
|
|
14
|
+
takes an optional one (PROP-0030). The live roster, `/subagents` and the transcript show the
|
|
15
|
+
title.
|
|
16
|
+
- The terminal runs the checklist tool and shows each write as a checklist block. An in-progress
|
|
17
|
+
item shows a yellow dot, and a running subagent's row shows the working spinner in its profile's
|
|
18
|
+
colour.
|
|
19
|
+
|
|
20
|
+
## Release pipeline
|
|
21
|
+
|
|
22
|
+
- The release pack and smoke scripts take their npm cache from the system temp folder. They
|
|
23
|
+
previously used a macOS-only path, which failed on Linux runners.
|
|
24
|
+
- The `/help` terminal check matches the documented grouped, scrollable help: it pages until every
|
|
25
|
+
group is seen, and its expected group is `Plugins`.
|
|
26
|
+
|
|
27
|
+
Checks for this release: `npm run ci` (148 test files, 1111 tests), the exact-tarball fresh
|
|
28
|
+
installation smoke test including the packaged terminal, and the release preflight.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Xingular Harness 1.2.0
|
|
2
|
+
|
|
3
|
+
This release builds on the published 1.1.1 line.
|
|
4
|
+
|
|
5
|
+
## Compatibility note
|
|
6
|
+
|
|
7
|
+
The filesystem root cannot be used as an active workspace, because that would make the boundary
|
|
8
|
+
meaningless. The workspace boundary is intentionally stricter: model-controlled writes outside the active project,
|
|
9
|
+
including writes to temporary directories, require a one-call approval unless the eligible Full
|
|
10
|
+
Permission switch is explicitly enabled. Remembered per-tool grants do not cover them; unattended
|
|
11
|
+
runs cannot request approval. The Full Permission switch remains off by default. A workspace with
|
|
12
|
+
an external hard-link alias blocks default-scope Bash until the alias is removed or the file is
|
|
13
|
+
replaced with a copy. Native writes use atomic replacement and preserve ordinary file mode where
|
|
14
|
+
possible; ACLs and extended attributes are not guaranteed to survive replacement. On macOS, the
|
|
15
|
+
sandbox also blocks workspace-local hard-link creation.
|
|
16
|
+
|
|
17
|
+
## Workspace write boundary
|
|
18
|
+
|
|
19
|
+
Model-controlled file writes and Bash are scoped to the active project workspace by default. Native
|
|
20
|
+
write/edit operations revalidate the target and atomically replace the directory entry under an
|
|
21
|
+
OS-enforced write scope, so an in-workspace hard link does not modify an outside alias. Default Bash
|
|
22
|
+
scans for external hard links and runs in an OS sandbox that prevents cross-boundary hard-link
|
|
23
|
+
creation; unavailable or incomplete enforcement fails closed. Reads remain unchanged. Explicit
|
|
24
|
+
outside Bash writes require pre-execution one-call approval and run exactly once (`workspaceWriteScope:
|
|
25
|
+
'outside'`; in the terminal composer, `!outside <command>`). The approval shows the complete quoted
|
|
26
|
+
command in scrollable details; if the terminal is too small to show both details and choices, the
|
|
27
|
+
request is denied. Command output cannot trigger approval or automatic retry. Runs record their
|
|
28
|
+
resolved `workspaceRoot`; older run records remain readable.
|
|
29
|
+
Protection from a separate same-user process outside Harness is not provided.
|
|
30
|
+
|
|
31
|
+
## Planning and run continuity
|
|
32
|
+
|
|
33
|
+
Plan mode now requires evidence-grounded repository research and can delegate bounded read-only investigations to eligible research profiles. After compaction, active runs rehydrate the latest checklist and plan instructions. The terminal keeps the latest subagent status visible until its next run.
|
|
34
|
+
|
|
35
|
+
## Terminal commands and annotations
|
|
36
|
+
|
|
37
|
+
Plugin-owned terminal commands use `/<owner-prefix>:<command>`, while Harness-owned routes such as `/doctor`, `/worktree`, `/trajectory`, `/subagents`, and `/agents` are first-class core commands. Prior command forms remain hidden compatibility aliases for one release; migrate scripts and keybindings to the canonical names.
|
|
38
|
+
|
|
39
|
+
The annotation inspector now supports content in open shadow roots, including composed selections and targets. Closed shadow roots and frames remain unsupported, and existing document-only annotations retain their behavior.
|
|
40
|
+
|
|
41
|
+
## Terminal interaction
|
|
42
|
+
|
|
43
|
+
`/session` without a path now opens a searchable saved-session picker. Composer history includes user prompts, Bash commands and executed slash commands; browsing temporarily replaces the draft and restores its cursor, mode and attachments when it returns. Compact question docks now size each tab independently, keep nested sketches scrollable, and preserve page-footer hints at narrow widths.
|
|
44
|
+
|
|
45
|
+
## Performance evidence
|
|
46
|
+
|
|
47
|
+
Adds reproducible PTY and session-runtime profiling and publishes the [EXP-0003 report](../experiments/EXP-0003-performance-audit/results.md). That report is a 1.1.1 baseline captured from a dirty worktree, not a clean 1.2.0 benchmark; it also records a failed narrow-width `/settings` footer check and other measurement limits.
|
|
48
|
+
|
|
49
|
+
Node 22.19 or later is required. Building or running the standalone terminal also requires Bun 1.3.14 or later. See the project license and notices for third-party terms.
|
package/docs/releases/4.0.0.md
CHANGED
|
@@ -8,11 +8,11 @@ terminal command namespace, documented below. Earlier published versions remain
|
|
|
8
8
|
|
|
9
9
|
- Managed Git worktrees for sessions and the terminal, with leases, guarded setup scripts, handoff,
|
|
10
10
|
pruning, restoration, and bounded snapshots that preserve uncommitted work.
|
|
11
|
-
-
|
|
12
|
-
through Harness methods and terminal `/
|
|
11
|
+
- Web annotations and queued comments, including capture, review, resolution, sharing, and delivery
|
|
12
|
+
through Harness methods and terminal `/annotate:` and `/annotate:notes` pages.
|
|
13
13
|
- A unified terminal resource browser with persistent full-screen sections for browser tabs,
|
|
14
14
|
plugins, skills, connectors, variants, and other Harness resources.
|
|
15
|
-
- A full-screen `/trajectory` Runs/Events browser with searchable event details, selected-event
|
|
15
|
+
- A full-screen `/history:trajectory` Runs/Events browser with searchable event details, selected-event
|
|
16
16
|
JSON, and a responsive split-pane layout.
|
|
17
17
|
- Additional terminal controls for browser settings, plugin settings, and subagent activity.
|
|
18
18
|
- Fix Node 22 SQLite parameter binding in recall and run indexes, and guard worktree Git calls
|
|
@@ -31,12 +31,13 @@ credentials are configured inside an isolated Harness account.
|
|
|
31
31
|
|
|
32
32
|
The new server methods are additive. The published executable is `xagent`, replacing the earlier
|
|
33
33
|
`xharness` candidate command without a compatibility alias; scripts using that candidate name must
|
|
34
|
-
be updated.
|
|
35
|
-
`/subagents`, `/trajectory`, `/doctor`,
|
|
36
|
-
|
|
37
|
-
`/
|
|
38
|
-
for
|
|
39
|
-
place. Install this exact version or use the `latest` tag; historical
|
|
34
|
+
be updated. All plugin-owned terminal commands use `/<owner-prefix>:<command>`: for example,
|
|
35
|
+
`/subagents:subagents`, `/history:trajectory`, `/doctor:doctor`, `/worktrees:worktree`, and
|
|
36
|
+
`/annotate:annotate`. The annotation prefix root `/annotate:` opens the default capture pane, and
|
|
37
|
+
`/annotate:notes` opens saved annotations. Existing `/plugin:<command>` and former bare required-plugin
|
|
38
|
+
forms remain hidden compatibility aliases for one release. Existing session, variant, account, plugin,
|
|
39
|
+
and browser contracts remain in place. Install this exact version or use the `latest` tag; historical
|
|
40
|
+
versions remain available.
|
|
40
41
|
|
|
41
42
|
## Verification scope
|
|
42
43
|
|
package/docs/releases/README.md
CHANGED
|
@@ -1,41 +1,46 @@
|
|
|
1
1
|
# Release procedure
|
|
2
2
|
|
|
3
|
-
1. Review and commit completed Harness changes on the active release branch. Review App
|
|
3
|
+
1. Review and commit the completed Harness changes on the active release branch. Review App
|
|
4
4
|
compatibility changes separately. Preserve old tags and exclude outputs, external references,
|
|
5
5
|
and caches.
|
|
6
|
-
2. Run npm run ci and the required App checks on
|
|
7
|
-
1.4.2 and use Node 22.19.0
|
|
8
|
-
3. Run npm run release:pack
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
5. Present the exact commit, candidate inventory
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
6. After approval, push the reviewed
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
6
|
+
2. Run `npm run ci` and the required App checks. Require green CI on Ubuntu and macOS; install Bun
|
|
7
|
+
1.4.2 and use Node 22.19.0. Do not waive failing checks.
|
|
8
|
+
3. Run `npm run release:pack` and inspect the candidate inventory, SHA-256 and npm integrity. Run
|
|
9
|
+
`npm run release:smoke -- <tarball> --terminal` for a fresh-install SDK/server/terminal check;
|
|
10
|
+
`--offline` is only a local smoke check, not fresh-install acceptance.
|
|
11
|
+
4. Run `npm run release:preflight`. Verify npm scope ownership and trusted-publisher settings for
|
|
12
|
+
`tanntnny/xingular-harness` and `release.yml`, with direct publishing enabled. Configure the
|
|
13
|
+
GitHub `npm-publish` environment with required reviewers. No login is started automatically; an
|
|
14
|
+
already-used version, unreachable registry, or missing publishing configuration blocks release.
|
|
15
|
+
5. Candidate approval is a pre-tag gate. Present the exact clean commit, candidate inventory,
|
|
16
|
+
SHA-256, npm integrity, release notes and check results for approval. Do not create or push the
|
|
17
|
+
matching `v<version>` tag until the person explicitly approves that candidate.
|
|
18
|
+
6. After candidate approval, push the reviewed commit and matching tag. The workflow reruns CI on
|
|
19
|
+
both OSes, builds one candidate, and smoke-tests that exact tarball on both OSes. Before approving
|
|
20
|
+
the protected `npm-publish` environment, compare the uploaded candidate's commit, SHA-256 and npm
|
|
21
|
+
integrity with the approved local candidate; stop if they differ. This environment approval is a
|
|
22
|
+
separate publication gate. The publish job publishes that same tarball with OIDC provenance and
|
|
23
|
+
`--tag latest`, then verifies registry integrity/provenance and creates a GitHub release. No local
|
|
24
|
+
publishing token is needed. Inspect registry state before retrying any failed publication.
|
|
22
25
|
|
|
23
26
|
A published version cannot be replaced. Corrections require a later version. This package's
|
|
24
27
|
intentional 1.0.0 reset does not rewrite historical decisions or claim an ordering above older
|
|
25
28
|
2.x–5.x development versions. Publication status and local evidence belong in the candidate report.
|
|
26
29
|
|
|
27
|
-
## 4.0.0 candidate
|
|
30
|
+
## Historical 4.0.0 candidate evidence
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
1
|
|
31
|
-
tests, 47 sidecar tests, and 7 dev-signing tests passed with 1 skipped), layer check, and Rust tests
|
|
32
|
-
(168 passed, 1 ignored); and App UI consistency. The registry lists 1.0.0 as `latest` and 4.0.0 as
|
|
33
|
-
unused. The clean-tree release preflight passed. Exact-tarball packaging and a fresh-install smoke
|
|
34
|
-
test passed, including the packaged SDK, types, CLI, server and isolated terminal. The tagged
|
|
35
|
-
preflight, two-OS CI, and exact-tarball smoke are enforced by the release workflow. The npm
|
|
36
|
-
trusted-publisher configuration for `tanntnny/xingular-harness` and `release.yml` requires
|
|
37
|
-
package-owner verification; `npm login` does not verify that setting.
|
|
32
|
+
The following report records a prior candidate and registry snapshot; it is not evidence for the
|
|
33
|
+
1.2.0 candidate or a description of the current release gates.
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
At the time, local checks on that candidate source passed: Harness `npm run ci` (typecheck, 134 test
|
|
36
|
+
files with 1,004 passing tests and 3 skipped, plus the standalone proof); App typecheck, `npm test`
|
|
37
|
+
(566 renderer tests, 47 sidecar tests, and 7 dev-signing tests passed with 1 skipped), layer check,
|
|
38
|
+
and Rust tests (168 passed, 1 ignored); and App UI consistency. The registry snapshot listed 1.0.0 as
|
|
39
|
+
`latest` and 4.0.0 as unused. Its clean-tree preflight, exact-tarball packaging and fresh-install
|
|
40
|
+
smoke test passed. The package-owner verification of npm trusted-publisher configuration for
|
|
41
|
+
`tanntnny/xingular-harness` and `release.yml` was still required; `npm login` does not verify that
|
|
42
|
+
setting. These results and registry values are historical.
|
|
43
|
+
|
|
44
|
+
At that time, the workflow ran full CI and exact-tarball smoke on Ubuntu and macOS before publishing.
|
|
45
|
+
The current workflow and approval gates are described above. No local test failure was waived by the
|
|
46
|
+
historical report.
|
package/docs/study/00-index.md
CHANGED
|
@@ -20,6 +20,9 @@ written and the claim moves to checked behavior. Cite material as
|
|
|
20
20
|
side question, and checked-out external implementations.
|
|
21
21
|
- [Harness feature-gap review](feature-gap-review.md) — task/goal management, long-running work,
|
|
22
22
|
memory, execution isolation, verification, and observability gaps against the studied peers.
|
|
23
|
+
- [Why a long run takes hours](STUDY-0003-long-horizon-runs.md) — measured diagnosis of two 70–97
|
|
24
|
+
minute replies (447 and 266 tool calls, 5 and 2 compactions, zero assistant text), what other
|
|
25
|
+
harnesses do about it, and the fixes proposed in [PROP-0041](../architecture/proposals/PROP-0041-bounded-work-slices.md).
|
|
23
26
|
|
|
24
27
|
## Sources
|
|
25
28
|
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: STUDY-0003
|
|
3
|
+
title: Why a long run takes hours — measured diagnosis of two long sessions
|
|
4
|
+
status: measured-diagnosis; fix proposed in PROP-0041
|
|
5
|
+
created: 2026-10-26
|
|
6
|
+
updated: 2026-10-26
|
|
7
|
+
related:
|
|
8
|
+
- PROP-0033
|
|
9
|
+
- PROP-0041
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Why a long run takes hours
|
|
13
|
+
|
|
14
|
+
**Answer.** Neither session was looping on a single action — both kept changing files and running checks. But both ran as **one unbroken reply**: 448 and 274 tool calls, 5 and 2 context compactions, and a single assistant message at the very end, or none at all. The 75-minute session produced one final report and said **"release is still blocked"**. The other was **still running at 114 minutes when measured, with 448 tool calls and not one word to the person**. 41 of those minutes were three Playwright runs, 25 of them on two timeouts, and 55 minutes were 307 model requests averaging 10.7 s each over a ~140k-token context.
|
|
15
|
+
|
|
16
|
+
The loop is in the **shape of the reply**, not in the goal. The fix is not a better prompt; it is a bounded reply, a durable checkpoint, and a loop guard. [PROP-0041](../architecture/proposals/PROP-0041-bounded-work-slices.md)
|
|
17
|
+
proposes them.
|
|
18
|
+
|
|
19
|
+
## What was measured
|
|
20
|
+
|
|
21
|
+
Both sessions are ordinary records under the dev data root
|
|
22
|
+
(`~/.xingular-harness-dev/data/runs/<id>/`), read together with their native Pi session. Nothing was
|
|
23
|
+
re-run; every number below comes from `events.jsonl`, `run.json` and the native `*.jsonl`.
|
|
24
|
+
|
|
25
|
+
| | A — "Finish App Harness parity integration" | B — "Complete secure Harness release candidate" |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| Run | `64cdd5f0` | `2d62eaec` |
|
|
28
|
+
| User text that started it | "continue where you left of" | "continue where left of" |
|
|
29
|
+
| Started / last event | 17:50:43Z / 19:44:57Z at the cut, still active | 18:27:46Z / 19:42:40Z |
|
|
30
|
+
| Wall clock | **114.3 min at the cut, still running** | **74.9 min** |
|
|
31
|
+
| How it ended | no end: the same reply was still going | one final report, `completed` |
|
|
32
|
+
| Recorded state afterwards | `running` | `completed` |
|
|
33
|
+
| Model requests | 307 | 197 |
|
|
34
|
+
| Model time | 3299 s (55.0 min), mean 10.7 s, p90 20.0 s | 2924 s (48.7 min), mean 14.8 s, p90 30.4 s |
|
|
35
|
+
| Tool calls | 448 | 274 |
|
|
36
|
+
| Tool time | 3491 s (58.2 min), 51 % of the run | ~1420 s (23.7 min), 32 % |
|
|
37
|
+
| Reads | 163 over 96 paths (`host.rs` 11×) | 101 over 56 paths (`verify-terminal.py` 6×) |
|
|
38
|
+
| Edits | 61 over 35 files (`app.test.ts` 10×) | 78 over 30 files (`07-tools-and-gate.md` 9×) |
|
|
39
|
+
| Identical repeated calls | 42 instances, 20 signatures | 10 instances, 5 signatures |
|
|
40
|
+
| Billed tokens | 18.85 M input + 25.01 M cache read | 16.70 M input + 12.94 M cache read |
|
|
41
|
+
| Output tokens | 221 k, of which 175 k reasoning (79 %) | 205 k, of which 173 k reasoning (84 %) |
|
|
42
|
+
| Cost recorded by the harness | $2.23 | $1.66 |
|
|
43
|
+
| Compactions inside the run | **5**, at 255 852–269 591 tokens | **2** (7 across the 5-hour thread) |
|
|
44
|
+
| Cold re-sends (no cache read, >20 k input) | 9 requests, 1.58 M uncached tokens | 9 requests, 1.51 M uncached tokens |
|
|
45
|
+
| Assistant text inside the run | **0 characters** | **0 characters until 74.9 min**, then one 2 028-character report |
|
|
46
|
+
| Approvals | 49, all remembered, 0.0 s wait | 2, both remembered |
|
|
47
|
+
|
|
48
|
+
Run A was still producing events while this was written (314 model requests at 19:48Z); every number
|
|
49
|
+
for it is frozen at 19:44:57Z, 114.3 minutes in. Run B had already settled.
|
|
50
|
+
|
|
51
|
+
### Where run A's 114 minutes went
|
|
52
|
+
|
|
53
|
+
| Bucket | Time | Share |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| Model requests (307) | 55.0 min | 48 % |
|
|
56
|
+
| Bash (129 calls) | 57.6 min | 50 % |
|
|
57
|
+
| — three Playwright runs: 600 s timeout, 900 s timeout, 986 s success | 41.4 min | 36 % |
|
|
58
|
+
| Reads, edits, searches, subagent waits | ~0.5 min | 1 % |
|
|
59
|
+
| Unaccounted idle | ~1.2 min | 1 % |
|
|
60
|
+
|
|
61
|
+
The harness was busy for 98.5 % of the wall clock. Nothing was hung; the reply was simply too long,
|
|
62
|
+
and every step paid full-context latency. The same browser suite ran three times because it timed out
|
|
63
|
+
twice without narrowing itself, and each retry cost the full command budget.
|
|
64
|
+
|
|
65
|
+
That 986-second command is also why a heartbeat matters: from request 306 at 19:27:56 to request 307
|
|
66
|
+
at 19:44:29 there is **no event for 16.6 minutes**. A busy run and a wedged one look identical on the
|
|
67
|
+
record.
|
|
68
|
+
|
|
69
|
+
### Was it progressing?
|
|
70
|
+
|
|
71
|
+
Yes, measurably:
|
|
72
|
+
|
|
73
|
+
- 57 `file.changed` events in A at a steady rate (13, 6, 9, 6, 4, 9, 10 per ten minutes), longest gap
|
|
74
|
+
between changes 23.6 min; 74 in B, longest gap 17.5 min.
|
|
75
|
+
- 57 successful test/typecheck commands in A; 28 of 129 Bash calls failed and were retried.
|
|
76
|
+
- The checklist moved (B: 3 of 7 items completed across 9 checklist writes, and items were added as
|
|
77
|
+
gaps were found).
|
|
78
|
+
- B's last message is a real report: what changed, which checks passed (1 255 Harness tests, 586 App
|
|
79
|
+
tests, 185 Rust tests), and what remains blocked. That is genuine incremental work with an honest
|
|
80
|
+
ending — after 75 minutes and 274 tool calls.
|
|
81
|
+
|
|
82
|
+
But the same data shows the waste:
|
|
83
|
+
|
|
84
|
+
- 42 calls in A were byte-identical repeats of an earlier call; 20 distinct signatures were repeated.
|
|
85
|
+
- `host.rs` was read 11 times; `07-tools-and-gate.md` was edited 9 times as the checklist reworded
|
|
86
|
+
what "done" meant.
|
|
87
|
+
- Run B read its own trajectory 63 times and searched it 8 times — recovering, inside the run, state
|
|
88
|
+
that earlier compactions had dropped.
|
|
89
|
+
- Neither session produced a commit. The worktree is still dirty: B's own report counts 119 tracked
|
|
90
|
+
changes and 267 untracked files, which failed release preflight's clean-tree check. So "continue
|
|
91
|
+
where you left off" had no unambiguous answer — the work is real, but it is not a deliverable.
|
|
92
|
+
- A's checklist was rewritten 7 times (B's 9) and its items were reworded each time
|
|
93
|
+
("Complete Harness launch…" → "Complete App commands…" → "Complete App shared-profile…" →
|
|
94
|
+
"Close profile-root migration…" → "Finish App shared-profile…"). That is scope drift, not a
|
|
95
|
+
maintained plan.
|
|
96
|
+
|
|
97
|
+
So: **incremental work, at roughly half efficiency, with no visible progress and no way to stop
|
|
98
|
+
cleanly.** A person watching saw tool rows for 75–114 minutes, then either a single report or nothing
|
|
99
|
+
at all.
|
|
100
|
+
|
|
101
|
+
## The mechanisms that are missing
|
|
102
|
+
|
|
103
|
+
Measured against the code (all verified in this tree):
|
|
104
|
+
|
|
105
|
+
| Mechanism | State in this tree | Consequence |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| Reply budget | Only the opt-in `budget-guard` plugin (`src/plugins/firstParty.ts:31,105-140`), **off by default** and a blunt stop: it refuses tools and terminates the reply with no checkpoint | One reply ran 114 min and 448 calls |
|
|
108
|
+
| Checkpoint | PROP-0033's checkpoint exists (`src/sessions/compactionCheckpoint.ts`), but it restores only *goal + checklist + plan*, and `renderCompactionCheckpoint` returns `null` when there is no checklist (`src/prompt/compile.ts:196`) | No files, no failing commands, no decisions; A wrote no assistant text at all |
|
|
109
|
+
| Compaction discipline | Pi compacts at ~94 % of the window; the harness only observes it (`src/sessions/runner.ts:470-478`) | 5 compactions in one reply, each a cold re-send; state rebuilt by re-reading files |
|
|
110
|
+
| Command ceiling | Bash `timeout` is optional, "no default timeout" (`src/core/workspaceBashTool.ts:23`) | 41 minutes in three Playwright runs; 36 % of run A |
|
|
111
|
+
| Loop / stall detection | None (`rg loop|stuck|repeat` finds nothing in `src/sessions`) | 42 duplicate calls; 9 edits to one document |
|
|
112
|
+
| Liveness | Reconciliation runs only at startup and is keyed on the owner pid (`src/sessions/runStore.ts:228`); `owner.json` holds a bare pid | A run that stops producing events while its process lives is never settled, and a recycled pid can make a dead owner look alive. A long command already writes nothing for 16.6 minutes |
|
|
113
|
+
| Progress visibility | No mid-reply text requirement; `REPORTING_GUIDANCE` shapes only the final reply | 0 characters in 114 minutes and counting for A; one message at 74.9 minutes for B |
|
|
114
|
+
|
|
115
|
+
The layer boundary matters for the fix: task and goal lifecycle belong to the application
|
|
116
|
+
(`docs/study/feature-gap-review.md:7,35`). Everything above is **run execution**, which the harness
|
|
117
|
+
owns. PROP-0041 keeps it there.
|
|
118
|
+
|
|
119
|
+
## What other harnesses do about this
|
|
120
|
+
|
|
121
|
+
Fetched 2026-10-26; URLs are the primary sources.
|
|
122
|
+
|
|
123
|
+
| Mechanism | Who | Trigger | What it prevents |
|
|
124
|
+
|---|---|---|---|
|
|
125
|
+
| Stop hook that blocks the turn from ending until a check passes, with a cap on consecutive blocks | [Claude Code](https://code.claude.com/docs/en/best-practices) | Turn end | "Looks done" endings and endless turns |
|
|
126
|
+
| Auto-compaction thrash guard: after a few refills, stop compacting and report the offending oversized result | [Claude Code troubleshooting](https://code.claude.com/docs/en/troubleshooting) | Repeated compaction in one turn | Summarise–refill loops |
|
|
127
|
+
| Post-compaction re-injection of the plan file and up to five recently touched files (path only above 5k tokens) | [Claude Code context window](https://code.claude.com/docs/en/context-window) | Compaction | State lost to the summarizer |
|
|
128
|
+
| Tool-result clearing before summarisation | [Anthropic context engineering](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) | Context pressure | Unbounded context growth |
|
|
129
|
+
| Subagents with a 1–2k-token return contract | [Claude Code sub-agents](https://code.claude.com/docs/en/sub-agents) | Model decision | Exploration flooding the main context |
|
|
130
|
+
| `todo.md` recitation at the end of context; restorable compression (drop content, keep URL/path); keep failed actions | [Manus](https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus) | Every step / compression | Goal drift, repeated mistakes |
|
|
131
|
+
| Loop detection by hashing `toolName + args`, cycle length 1–5 repeated 5×, plus an LLM judge after 30 turns | [Gemini CLI loopDetectionService.ts](https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/services/loopDetectionService.ts) | Every streamed tool call | Oscillation and repeated failing commands |
|
|
132
|
+
| Stop hook with `loop_count` and `MAX_ITERATIONS = 5` | [Cursor](https://cursor.com/blog/agent-best-practices) | Turn end | Unbounded single turn |
|
|
133
|
+
| `max_requeries = 3` on malformed or blocked actions | [SWE-agent config](https://swe-agent.com/latest/reference/agent_config/) | Action error | Infinite retry |
|
|
134
|
+
| Repo map under a 1k-token budget (PageRank over the dependency graph) | [Aider repomap](https://aider.chat/docs/repomap.html) | Every request | Re-reading files to re-orient |
|
|
135
|
+
| Auto-commit, lint and test after each edit | [Aider git](https://aider.chat/docs/git.html) | Each edit | Long stretches with no checkpoint |
|
|
136
|
+
| Event-count condenser that keeps the first events | [OpenHands context condenser](https://docs.openhands.dev/sdk/guides/context-condenser) | History size | Cost and latency growth |
|
|
137
|
+
| Pre/post-turn compaction phases and pre/post-compact hooks | [Codex compact.rs](https://raw.githubusercontent.com/openai/codex/main/codex-rs/core/src/compact.rs) | Turn boundaries | Unpredictable compaction |
|
|
138
|
+
| Truncate-then-summarise plan saved to memory because the window will truncate | [Anthropic multi-agent research](https://www.anthropic.com/engineering/multi-agent-research-system) | Context limit | Losing the plan |
|
|
139
|
+
|
|
140
|
+
Two reference scales are worth stating plainly: Manus reports **~50 tool calls per task**, and
|
|
141
|
+
Claude Code's published loop cap is **5 iterations**. Both runs here exceeded those by 5–9× inside a
|
|
142
|
+
single reply that addressed the person once, at the end, or not at all.
|
|
143
|
+
|
|
144
|
+
Context rot compounds it: performance degrades as input grows and is worst for content in the middle
|
|
145
|
+
of a long context ([Chroma](https://www.trychroma.com/research/context-rot),
|
|
146
|
+
[Lost in the middle](https://arxiv.org/abs/2307.03172)). A 250k-token context is therefore both slow
|
|
147
|
+
and less reliable — the re-reads and reworded checklists are what that looks like.
|
|
148
|
+
|
|
149
|
+
## What to adopt, in order
|
|
150
|
+
|
|
151
|
+
1. **P0, configuration only, today.** Switch on `output-trim` (20 000 chars) and `budget-guard`
|
|
152
|
+
(120 requests) in the plugin attachments of the affected account/project. That alone caps the
|
|
153
|
+
reply and shrinks tool results. No architecture change, reversible per account and per project.
|
|
154
|
+
2. **P0b, small foundation fixes.** A default Bash timeout that returns partial output, and a stall
|
|
155
|
+
watchdog keyed on heartbeat age rather than only the owner pid. Both are narrow and independent of
|
|
156
|
+
the slice design below.
|
|
157
|
+
3. **P1, bounded work slices (PROP-0041).** A reply budget of 160 tool calls / 40 min / 320k new
|
|
158
|
+
tokens, a validated checkpoint at the boundary, and a continuation that starts from that
|
|
159
|
+
checkpoint. This is the structural fix.
|
|
160
|
+
4. **P2, the checkpoint as state, not prose.** Bounded, evidence-linked (files, failing checks,
|
|
161
|
+
decisions, next step) and injected at every slice start and after compaction, so the model never
|
|
162
|
+
re-derives state by archaeology.
|
|
163
|
+
5. **P3, deterministic loop guard.** Identical `tool + args` three times, the same command failing
|
|
164
|
+
twice, or 25 steps with no file change and no passing check: nudge once with the evidence, then
|
|
165
|
+
end the slice as `blocked`.
|
|
166
|
+
6. **P4, command budget.** Hard ceiling, and long suites (Playwright, full CI) as background work
|
|
167
|
+
rather than 16 blocking minutes.
|
|
168
|
+
7. **P5, compaction pipeline.** Clear old tool results first; summarise with restorable references
|
|
169
|
+
(path + line range); stop after three compactions in one reply and hand off instead.
|
|
170
|
+
8. **P6, visible progress.** Record narration as `progress` events and a heartbeat with steps,
|
|
171
|
+
elapsed time, slice and compactions; show "next checkpoint in N steps" in both surfaces.
|
|
172
|
+
|
|
173
|
+
## How to judge whether it worked
|
|
174
|
+
|
|
175
|
+
Baseline from these two runs, to compare after PROP-0041:
|
|
176
|
+
|
|
177
|
+
| Metric | Baseline |
|
|
178
|
+
|---|---|
|
|
179
|
+
| Time to first user-visible text | never (A) / 74.9 min (B) |
|
|
180
|
+
| Tool calls per user-visible text | ∞ (A) / 274 (B) |
|
|
181
|
+
| Longest reply | 114 min and counting / 448 calls |
|
|
182
|
+
| Compactions per reply | 2–5 |
|
|
183
|
+
| Repeated identical calls | 42 per 448 (9 %) |
|
|
184
|
+
| Reads per distinct file | 1.7 (163/96), worst 11 |
|
|
185
|
+
| Time in three Playwright runs | 36 % of run A |
|
|
186
|
+
| Runs left `running` after owner death | 1 of 2 |
|
|
187
|
+
|
|
188
|
+
A working slice policy should keep the longest reply under ~45 minutes, put text in front of the
|
|
189
|
+
person at every boundary, hold compactions to at most one per slice, and never leave a run
|
|
190
|
+
`running` after its owner is gone.
|
|
191
|
+
|
|
192
|
+
## What this does not fix
|
|
193
|
+
|
|
194
|
+
Model latency per token, the correctness of the work itself, or a task whose acceptance criteria
|
|
195
|
+
were never written down. A slice boundary cannot invent a definition of done; it can only make the
|
|
196
|
+
absence of one visible early.
|
|
197
|
+
|
|
198
|
+
## Appendix: how to reproduce
|
|
199
|
+
|
|
200
|
+
Read-only, from the dev data root:
|
|
201
|
+
|
|
202
|
+
```sh
|
|
203
|
+
R=~/.xingular-harness-dev/data/runs/64cdd5f0-da45-43a1-9130-89c54f298f21
|
|
204
|
+
jq -r 'select(.type=="usage.updated") | .payload.request.durationMs' "$R/events.jsonl" | awk '{s+=$1/1000; n++} END {print n" requests, "s" s"}'
|
|
205
|
+
jq -r 'select(.type=="tool.completed") | .payload.name' "$R/events.jsonl" | sort | uniq -c | sort -rn
|
|
206
|
+
jq -r 'select(.type=="message.completed") | .payload.role' "$R/events.jsonl"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The assistant's own text lives in the native session named by `run.json`
|
|
210
|
+
(`nativeSessionId`), as `message` entries whose `content` blocks have `type: "text"`.
|