@xingular/harness 2.1.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/NOTICE.md +22 -0
  3. package/README.md +67 -36
  4. package/dist/cli.js +6023 -6621
  5. package/dist/terminal-pi.js +19 -24
  6. package/docs/terminal-tui.md +27 -7
  7. package/package.json +2 -2
  8. package/src/accounts/accounts.ts +4 -3
  9. package/src/capabilities/api.ts +1 -1
  10. package/src/cli.ts +7 -3
  11. package/src/core/caller.ts +34 -0
  12. package/src/core/fs.ts +17 -1
  13. package/src/harness.ts +55 -66
  14. package/src/{memory → history}/recall.test.ts +1 -1
  15. package/src/{memory → history}/recall.ts +1 -1
  16. package/src/{memory → history}/trajectory.test.ts +4 -4
  17. package/src/{memory → history}/trajectory.ts +1 -1
  18. package/src/hub/hub.test.ts +4 -5
  19. package/src/hub/hub.ts +2 -2
  20. package/src/index.ts +28 -14
  21. package/src/mcp/connections.ts +1 -1
  22. package/src/mcp/service.ts +1 -1
  23. package/src/pi/proxy.test.ts +68 -0
  24. package/src/pi/runtime.test.ts +61 -0
  25. package/src/pi/runtime.ts +50 -0
  26. package/src/plugins/api.ts +11 -9
  27. package/src/plugins/builtin.ts +22 -40
  28. package/src/plugins/catalogue.test.ts +13 -41
  29. package/src/plugins/catalogue.ts +3 -32
  30. package/src/plugins/discover.ts +2 -1
  31. package/src/plugins/firstParty.test.ts +1 -1
  32. package/src/plugins/hooks.test.ts +21 -71
  33. package/src/plugins/hooks.ts +6 -7
  34. package/src/plugins/identity.ts +16 -2
  35. package/src/plugins/install.test.ts +1 -1
  36. package/src/plugins/install.ts +2 -1
  37. package/src/plugins/inventory.ts +19 -18
  38. package/src/plugins/plugins.ts +38 -2
  39. package/src/prompt/compile.test.ts +82 -193
  40. package/src/prompt/compile.ts +98 -363
  41. package/src/refine/cli.ts +114 -0
  42. package/src/refine/demo.ts +124 -0
  43. package/src/refine/evidence.ts +349 -0
  44. package/src/refine/host.ts +102 -0
  45. package/src/refine/ledger.ts +104 -0
  46. package/src/refine/library.ts +192 -0
  47. package/src/refine/pi.test.ts +90 -0
  48. package/src/refine/pi.ts +218 -0
  49. package/src/refine/prompts.ts +430 -0
  50. package/src/refine/recursion.ts +353 -0
  51. package/src/refine/refine.test.ts +140 -0
  52. package/src/refine/runner.ts +205 -0
  53. package/src/refine/selection.ts +291 -0
  54. package/src/refine/service.ts +194 -0
  55. package/src/refine/trajectory.ts +71 -0
  56. package/src/refine/types.ts +91 -0
  57. package/src/server/methods.ts +137 -123
  58. package/src/server/server.test.ts +37 -30
  59. package/src/sessions/contracts.ts +6 -1
  60. package/src/sessions/conversation.test.ts +2 -27
  61. package/src/sessions/policy.ts +1 -1
  62. package/src/sessions/pricing.ts +3 -1
  63. package/src/sessions/registry.ts +5 -1
  64. package/src/sessions/runStore.ts +3 -1
  65. package/src/sessions/runner.ts +10 -5
  66. package/src/sessions/sessions.test.ts +45 -6
  67. package/src/sessions/sessions.ts +40 -17
  68. package/src/sessions/subagentService.test.ts +22 -1
  69. package/src/sessions/subagentService.ts +14 -1
  70. package/src/sessions/subagents.ts +2 -0
  71. package/src/terminal/cli.ts +24 -48
  72. package/src/terminal/pluginControl.test.ts +7 -8
  73. package/src/terminal/socket.ts +3 -3
  74. package/src/terminal/terminal.test.ts +21 -39
  75. package/src/terminal/terminals.ts +20 -13
  76. package/src/terminal/tui/application.test.ts +58 -0
  77. package/src/terminal/tui/application.ts +10 -4
  78. package/src/terminal/tui/clipboardFiles.test.ts +94 -0
  79. package/src/terminal/tui/clipboardFiles.ts +86 -0
  80. package/src/terminal/tui/piAdapter.ts +7 -4
  81. package/src/terminal/tui/runtime.ts +2 -0
  82. package/src/tools/definitions.ts +49 -132
  83. package/src/tools/dispatch.ts +78 -0
  84. package/src/tools/harnessTools.ts +23 -0
  85. package/src/tools/spawnSubagent.ts +3 -3
  86. package/src/tools/types.ts +1 -1
  87. package/src/tree/components.ts +221 -0
  88. package/src/tree/materialise.ts +122 -0
  89. package/src/tree/seed.ts +123 -0
  90. package/src/tree/store.ts +193 -0
  91. package/src/tree/surface.ts +135 -0
  92. package/src/tree/tree.test.ts +126 -0
  93. package/src/tree/tree.ts +346 -0
  94. package/src/tree/trust.ts +86 -0
  95. package/src/wiki/notes.ts +313 -0
  96. package/src/memory/api.test.ts +0 -82
  97. package/src/memory/api.ts +0 -303
  98. package/src/memory/blocks.test.ts +0 -78
  99. package/src/memory/blocks.ts +0 -408
  100. package/src/memory/caller.ts +0 -69
  101. package/src/memory/curation.test.ts +0 -206
  102. package/src/memory/curation.ts +0 -64
  103. package/src/memory/dispatch.ts +0 -64
  104. package/src/memory/facts.test.ts +0 -41
  105. package/src/memory/facts.ts +0 -248
  106. package/src/memory/graph.ts +0 -103
  107. package/src/memory/health.test.ts +0 -130
  108. package/src/memory/health.ts +0 -74
  109. package/src/memory/maintainer.ts +0 -272
  110. package/src/memory/maintenance.test.ts +0 -192
  111. package/src/memory/maintenance.ts +0 -679
  112. package/src/memory/migrate.ts +0 -79
  113. package/src/memory/operations.ts +0 -150
  114. package/src/memory/proposals.test.ts +0 -168
  115. package/src/memory/proposals.ts +0 -584
  116. package/src/memory/references.ts +0 -77
  117. package/src/memory/runContext.ts +0 -93
  118. package/src/memory/store.test.ts +0 -66
  119. package/src/memory/store.ts +0 -385
  120. package/src/memory/wiki.test.ts +0 -47
  121. package/src/memory/wiki.ts +0 -423
  122. package/src/memory/wikiIndex.test.ts +0 -88
  123. package/src/memory/wikiIndex.ts +0 -117
  124. package/src/plugins/proposal.ts +0 -121
  125. package/src/skills/registry.test.ts +0 -104
  126. package/src/skills/registry.ts +0 -413
  127. package/src/tools/maintenance.ts +0 -29
  128. package/src/tools/memoryTools.ts +0 -22
  129. package/src/tools/pluginPropose.ts +0 -41
  130. package/src/tools/registryWrite.test.ts +0 -101
  131. package/src/tools/registryWrite.ts +0 -182
  132. /package/src/{memory → core}/secrets.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 3.0.0 - 2026-10-19
6
+
7
+ Rebuilt on recursive harnessing (Harness², Apache-2.0, Google LLC). Breaking.
8
+
9
+ - Add harness trees (`src/tree/`): each caller scope has a versioned tree of eight components — system prompt, guardrails, memory, tool guidance, subagents, skills, scripts and plugins — that is validated, content-addressed, and pinned for a whole run. `SessionRunInput.harness` and `TerminalPrepareInput.harness` choose one; run records carry `harnessScope` and `harnessVersion`. Plugin code in a tree loads only after it is trusted (`TreeTrust`).
10
+ - Add refinement (`src/refine/`): Propose–Probe–Compose in parallel and sequential modes with the R=4k/P=3k budget identity, blind answer-free selection, reflection into a per-scope experience library, and adoption of the chosen tree. Executions and improver sessions are ordinary recorded runs, marked by the `probe` and `improver` triggers. `harness.refine`, `refine.*` and `library.*` RPC methods, and `xingular-harness refine demo|run`.
11
+ - Add the seventh extension point, `RefineHost`: where an execution works, as whom, with which tools, and what it produced.
12
+ - `spawn_subagent` takes `agent`, naming one of the tree's subagents; that child works from its own definition.
13
+ - Replace the Wiki with project notes (`src/wiki/`): linked Markdown under `wiki/`, versions, search, and `wiki_search`, `wiki_read`, `wiki_list` and a switchable `wiki_write`. An earlier Wiki's memory blocks, facts, revisions and Inbox are moved once to `legacy/wiki-<time>/`; nothing is deleted.
14
+ - Remove memory blocks, facts, proposals and the evidence gate, maintenance and the maintainer, curation, context profiles, the skills/rules/prompts registry as a source of prompt text, `registry_write`, `plugin_write` and `plugin_propose`. `harnesses.seed` builds a caller's first tree from what shaped it before (instructions, its rules, its memory blocks, its skills). `registry/` stays as a component library the Hub installs into and a tree can take items from.
15
+ - Hook events are `wiki.page.saved` and `history.run.ended`.
16
+
5
17
  ## 2.1.2 - 2026-10-19
6
18
 
7
19
  - Add `/log`, a full-screen snapshot of redacted Harness diagnostics and current-conversation run events.
package/NOTICE.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Third-party notices
2
2
 
3
+ ## Harness²
4
+
5
+ The harness tree (`src/tree/`) and refinement (`src/refine/`) port the method of Harness²:
6
+ Recursive Agent Harnessing for an Open World (Xu, Chen, CuiZhu, Dalvi Mishra, Ming, Yu, Han,
7
+ Lee, Pfister; arXiv:2610.14224). The component surface and its validation, Propose–Probe–Compose
8
+ in parallel and sequential modes with its budget identity, blind answer-free selection, the
9
+ reflection record and the experience library, and the improver, selector and reflector prompts
10
+ are adapted from its reference implementation (`harness2/core`, `harness2/substrate`) for Pi.
11
+
12
+ Upstream: https://github.com/google-research/harness2 (Copyright 2026 Google LLC)
13
+
14
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use these files
15
+ except in compliance with the License. You may obtain a copy of the License at
16
+ https://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or agreed to in
17
+ writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
18
+ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Changes from upstream: ported
19
+ from Python to TypeScript; the OpenCode and Codex surfaces replaced by one Pi surface; executors
20
+ and improvers run as recorded harness sessions; benchmark adapters replaced by a host-supplied
21
+ `RefineHost`; prompt text that named a framework rewritten for Pi.
22
+
23
+ ## Oh My Pi
24
+
3
25
  The Harness terminal presentation adapts the titanium color palette, five-row Pi logo,
4
26
  diagonal gradient and related terminal presentation conventions from Oh My Pi 18.11.3,
5
27
  particularly `@oh-my-pi/pi-tui/src/theme/defaults/titanium.json` and
package/README.md CHANGED
@@ -1,22 +1,38 @@
1
1
  # Xingular Harness
2
2
 
3
- A Pi agent harness, as one TypeScript package (`@xingular/harness`). It is everything a model
4
- needs to work for someone over time, and nothing about any particular application:
3
+ A Pi agent harness built on **recursive harnessing** ([Harness²](https://arxiv.org/abs/2610.14224),
4
+ Apache-2.0, Google LLC), as one TypeScript package (`@xingular/harness`). The harness — what a
5
+ model is told and can do — is the object that improves, with model weights fixed:
6
+
7
+ - **A harness is a tree of eight components** (c1–c8): system prompt, guardrails, memory and tool
8
+ guidance (always in the prompt, capped), subagents, skills and scripts (on demand), and plugins
9
+ (in the tool loop). Each caller scope has versioned, validated trees; a run pins one version.
10
+ - **Task-level recursion** refines a tree on one task through *Propose–Probe–Compose*: k base
11
+ executions, improvers that edit the tree from the evidence (INV: how the agent works; DOM: what a
12
+ practitioner knows), a probe execution of each candidate, and compositions built from the
13
+ behavioural contrasts. Parallel mode explores wider; sequential mode refines deeper. Each costs
14
+ 4k executions and 3k improver sessions.
15
+ - **Blind, answer-free selection** picks one final output from anonymised candidates; no rubric,
16
+ score or reviewer verdict ever reaches an improver.
17
+ - **Harnessing-level recursion** keeps an experience library per scope: each adopted tree with
18
+ what each edit did and one evidence-backed lesson, read by the next task's improvers.
5
19
 
6
20
  | Part | Folder | What it does |
7
21
  |---|---|---|
22
+ | Harness trees | `src/tree/` | The eight-component surface, validation and repair, content-addressed versions and lineage, materialising a tree for Pi, plugin-code trust, seeding a first tree, the component library. |
23
+ | Refinement | `src/refine/` | Evidence folders, the prompt pack, parallel and sequential recursion, the budget ledger, selection, reflection, the experience library, Pi-backed executor and improver, and the `refine` service. |
8
24
  | Accounts | `src/accounts/` | Several isolated Pi accounts and pools, sign-in, model lists, health and limits. A session keeps the account it started with. |
9
- | Sessions | `src/sessions/` | Pi SDK turns, run records and `events.jsonl`, interrupt, approvals, questions, recovery after a crash. |
10
- | Prompt | `src/prompt/` | The system prompt compiled from sections with budgets and profiles; a stable prefix, and changing state delivered as updates in native history. |
11
- | Memory | `src/memory/` | The Wiki: pages, facts, memory blocks, revisions, proposals with an evidence gate, undo, an Inbox, history recall, run trajectory inspection, and sleep-time consolidation. |
12
- | Skills | `src/skills/` | Skills, prompts, and rules: a person's own in the data root, and built-in ones shipped with the harness or the application. |
25
+ | Sessions | `src/sessions/` | Pi SDK turns on a pinned harness tree, run records and `events.jsonl`, interrupt, approvals, questions, subagents (named by a tree's c5), recovery after a crash. |
26
+ | Prompt | `src/prompt/` | The system prompt compiled from the tree's sections and the application's, with budgets; a stable prefix, and changing state delivered as updates in native history. |
27
+ | Wiki | `src/wiki/` | Project notes: linked Markdown, versions, search. Reference material, not instructions. |
28
+ | History | `src/history/` | Recall over earlier runs and bounded trajectory reads. |
13
29
  | Plugins | `src/plugins/` | What a Pi session loads, chosen by the harness and never by Pi's own discovery; trust for a working folder's code; the list of every plugin and what reaches one caller. |
14
- | Tools | `src/tools/` | Tool definitions, the memory tools, `ask_user`; a gate that asks the application's policy, then standing approvals, then the person. |
30
+ | Tools | `src/tools/` | Tool definitions, History/Wiki/skill tools, `ask_user`; a gate that asks the application's policy, then standing approvals, then the person. |
15
31
  | Connected apps | `src/mcp/` | MCP connections, OAuth, per-session grants, redaction, a trace of what each call returned. |
16
- | Terminal | `src/terminal/` | A Harness-owned terminal frontend over persistent Pi sessions, isolated accounts, compiled instructions, the tool gate and telemetry bridge, native history, plugin UI, `/plugins`, `/hub`, `/accounts`, and the existing session socket. |
32
+ | Terminal | `src/terminal/` | A Harness-owned terminal frontend over persistent Pi sessions on a harness tree. |
17
33
  | Server | `src/server/` | The same API over newline-delimited JSON, for a host that is not a Node program. |
18
34
 
19
- It was split out of Xingular Agent, which is now an application built on it.
35
+ Try refinement with no model and no credentials: `npm run build && node dist/cli.js refine demo --k 2`.
20
36
  The [documentation index](docs/README.md) links current terminal architecture and decisions.
21
37
 
22
38
  ### Session options for applications
@@ -26,8 +42,9 @@ The [documentation index](docs/README.md) links current terminal architecture an
26
42
  - The model's `spawn_subagent` returns immediately by default; `wait: true` returns an inline result. `wait_subagents` joins selected children. The SDK and standalone terminal share this execution service. Terminal calls use its private control channel, including when connected apps are disabled.
27
43
  - Parents receive results at native turn boundaries and join outstanding children before completing. Typed native-history receipts prevent duplicate automatic delivery; explicit waits can reread results. Ownership is recorded before startup so an explicit resume can recover even a lost spawn return. Startup reservations without a run become interrupted outcomes. A restarted Harness never restarts model work automatically. Recovery requires the same recorded account, caller, working folder, and selected history branch. Session IDs are opaque; consumers follow `parentRunId` and `relation`.
28
44
  - `providers: false` runs a session with the harness's own tools only.
29
- - On the caller, `vaultAccess: 'propose'` writes no memory directly, and `recallExcludeAgents` hides those agents' conversations from history and trajectory tools.
30
- - `maintenanceRunTrigger: false` (a harness option) leaves memory to explicit proposals and scheduled merges.
45
+ - `harness: { scope }` runs the session on that scope's head tree (or `{ scope, version }`, or `{ dir }` for a tree on disk). The version is pinned for the run and recorded on it.
46
+ - On the caller, `recallExcludeAgents` hides those agents' conversations from history and trajectory tools.
47
+ - `harnessTools: false` runs a session without the History, Wiki and skill tools.
31
48
 
32
49
  Every session also gets `trajectory_search` and `trajectory_read` from the built-in History plugin.
33
50
  Search lists runs in the current data root, including active runs, with filters and a continuation
@@ -44,16 +61,19 @@ They report recorded evidence without scoring runs, and do not backfill older re
44
61
  import { createHarness } from '@xingular/harness'
45
62
 
46
63
  const harness = createHarness({
47
- dataRoot: '/path/to/data', // knowledge and history: wiki/, registry/, runs/, index.sqlite
64
+ dataRoot: '/path/to/data', // harnesses/, library/, refine/, wiki/, registry/, runs/, index.sqlite
48
65
  stateDir: '/path/to/state', // device-local: accounts, approvals, connections, sockets
49
66
  productName: 'My App', // how the harness names itself to a model (default 'Xingular Harness')
50
67
  secrets, // SecretStore; defaults to an owner-only file in stateDir
51
68
  policy, // ToolPolicy: what a run may do, and what needs a person
52
69
  directory, // names for the ids the application uses
53
70
  builtins: ['/path/to/builtin'], // folders of built-in skills, prompts, and rules
54
- plugins: [myPlugin] // the application's own parts, described as plugins
71
+ plugins: [myPlugin], // the application's own parts, described as plugins
72
+ refineHost // where refinement executions work, as whom, with which tools
55
73
  })
56
74
 
75
+ harness.refine.start({ task: { id, scope: 'agent-1', prompt }, k: 1, mode: 'parallel' })
76
+
57
77
  harness.sessions.provide((session) => myTools(session)) // the application's own tools
58
78
  harness.runs.listen((event, run) => show(event)) // every run event, after it is saved
59
79
 
@@ -61,6 +81,7 @@ await harness.sessions.run({
61
81
  run: { id, sessionId },
62
82
  cwd, sessionDir, text,
63
83
  caller: { agentId, agentName, actor: 'Chat' },
84
+ harness: { scope: 'agent-1' },
64
85
  launch: { sections: [{ id: 'identity', title: 'Identity', body, budget: 2000, order: 10 }] },
65
86
  tools: { allow: ['read', 'bash', 'my_tool'], gated: ['bash'] }
66
87
  })
@@ -68,14 +89,14 @@ await harness.sessions.run({
68
89
 
69
90
  ## How an application extends it
70
91
 
71
- The harness knows a caller (an opaque id that owns memory), never an agent, a group, or a task.
72
- An application adds what it knows through six points:
92
+ The harness knows a caller and a harness scope (opaque ids), never an agent, a group, or a task.
93
+ An application adds what it knows through seven points:
73
94
 
74
95
  1. **Prompt sections** (`Launch.sections`, `Launch.toolGroups`, `Launch.references`). Each
75
- section has an `order` and may be `dynamic`. The harness adds its own (`blocks` 30, `rules` 40,
76
- `references` 50, `skills` 60, `knowledge` 80, `tools` 90), applies budgets and the caller's
77
- context profile, keeps stable sections in the system prompt, and sends dynamic ones as
78
- updates.
96
+ section has an `order` and may be `dynamic`. The harness adds its own (`system` 25,
97
+ `guardrails` 40, `memory` 45, `references` 50, `subagents` 64, `scripts` 66, `wiki` 80,
98
+ `tools` 90), applies budgets, keeps stable sections in the system prompt, and sends dynamic
99
+ ones as updates.
79
100
  2. **Tool providers** (`harness.sessions.provide`). A provider returns `ToolSpec`s for a session;
80
101
  only the names in the session's `allow` list are registered, in that order.
81
102
  A tool may return `attachments` as `{ id, name, mimeType }` references. The harness records
@@ -84,9 +105,6 @@ An application adds what it knows through six points:
84
105
  The harness provides the web tools itself: `webTools({ secrets })` gives `web_search` (Brave Search,
85
106
  key read from the secret store) and `web_fetch` (checked reads of public pages). An application
86
107
  passes it to `harness.sessions.provide` and switches the names on for each agent.
87
- `registryTools({ harness })` gives `registry_write` (a skill, rule, or prompt) and `plugin_write`
88
- (a plugin). Each writes for the calling agent only: the item is on for that agent, and a plugin's
89
- code is trusted once written. An item others already use goes to the Inbox instead.
90
108
  3. **`ToolPolicy`**. `scope` says whether a call is inside what the run may do (or needs one
91
109
  approval). A decision with `humanOnly` is for a person alone: the always-approve switch and
92
110
  remembered answers do not apply to it. `authorize` says whether the tool is still switched on;
@@ -99,6 +117,11 @@ An application adds what it knows through six points:
99
117
  the application and says which tools, prompt sections and tool groups it provides. It is data:
100
118
  it changes what `plugins.list` and `plugins.inventory` report, never what runs. `WEB_PLUGIN`
101
119
  describes the web tools. A host that is not a Node program sends them with `plugins.describe`.
120
+ 7. **`RefineHost`** (`HarnessOptions.refineHost`). Where a refinement execution works
121
+ (`prepareWorkspace`: an isolated folder, such as a git worktree), as whom and with which tools
122
+ (`session`), and what it produced (`deliverable`). Executions run as unattended runs with
123
+ trigger `probe`, so a `ToolPolicy` can refuse anything with effects outside that folder;
124
+ improver sessions run with trigger `improver`, file tools only, on a copy of the evidence.
102
125
 
103
126
  `apps.expose(...)` additionally offers the application's tools through the connected-apps
104
127
  broker (`mcp_list_tools`, `mcp_call_tool`), which is how a terminal session reaches them.
@@ -107,7 +130,7 @@ broker (`mcp_list_tools`, `mcp_call_tool`), which is how a terminal session reac
107
130
 
108
131
  A plugin is a bundle with a title, a description and contributions: instructions, skills,
109
132
  commands, tools, connections, code (a Pi extension) and themes. A Pi package is a plugin as it
110
- is; so are the harness's own parts (Memory, Wiki, History, Ask the user, Connected apps, Pi), the
133
+ is; so are the harness's own parts (Harness, Wiki, History, Subagents, Ask the user, Connected apps, Pi), the
111
134
  application's, a person's registry ("Yours"), the folder every account shares, and what a
112
135
  working folder brings.
113
136
 
@@ -141,11 +164,10 @@ working folder brings.
141
164
  input does so before the gate sees it. Every resource reload revalidates the parent's original
142
165
  trusted selection; changed or revoked code requires review and a fresh terminal.
143
166
  - **A required part can be extended.** A package names the part it adds to and, optionally, a
144
- hooks file: `"harness": { "extends": ["memory"], "hooks": "./hooks.mjs" }`. The harness runs
145
- hooks itself (`src/plugins/hooks.ts`), in its own process, because most memory is written while
146
- no session is open. `export default function (harness) { harness.on('memory.saved', async
147
- (event, ctx) => …) }`; the events are `memory.saved`, `memory.block.changed`,
148
- `wiki.page.saved` and `history.run.ended`. A hook is told after the write and cannot stop it,
167
+ hooks file: `"harness": { "extends": ["wiki"], "hooks": "./hooks.mjs" }`. The harness runs
168
+ hooks itself (`src/plugins/hooks.ts`), in its own process, because notes are often written while
169
+ no session is open. `export default function (harness) { harness.on('wiki.page.saved', async
170
+ (event, ctx) => …) }`; the events are `wiki.page.saved` and `history.run.ended`. A hook is told after the write and cannot stop it,
149
171
  has 30 seconds, and what it throws is kept in `plugin-hooks.json` and shown on its plugin. It
150
172
  runs only while its plugin is switched on for everyone and trusted; what is loaded is checked
151
173
  against that before each delivery. `ctx.call(connection, tool, args)` reaches a connected app
@@ -172,7 +194,8 @@ working folder brings.
172
194
  Outside a session, `xingular-harness plugins list | show | install | remove | update | attach |
173
195
  detach | trust | untrust` acts directly, as the person who typed it; `trust` shows the files
174
196
  and wants a typed yes or `--yes`. It does not open the data root, so it settles no run.
175
- - **Unattended runs and memory maintenance load no extension**, as before.
197
+ - **Unattended runs load no extension found on disk.** A harness tree's own trusted plugins still
198
+ load, so a refinement probe runs the plugin it is testing.
176
199
  - **A person switches things on and off for a scope.** `plugins.attach` and `plugins.detach`
177
200
  take a plugin's or a contribution's `id` and a `scope` (`{}` for everywhere, `{ agentId }`, or
178
201
  `{ projectId }`). The narrowest scope that says something wins: an agent, then a project, then
@@ -216,7 +239,8 @@ table. With the `--host-*` flags the harness calls the host for `secrets.get|set
216
239
  `policy.scope|authorize|approval|connections`, and `tools.call`; the host registers its tools
217
240
  with `tools.register` and its names with `directory.set`.
218
241
 
219
- `skills.import` accepts complete user-owned skill folders:
242
+ `harnesses.importComponents` adds complete skill folders, or single-file rules and prompts, to the
243
+ component library:
220
244
 
221
245
  ```ts
222
246
  { skills: [{ name, files: [{ path, content, encoding }] }] }
@@ -227,7 +251,8 @@ It validates bounded relative paths and file encodings, requires a root
227
251
  has no knowledge of the application feature that may call it.
228
252
 
229
253
  `npm run prove` starts that server on a throwaway data root, with no application present, and
230
- exercises accounts, memory, skills, the prompt, connected apps, and a recorded session.
254
+ exercises accounts, harness trees, the Wiki, the prompt, connected apps, a recorded session, a
255
+ plugin hook, and the refinement demo end to end.
231
256
 
232
257
  ## Run it as a standalone Harness terminal
233
258
 
@@ -309,19 +334,25 @@ command. The explicit `terminal` command is an alias for the default launch. Use
309
334
 
310
335
  ```
311
336
  <data root>/
312
- wiki/ home.md, library/, projects/<slug>/, facts/, blocks/, revisions, inbox, log
313
- registry/ skills/, prompts/, rules/ (a person's own; never copied)
337
+ harnesses/<scope>/ versions/<fingerprint>/tree/, head.json, lineage.jsonl (the eight components)
338
+ refine/<id>/ summary.json, task.json, harnesses/<label>/, rollouts/, context/, selection/, reflection/, improver/
339
+ library/<scope>/<area>/ INDEX.md, harnesses/<task>/{harness/, EXPERIENCE.md} (the experience library)
340
+ wiki/ home.md, library/, projects/<slug>/ (project notes)
341
+ wiki-history/ earlier versions of notes
342
+ legacy/ what an earlier Wiki kept (memory blocks, facts, revisions, Inbox), moved once
343
+ registry/ skills/, prompts/, rules/ (the component library; the Hub installs here)
314
344
  plugins/<name>/ packages kept with a person's data; each is found as an installed plugin
315
345
  runs/<id>/ run.json, events.jsonl, context.json, caller.json, subagents.json (reserved child IDs)
316
- config/ context profiles, what is switched on for whom (plugin-attachments.json),
346
+ config/ what is switched on for whom (plugin-attachments.json),
317
347
  settings the harness reads
318
- index.sqlite a rebuildable index of Wiki entries and runs (FTS5)
348
+ index.sqlite a rebuildable index of runs for recall (FTS5)
319
349
  projects.json read only: the application owns it
320
350
 
321
351
  <state dir>/
322
352
  accounts/ registry, per-account Pi agent folders, audit log
323
353
  approvals.json standing approvals
324
354
  plugin-trust.json the code a person trusted, by hash, and whether earlier packages were taken over
355
+ tree-plugin-trust.json harness-tree plugin code a person trusted, and scopes whose probes may run improver code
325
356
  plugin-registered.json what each extension registered the last time a session loaded it
326
357
  plugin-hooks.json what each hooks file listens for and how its last run went
327
358
  connections.json connected apps (secrets are in the SecretStore)
@@ -343,7 +374,7 @@ Node 22.19 or newer.
343
374
 
344
375
  ## Images
345
376
 
346
- `SessionRunInput.requiresImageInput` optionally requires a vision-capable resolved Pi model before a prompt is delivered. The check includes direct `images` input, and the generic tool wrapper rejects image results on text-only models. Direct prompt images use Pi's `{ type: 'image', data, mimeType }` content shape. Applications own file formats, attachment selection, extraction and image preparation; the Harness only transports typed image content and validates model capability.
377
+ `SessionRunInput.requiresImageInput` optionally requires a vision-capable resolved Pi model before a prompt is delivered. The check includes direct `images` input, and the generic tool wrapper rejects image results on text-only models. Direct prompt images use Pi's `{ type: 'image', data, mimeType }` content shape. Applications own attachment selection, extraction and image preparation; the Harness transports typed image content and validates model capability. In the standalone terminal, pasting Finder-copied HEIC/HEIF files on macOS converts them to temporary PNGs so Pi can read their pixels. See [the terminal guide](docs/terminal-tui.md#clipboard-image-paste).
347
378
 
348
379
  ## Curated Hub
349
380