@visual-z/xeno 0.8.3 → 0.9.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 (348) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +31 -746
  3. package/bin/xeno.exe +26 -0
  4. package/install.cjs +88 -0
  5. package/package.json +18 -48
  6. package/docs/app-server.md +0 -115
  7. package/docs/foundations.md +0 -88
  8. package/docs/install.md +0 -244
  9. package/docs/providers.md +0 -172
  10. package/docs/research/foundation-clients-2026-10-09.md +0 -27
  11. package/docs/research/foundation-editing-2026-10-09.md +0 -56
  12. package/docs/research/foundation-network-2026-10-09.md +0 -37
  13. package/docs/research/foundation-workflow-2026-10-09.md +0 -37
  14. package/src/apps/acp-server.ts +0 -41
  15. package/src/apps/agent-profiles.ts +0 -19
  16. package/src/apps/app-server.ts +0 -30
  17. package/src/apps/approve.ts +0 -49
  18. package/src/apps/cli.ts +0 -99
  19. package/src/apps/commands.ts +0 -319
  20. package/src/apps/completions.ts +0 -87
  21. package/src/apps/control-transport.ts +0 -90
  22. package/src/apps/export-cli.ts +0 -24
  23. package/src/apps/goal-flow.ts +0 -70
  24. package/src/apps/image-draft.ts +0 -46
  25. package/src/apps/input.ts +0 -312
  26. package/src/apps/model-catalog.ts +0 -69
  27. package/src/apps/preferences.ts +0 -20
  28. package/src/apps/project-trust.ts +0 -9
  29. package/src/apps/provider-connect.ts +0 -346
  30. package/src/apps/question-ui.ts +0 -27
  31. package/src/apps/render.ts +0 -181
  32. package/src/apps/resources.ts +0 -66
  33. package/src/apps/review.ts +0 -109
  34. package/src/apps/session-hub.ts +0 -96
  35. package/src/apps/session-lifecycle.ts +0 -64
  36. package/src/apps/shell.ts +0 -2066
  37. package/src/apps/startup-input.ts +0 -135
  38. package/src/apps/startup.ts +0 -1677
  39. package/src/apps/ui/app.ts +0 -1713
  40. package/src/apps/ui/control-model.ts +0 -43
  41. package/src/apps/ui/extension-host.ts +0 -194
  42. package/src/apps/ui/image-cache.ts +0 -121
  43. package/src/apps/ui/palette.ts +0 -88
  44. package/src/apps/ui/project.ts +0 -127
  45. package/src/apps/ui/standalone.ts +0 -148
  46. package/src/apps/ui/status-model.ts +0 -68
  47. package/src/apps/ui/surface.ts +0 -91
  48. package/src/apps/ui/theme.ts +0 -86
  49. package/src/apps/update-check.ts +0 -112
  50. package/src/apps/workflow.ts +0 -58
  51. package/src/core/acceptance.ts +0 -139
  52. package/src/core/action-defaults.ts +0 -58
  53. package/src/core/activity-status.ts +0 -52
  54. package/src/core/agent-profile.ts +0 -130
  55. package/src/core/attachment-input.ts +0 -17
  56. package/src/core/blind-checks.ts +0 -72
  57. package/src/core/boundary.ts +0 -174
  58. package/src/core/branch-receipt.ts +0 -26
  59. package/src/core/catalog-merge.ts +0 -19
  60. package/src/core/checkpoints.ts +0 -85
  61. package/src/core/churn.ts +0 -61
  62. package/src/core/command-artifacts.ts +0 -94
  63. package/src/core/command-contract.ts +0 -151
  64. package/src/core/completion-action.ts +0 -20
  65. package/src/core/completion-review.ts +0 -98
  66. package/src/core/context-detail.ts +0 -37
  67. package/src/core/context-policy.ts +0 -133
  68. package/src/core/context-window.ts +0 -54
  69. package/src/core/continuation.ts +0 -130
  70. package/src/core/control-protocol.ts +0 -69
  71. package/src/core/control-view.ts +0 -39
  72. package/src/core/cycle.ts +0 -17
  73. package/src/core/data-query.ts +0 -201
  74. package/src/core/deadline.ts +0 -40
  75. package/src/core/derive.ts +0 -516
  76. package/src/core/draft-images.ts +0 -56
  77. package/src/core/edit-plan.ts +0 -200
  78. package/src/core/environment.ts +0 -181
  79. package/src/core/event-validation.ts +0 -220
  80. package/src/core/events.ts +0 -670
  81. package/src/core/evidence-ladder.ts +0 -62
  82. package/src/core/evidence-links.ts +0 -68
  83. package/src/core/evidence.ts +0 -240
  84. package/src/core/execution.ts +0 -18
  85. package/src/core/exhaustive.ts +0 -18
  86. package/src/core/export.ts +0 -179
  87. package/src/core/extension-flags.ts +0 -14
  88. package/src/core/external-effects.ts +0 -488
  89. package/src/core/failure-recovery.ts +0 -173
  90. package/src/core/file-precondition.ts +0 -78
  91. package/src/core/file-references.ts +0 -35
  92. package/src/core/frontmatter.ts +0 -213
  93. package/src/core/git-status.ts +0 -29
  94. package/src/core/goal-view.ts +0 -64
  95. package/src/core/goal.ts +0 -200
  96. package/src/core/handoff.ts +0 -479
  97. package/src/core/history-query.ts +0 -139
  98. package/src/core/history.ts +0 -237
  99. package/src/core/image-limits.ts +0 -72
  100. package/src/core/images.ts +0 -46
  101. package/src/core/integration-health.ts +0 -34
  102. package/src/core/json-event.ts +0 -131
  103. package/src/core/json-pointer.ts +0 -46
  104. package/src/core/keymap.ts +0 -153
  105. package/src/core/lsp-framing.ts +0 -34
  106. package/src/core/mcp-config.ts +0 -68
  107. package/src/core/model-picker.ts +0 -64
  108. package/src/core/model-preferences.ts +0 -28
  109. package/src/core/model-replay.ts +0 -22
  110. package/src/core/model-scope.ts +0 -53
  111. package/src/core/note-guidance.ts +0 -34
  112. package/src/core/oauth-fields.ts +0 -44
  113. package/src/core/observation-view.ts +0 -152
  114. package/src/core/outcome.ts +0 -44
  115. package/src/core/overflow.ts +0 -59
  116. package/src/core/packages.ts +0 -47
  117. package/src/core/patch.ts +0 -130
  118. package/src/core/path-suggestions.ts +0 -59
  119. package/src/core/permissions.ts +0 -410
  120. package/src/core/process-receipt.ts +0 -105
  121. package/src/core/process-state.ts +0 -37
  122. package/src/core/program-status.ts +0 -40
  123. package/src/core/progress.ts +0 -150
  124. package/src/core/project.ts +0 -431
  125. package/src/core/prompt-policy.ts +0 -46
  126. package/src/core/prompts.ts +0 -111
  127. package/src/core/question.ts +0 -94
  128. package/src/core/queue.ts +0 -78
  129. package/src/core/read-bounds.ts +0 -24
  130. package/src/core/read-observation.ts +0 -106
  131. package/src/core/recovery-sources.ts +0 -74
  132. package/src/core/regex-dialect.ts +0 -25
  133. package/src/core/request-budget.ts +0 -23
  134. package/src/core/request-progress.ts +0 -87
  135. package/src/core/request-state.ts +0 -273
  136. package/src/core/resource-selection.ts +0 -36
  137. package/src/core/response-recovery.ts +0 -59
  138. package/src/core/resume.ts +0 -59
  139. package/src/core/review.ts +0 -68
  140. package/src/core/ripgrep-release.ts +0 -64
  141. package/src/core/runtime-target.ts +0 -94
  142. package/src/core/scheduling.ts +0 -8
  143. package/src/core/search-observation.ts +0 -97
  144. package/src/core/secrets.ts +0 -188
  145. package/src/core/session-archive.ts +0 -4
  146. package/src/core/session-browser.ts +0 -82
  147. package/src/core/session-entry.ts +0 -61
  148. package/src/core/session-exit.ts +0 -42
  149. package/src/core/session-format.ts +0 -169
  150. package/src/core/session-position.ts +0 -26
  151. package/src/core/session-tree.ts +0 -147
  152. package/src/core/settings.ts +0 -192
  153. package/src/core/skills.ts +0 -165
  154. package/src/core/sql-query.ts +0 -211
  155. package/src/core/stall.ts +0 -128
  156. package/src/core/stop-report.ts +0 -68
  157. package/src/core/text-normalize.ts +0 -81
  158. package/src/core/theme.ts +0 -166
  159. package/src/core/thinking.ts +0 -26
  160. package/src/core/tokens.ts +0 -151
  161. package/src/core/tool-contract.ts +0 -153
  162. package/src/core/tool-discovery.ts +0 -87
  163. package/src/core/tool-failure.ts +0 -81
  164. package/src/core/tool-input.ts +0 -44
  165. package/src/core/transcript.ts +0 -108
  166. package/src/core/tui-mode.ts +0 -29
  167. package/src/core/update-check.ts +0 -157
  168. package/src/core/version.ts +0 -55
  169. package/src/core/web-content.ts +0 -80
  170. package/src/core/work-state.ts +0 -154
  171. package/src/core/workflow-mode.ts +0 -34
  172. package/src/core/working-set.ts +0 -119
  173. package/src/core/yaml.ts +0 -282
  174. package/src/runtime/acp-agent.ts +0 -289
  175. package/src/runtime/agent-profiles.ts +0 -21
  176. package/src/runtime/auth.ts +0 -367
  177. package/src/runtime/blind-check.ts +0 -36
  178. package/src/runtime/branch-jobs.ts +0 -36
  179. package/src/runtime/catalog.ts +0 -285
  180. package/src/runtime/clipboard.ts +0 -125
  181. package/src/runtime/command-artifacts.ts +0 -64
  182. package/src/runtime/connection-reuse.ts +0 -40
  183. package/src/runtime/control-client.ts +0 -149
  184. package/src/runtime/control-connection.ts +0 -139
  185. package/src/runtime/counter-check.ts +0 -74
  186. package/src/runtime/environment-tools.ts +0 -60
  187. package/src/runtime/evidence-notes.ts +0 -35
  188. package/src/runtime/exec-sessions.ts +0 -456
  189. package/src/runtime/execution-control.ts +0 -40
  190. package/src/runtime/extension-loader.ts +0 -37
  191. package/src/runtime/extension-ui.ts +0 -47
  192. package/src/runtime/extensions.ts +0 -370
  193. package/src/runtime/formatter-tool.ts +0 -38
  194. package/src/runtime/formatter.ts +0 -50
  195. package/src/runtime/foundation.ts +0 -116
  196. package/src/runtime/history-cache.ts +0 -57
  197. package/src/runtime/history-tools.ts +0 -168
  198. package/src/runtime/images.ts +0 -80
  199. package/src/runtime/integrations.ts +0 -216
  200. package/src/runtime/loop.ts +0 -3001
  201. package/src/runtime/lsp-client.ts +0 -201
  202. package/src/runtime/mcp-client.ts +0 -264
  203. package/src/runtime/mcp-oauth.ts +0 -168
  204. package/src/runtime/mcp-schema.ts +0 -51
  205. package/src/runtime/model-config.ts +0 -232
  206. package/src/runtime/model-data.LICENSE +0 -27
  207. package/src/runtime/model-data.ts +0 -21
  208. package/src/runtime/model-discovery.ts +0 -208
  209. package/src/runtime/model-replay.ts +0 -10
  210. package/src/runtime/model-scope.ts +0 -20
  211. package/src/runtime/model-sources.ts +0 -151
  212. package/src/runtime/model.ts +0 -686
  213. package/src/runtime/models-fetch.ts +0 -57
  214. package/src/runtime/oauth-device.ts +0 -86
  215. package/src/runtime/oauth.ts +0 -853
  216. package/src/runtime/open-image.ts +0 -42
  217. package/src/runtime/openai-responses.ts +0 -304
  218. package/src/runtime/openai.ts +0 -697
  219. package/src/runtime/output-schema.ts +0 -26
  220. package/src/runtime/package-manager.ts +0 -125
  221. package/src/runtime/patch-tool.ts +0 -38
  222. package/src/runtime/permission-resources.ts +0 -18
  223. package/src/runtime/pi-provider.ts +0 -423
  224. package/src/runtime/program-status.ts +0 -38
  225. package/src/runtime/progress.ts +0 -26
  226. package/src/runtime/provider-access.ts +0 -21
  227. package/src/runtime/provider-connect.ts +0 -109
  228. package/src/runtime/provider-presets.ts +0 -98
  229. package/src/runtime/provider-protocols.ts +0 -29
  230. package/src/runtime/provider-request.ts +0 -87
  231. package/src/runtime/provider-tool-policy.ts +0 -33
  232. package/src/runtime/provider.ts +0 -580
  233. package/src/runtime/question-tool.ts +0 -62
  234. package/src/runtime/retry.ts +0 -447
  235. package/src/runtime/review-tool.ts +0 -48
  236. package/src/runtime/rich-text.ts +0 -36
  237. package/src/runtime/runtime-target.ts +0 -149
  238. package/src/runtime/secrets.ts +0 -79
  239. package/src/runtime/self-update.ts +0 -74
  240. package/src/runtime/session-control.ts +0 -265
  241. package/src/runtime/session-hub.ts +0 -85
  242. package/src/runtime/stream-idle.ts +0 -80
  243. package/src/runtime/tool-broker.ts +0 -137
  244. package/src/runtime/tool-discovery.ts +0 -58
  245. package/src/runtime/tool-queue.ts +0 -77
  246. package/src/runtime/tools.ts +0 -1820
  247. package/src/runtime/turn-effects.ts +0 -31
  248. package/src/runtime/update-check.ts +0 -48
  249. package/src/runtime/usage.ts +0 -253
  250. package/src/runtime/version.ts +0 -12
  251. package/src/runtime/web-http.ts +0 -56
  252. package/src/runtime/web-tools.ts +0 -88
  253. package/src/runtime/working-notes.ts +0 -60
  254. package/src/runtime/workspace-lifecycle.ts +0 -141
  255. package/src/store/acceptance.ts +0 -15
  256. package/src/store/agent-profile-files.ts +0 -13
  257. package/src/store/atomic.ts +0 -31
  258. package/src/store/auth-store.ts +0 -50
  259. package/src/store/blind-checks.ts +0 -32
  260. package/src/store/blobs.ts +0 -143
  261. package/src/store/checkpoint-history.ts +0 -32
  262. package/src/store/command-artifacts.ts +0 -96
  263. package/src/store/command.ts +0 -111
  264. package/src/store/config.ts +0 -69
  265. package/src/store/context-files.ts +0 -436
  266. package/src/store/file-checkpoints.ts +0 -108
  267. package/src/store/file-index.ts +0 -174
  268. package/src/store/foundation-config.ts +0 -24
  269. package/src/store/git-checkpoints.ts +0 -67
  270. package/src/store/git-status.ts +0 -15
  271. package/src/store/history-search.ts +0 -19
  272. package/src/store/log.ts +0 -725
  273. package/src/store/lsp-document.ts +0 -30
  274. package/src/store/mcp-credentials.ts +0 -85
  275. package/src/store/models.ts +0 -60
  276. package/src/store/observations.ts +0 -224
  277. package/src/store/packages.ts +0 -98
  278. package/src/store/patch.ts +0 -92
  279. package/src/store/permission-paths.ts +0 -34
  280. package/src/store/process-receipts.ts +0 -34
  281. package/src/store/query-source.ts +0 -49
  282. package/src/store/recovery.ts +0 -44
  283. package/src/store/replay.ts +0 -76
  284. package/src/store/resource-index.ts +0 -170
  285. package/src/store/resources.ts +0 -285
  286. package/src/store/restore.ts +0 -110
  287. package/src/store/review.ts +0 -109
  288. package/src/store/runtime-target.ts +0 -64
  289. package/src/store/search.ts +0 -728
  290. package/src/store/secrets.ts +0 -44
  291. package/src/store/serial.ts +0 -13
  292. package/src/store/session-archive.ts +0 -165
  293. package/src/store/session-browser.ts +0 -68
  294. package/src/store/session-position.ts +0 -27
  295. package/src/store/sessions.ts +0 -525
  296. package/src/store/source-cancellation.ts +0 -6
  297. package/src/store/tool-binaries.ts +0 -90
  298. package/src/store/trust.ts +0 -82
  299. package/src/store/update-cache.ts +0 -36
  300. package/src/store/user-settings.ts +0 -30
  301. package/src/store/workspace-clone.ts +0 -42
  302. package/src/store/workspace-observation.ts +0 -113
  303. package/src/store/workspace.ts +0 -115
  304. package/src/store/worktree.ts +0 -278
  305. package/src/tui/ansi-spans.ts +0 -126
  306. package/src/tui/diff.ts +0 -160
  307. package/src/tui/exhaustive.ts +0 -14
  308. package/src/tui/fuzzy.ts +0 -75
  309. package/src/tui/style.ts +0 -208
  310. package/src/tui/ui/atomic-draft.ts +0 -121
  311. package/src/tui/ui/canvas.ts +0 -96
  312. package/src/tui/ui/colors.ts +0 -70
  313. package/src/tui/ui/composer.ts +0 -200
  314. package/src/tui/ui/control-panel.ts +0 -25
  315. package/src/tui/ui/control-sidebar.ts +0 -49
  316. package/src/tui/ui/dialog.ts +0 -398
  317. package/src/tui/ui/draft.ts +0 -23
  318. package/src/tui/ui/duration.ts +0 -16
  319. package/src/tui/ui/edge.ts +0 -186
  320. package/src/tui/ui/image-size.ts +0 -44
  321. package/src/tui/ui/ink.ts +0 -210
  322. package/src/tui/ui/items.ts +0 -42
  323. package/src/tui/ui/keys.ts +0 -40
  324. package/src/tui/ui/layout.ts +0 -74
  325. package/src/tui/ui/list-model.ts +0 -86
  326. package/src/tui/ui/list-view.ts +0 -172
  327. package/src/tui/ui/mascot.ts +0 -67
  328. package/src/tui/ui/messages.ts +0 -518
  329. package/src/tui/ui/motion.ts +0 -28
  330. package/src/tui/ui/paths.ts +0 -10
  331. package/src/tui/ui/pictures.ts +0 -108
  332. package/src/tui/ui/screen.ts +0 -548
  333. package/src/tui/ui/status.ts +0 -403
  334. package/src/tui/ui/styled.ts +0 -85
  335. package/src/tui/ui/tool-card.ts +0 -150
  336. package/src/tui/width.ts +0 -567
  337. package/src/vendor/pi-rich/LICENSE.upstream +0 -21
  338. package/src/vendor/pi-rich/UPSTREAM.json +0 -17
  339. package/src/vendor/pi-rich/clipboard-command.ts +0 -44
  340. package/src/vendor/pi-rich/exif-orientation.ts +0 -182
  341. package/src/vendor/pi-rich/html.ts +0 -51
  342. package/src/vendor/pi-rich/image-convert.ts +0 -49
  343. package/src/vendor/pi-rich/image-resize-core.ts +0 -164
  344. package/src/vendor/pi-rich/image-resize-worker.ts +0 -42
  345. package/src/vendor/pi-rich/image-resize.ts +0 -123
  346. package/src/vendor/pi-rich/mime.ts +0 -116
  347. package/src/vendor/pi-rich/photon.ts +0 -139
  348. package/src/vendor/pi-rich/syntax-highlight.ts +0 -214
package/README.md CHANGED
@@ -1,769 +1,54 @@
1
1
  # xeno
2
2
 
3
- A segmented append-only agent log with **pure** context and handoff projections.
4
-
5
- The log is the truth. What the model sees is a recomputable projection of it. Nothing
6
- is ever summarized by a model, and nothing is ever rewritten in place.
7
-
8
- ```
9
- .xeno/sessions/<id>/node-0007.jsonl append-only events, references only
10
- |
11
- | deriveHandoff() pure, zero LLM calls
12
- v
13
- .xeno/sessions/<id>/handoff-0007.yaml structured state: verified completions,
14
- | decisions, pitfalls, file digests, gate status
15
- | projectContext() pure
16
- v
17
- messages[] frozen system prefix + handoff + this node's events
18
- ```
19
-
20
- The on-disk session format will still change; `0.x` is that statement, and
21
- `xeno --version` reports the installed release. Published as `@visual-z/xeno`; the license is `UNLICENSED` (readable and installable, no reuse granted).
3
+ A terminal coding agent whose session is a segmented, append-only log. What the
4
+ model sees is a recomputable projection of that log. Nothing is summarized by a
5
+ model, and nothing is rewritten in place. A step counts as done only when a command's exit
6
+ code says so.
22
7
 
23
8
  ## Install
24
9
 
25
- Bun is required. This tree was run on Bun 1.3.10. Node has not been tried.
26
-
27
10
  ```bash
28
- npm i -g @visual-z/xeno # or: bun add -g @visual-z/xeno
11
+ npm i -g @visual-z/xeno
29
12
  xeno --help
30
13
  ```
31
14
 
32
- From a checkout instead:
33
-
34
- ```bash
35
- git clone <this-repo> xeno
36
- cd xeno
37
- bun install
38
- bun src/apps/cli.ts --help
39
- # or: bun link then, anywhere: xeno --help
40
- ```
41
-
42
- Full steps, credential variables, and what `.xeno/` writes: [`docs/install.md`](docs/install.md).
43
-
44
- Validation commands and current evidence are recorded in
45
- [`docs/research/harness-practice-rollout-2026-09-23.md`](docs/research/harness-practice-rollout-2026-09-23.md).
46
-
47
- ## Harness capabilities
48
-
49
- - One live execution per session, with cancellation, draining, and explicit completion/stop/failure outcomes.
50
- - Evidence-backed goals, progress and Context Lens in `/control`, shared with the experimental JSONL app server and optional local control socket. See [`docs/app-server.md`](docs/app-server.md) for identity, events, approval, recovery and OSC 7501 status.
51
- - Stable work IDs with explicit unblock, reopen, and cancel operations. Verified completion still requires fresh executed evidence.
52
- - Shared schema validation and structured tool feedback. Reads return file versions; edits support an expected version and return a diff.
53
- - Writing branches start from the parent's working copy, including uncommitted files, in an isolated Git worktree. Adopt continues that checkout.
54
- - Independent readers and read-only branches run in a bounded window; writes and state changes are barriers. Results remain in request order.
55
- - `note(kind="pin", work_id, event, what)` links original observations; `supersedes` replaces an earlier reference. `history(work_id=...)`, `history(resource=...)`, and `history(events=[...])` locate or batch-read the originals.
56
- - Verified history projections use a bounded per-session cache. Original ancestry and sealed digests are checked before every hit; a lost cache is rebuilt from the log.
57
- - The `foundation` tool profile adds web fetch/search, standard MCP, structured questions, transactional Patch, explicit formatters, diff and configured LSP. Build/Plan roles share the real capability and permission owner; independent code review has its own read-only context. Final JSON can be schema-validated before print output. See [`docs/foundations.md`](docs/foundations.md) for configuration and commands.
58
- - The app server owns multiple sessions with a typed local control client; `xeno acp` also exposes standard ACP through the official SDK. Both route cancellation, approvals and questions through the original Session.
59
-
60
- Use `/new` or `--fresh` to start with the current tool protocol. Existing sessions
61
- keep their saved frozen schemas and concurrency policy. New sessions default to
62
- three concurrent readers; programmatic callers can set `SessionConfig.maxParallelTools`.
63
- This setting is not a CLI flag. Evidence freshness reflects the last logged observation.
64
-
65
- The public-data evaluation protocol, architectural hypotheses, and measured
66
- results are in [`docs/benchmarks.md`](docs/benchmarks.md). The LongBench v2 pilot
67
- compares segmentation, full history, and observation masking with the same model;
68
- its tool-based input protocol is explicitly separate from the official leaderboard.
69
- The follow-up trial compares the enhanced working-state protocol and computation
70
- tools with a control on six previously unused questions. Real process-kill recovery
71
- checks are reported separately from model accuracy.
72
- The explicit-policy follow-up separates segmented, continuous and adaptive context
73
- views. Its budget-limited result and negative cases are recorded in the same report;
74
- neither segmentation nor the experimental adaptive rule has established a quality advantage.
75
- `bun run eval/scripts/compare-harness.ts smoke --output /absolute/new/smoke-directory`
76
- also exercises xeno-windowed, xeno-continuous and an installed Pi CLI with shared
77
- confined tools, without paid model calls. The comparison Pi CLI runs on Node through
78
- an isolated local tool bridge; xeno's providers use the pinned Pi AI runtime described below.
79
- Its `plan` / `run` protocol freezes
80
- source, model, task order and spending policy, including summary calls. An explicitly
81
- authorized `--budget unlimited` on both `plan` and `run` records costs without a local
82
- dollar ceiling; upstream errors stop the trial, with HTTP 402 marked as awaiting top-up.
83
- This checks a controlled configuration, not stock Pi or an official leaderboard.
84
-
85
- The new single-factor protocol separately compares tool profiles, the carried
86
- working set, and strict verification. It runs four isolated scenarios through
87
- real sessions and grades files, fresh command evidence, and pending human review.
88
- Use `bun eval/scripts/eval-harness.ts smoke --output /absolute/new/eval-directory`,
89
- then `bun eval/scripts/eval-harness.ts audit --output /absolute/new/eval-directory`.
90
- Smoke has no paid requests and reports synthetic usage. `plan` and `run` require
91
- the same explicit numeric `--budget`; inputs, source, schemas, model settings,
92
- and paired order are frozen before spending. Started directories cannot be
93
- replayed automatically. Failures and missing trials remain in the denominator,
94
- and unknown charges retain their reservation. Details are in `docs/benchmarks.md`.
95
-
96
- ## Usage
97
-
98
- ```
99
- xeno [-m <model>] [--provider <name>] [--api-key <key>]
100
- [-w <workspace>] [--log <dir>] [--max-turns N]
101
- [--trigger N --hard N] [--list-models [search]] [--fresh]
102
- [-c|--continue] [-r|--resume [id]] [--session path|id]
103
- [--fork path|id] [--session-dir dir] [--session-id id] [--no-session]
104
- [--models patterns] [--thinking level] [--mode text|json]
105
- [--export session [output.html]] [--offline] [--version]
106
- [models --refresh]
107
- [--system-prompt <text-or-file>] [--append-system-prompt <text>]
108
- [--no-context-files|-nc]
109
- [--tools names] [--exclude-tools names] [--no-tools]
110
- [--tool-profile coding|readonly|research|data|full]
111
- [--acceptance-file <contract.json>]
112
- [--allow-tools names] [--yolo|-y] [--approve|--no-approve]
113
- [--theme <name|path>] [--use-theme <name>] [--no-themes]
114
- [--tui-mode regular|fullscreen]
115
- [--skill <path>] [--no-skills|-ns]
116
- [--prompt-template <path>] [--no-prompt-templates|-np]
117
- [--extension|-e <path>] [--no-extensions|-ne]
118
- [-p <prompt>] [prompt...]
119
- ```
120
-
121
- - No prompt, a tty: interactive session.
122
- - `/state` shows the current request's execution outcome, command receipts,
123
- verification state and diagnostic progress across segment cuts and restarts.
124
- Short tasks need no `note` calls to associate evidence. Without a declared
125
- acceptance contract, successful commands remain evidence rather than verified
126
- task completion. A command's new output counts as progress for the stall
127
- watchdog whatever its exit code; an exchange that repeats the previous one
128
- exactly earns none from output that only changes with timing.
129
- - `/goal <objective>` sets an explicit goal:
130
- - The model first drafts acceptance criteria in a single read-only request: it may read the workspace (read, find, grep) but cannot change it or run commands. Each criterion is a command that should fail until the goal is done, a human check, or a guard.
131
- - A guard (`"guard": true` on a command) protects what the goal must not break, such as "the test file is unchanged" or "only plan.md changed". It passes before the work and must still pass after it. Guards are marked in the checklist.
132
- - A draft that does not parse goes back to the model once with the reasons. If the model says the goal cannot be checked in this workspace, it gives the reason and no goal is set.
133
- - You accept the criteria one by one: a checklist in the TUI, or `/goal accept all|1,3` in line mode.
134
- - Work then starts from the objective and continues automatically until every accepted criterion has a fresh passing receipt (and human criteria have your `/accept`).
135
- - It stops early, with the goal still active, when the model reports a blocker, answers two goal checks without acting, a `--max-turns` budget runs out, or the stall watchdog fires.
136
- - `/goal` shows the goal and the status of each criterion; `/goal clear` ends it.
137
- - "Met" comes from receipts and your decisions, never from the model saying it is done.
138
- - When the accepted checks pass, each one is counter-checked: it is re-run in a disposable copy-on-write clone of the workspace with this request's file changes undone.
139
- - It reports whether the check fails without the changes (it tests them) or still passes (it does not).
140
- - A guard is expected to pass there. If it does, it "held" and does not count against the evidence ladder. If it fails there, it "did not hold": the check actually tests the change, and it counts as such.
141
- - If every check is a guard that held, the ladder says that no check tests the change.
142
- - The undo comes from a snapshot taken when the goal request starts (a private Git directory and index; your HEAD, index and stash are untouched), so changes made by shell commands are undone too.
143
- - If the starting state cannot be rebuilt exactly, the result is "unavailable", for example outside a Git work tree when a shell command wrote files that no checkpoint recorded.
144
- - The real workspace is never touched, and the counter-check never blocks the goal.
145
- - `--blind-checks <dir>` adds hidden checks: a directory outside the workspace holding `blind.json` (`{"version":1,"checks":[{"id","description","command"}]}`) and any fixtures.
146
- - The checks are frozen when the session starts and never shown to the model.
147
- - When the goal's checks pass, they run against a clone of the final workspace, with the directory copied in as `.xeno-blind/`.
148
- - The whole log is scanned first, and a pass after the model named the directory or read one of its files is reported as `exposed`, not independent.
149
- - `/acceptance` shows declared command checks and human criteria. `/accept ID`
150
- records your acceptance of a human criterion; subsequent edits invalidate it.
151
- Use `--acceptance-file` or a trusted project's `.xeno/acceptance.json` with
152
- `{ "version": 1, "id": "task", "criteria": [{ "id": "tests", "kind": "command", "description": "tests pass", "command": "bun test" }] }`.
153
- Add `"guard": true` to a command criterion that must keep passing rather than one that shows the work was done.
154
- The declaration is frozen in the session. A normal execution exit does not
155
- imply that human acceptance has been granted.
156
- A contract may additionally declare `targets`, each with `id`, `build`
157
- (a command criterion ID), `artifacts: { paths, output_roots }`, and `entry`
158
- (one of those artifact paths). Optional `interpreter` is an absolute executable
159
- path; `args` are literal strings, `workdir` stays inside the workspace, and
160
- `port` declares an IPv4 loopback listener. A human criterion binds to it with
161
- `target: "ID"`. Enable the `target` tool explicitly with `--tools` or the
162
- `full` profile; the default coding profile stays compact. Run the declared
163
- build with its exact artifact plan, then `target({action:"start",target:"ID"})`.
164
- `inspect` rechecks the owned instance, build inputs, artifact/executable identity
165
- and port ownership. `/acceptance` shows the entry, build, PID and session;
166
- `/accept ID` binds your decision to that observed instance. Rebuilds, changed
167
- files, process exits or lost ownership require fresh acceptance. The first
168
- implementation observes macOS executable identity with the system `lsof` and
169
- Linux identity with `/proc`; port checks require system `lsof`. Missing OS
170
- evidence remains unknown. It never adopts an existing server or proves visual
171
- correctness automatically, and a resumed session cannot reattach an old PID.
172
- - A prompt, or `-p` / `--print`: one shot, then exit. `-p` puts only the
173
- assistant's final text on stdout; the banner, usage, thinking, and tool
174
- lines go to stderr. Piped stdin is appended after the command-line prompt.
175
- - Each invocation starts a new session, including `-p`. `--fresh` remains
176
- an explicit alias. Nothing is deleted.
177
- - `-c` continues the newest session, or starts one if none exists. `-r`
178
- opens a session picker; cancelling leaves saved sessions untouched.
179
- `--session <path|id>` and `-r <id>` open a specific session.
180
- A portable JSONL file creates an independent imported session in the current workspace.
181
- - Resume restores that session's model before consulting defaults. An
182
- explicit `--model` switches through a checkpoint, preserving the original
183
- log without replaying another model's thinking. Missing or ambiguous saved
184
- models are reported; restore their catalog entry before resuming.
185
- - A leftover `.xeno/log` is not migrated; continue it with `--log .xeno/log`.
186
- - `--models 'deepseek/*:low,anthropic/*'` resolves ordered model scopes; an
187
- explicit empty scope disables cycling. `--model id:level` sets thinking,
188
- with an explicit `--thinking` taking precedence.
189
- - `--session-id id` creates or resumes that exact local ID. `--export` writes
190
- offline HTML from a saved session or portable archive without starting an agent.
191
- - `--theme` can be repeated for explicit files/directories; `--use-theme`
192
- selects a theme. `--no-themes` disables automatic discovery.
193
- - Extensions can register typed native CLI flags, including in `--help`.
194
- Normal startup stays offline; `--offline` also blocks remote preparation.
195
-
196
- Slash commands that exist in the session (from `/help`):
197
-
198
- ```
199
- /model [id] search models, or switch (cuts a node)
200
- /models refresh refresh ~/.xeno/models-cache.json; preserve models.json
201
- /provider [provider] connect or manage an account, API key, gateway or local server
202
- /provider claude-pro|codex|github-copilot|grok
203
- subscription login (first-party client credentials)
204
- /logout [provider] remove a stored credential
205
- /scoped-models enable, disable and order models for cycling
206
- /new start a new session beside this one
207
- /resume [id] search sessions, or switch to one
208
- /name <name> name this session
209
- /session id, path, events, usage
210
- /back [n [files|context]] [confirm]
211
- /tree search, filter, fold, label and navigate exact session events
212
- /fork [n] choose an exchange to copy into a new session
213
- /clone copy the active branch into a new session
214
- /export [file] offline HTML, or a portable archive with a .jsonl filename
215
- /import <file> validate and open an archive as an independent session
216
- /debug [file] write local terminal and message diagnostics
217
- /changelog show bundled release notes
218
- /update check for a newer xeno and install it (restart to use)
219
- /trust [once|here|parent|never]
220
- /reload refresh local resources at a durable context checkpoint
221
- /config search resources and edit global or project overrides
222
- /settings [key v] theme, thinking, queues, viewport and editor settings
223
- /hotkeys bindings in effect
224
- /usage /state /help /quit
225
- ```
226
-
227
- Type `/` for commands, templates and skills. The editor completes command
228
- arguments and paths. `@file` or `@"file name"` attaches a project file anywhere
229
- outside code literals; choosing a file keeps the prompt in the editor.
230
- `!cmd` runs in the workspace, streams output, and records it for the next model
231
- request. `!!cmd` records human history while excluding its output from model
232
- context. Neither starts a model request or requires a model credential.
233
- Escape cancels the command and its process group. During a turn, Enter queues
234
- steering after the current tools finish; Alt+Enter queues a follow-up after the
235
- turn, or submits immediately while idle. Alt+Up returns the entire queue to the
236
- editor. Settings expose independent `steeringMode` and `followUpMode` values
237
- of `all` or `one-at-a-time`.
238
- Escape interrupts; pressing Escape twice on an empty idle editor opens the tree.
239
- Ctrl+C clears the draft, then a quick second press exits; Ctrl+D exits an empty
240
- editor. Ctrl+O and Ctrl+T toggle tools and thinking throughout the history.
241
- Ctrl+T persists `hideThinkingBlock`. `/settings` also manages new-session model
242
- defaults and per-model thinking overrides; clearing an override restores the
243
- project or global setting. `showCacheMissNotices` displays the existing prefix
244
- diagnostics without changing usage accounting or issuing extra model requests.
245
-
246
- `/scoped-models` changes the current session immediately; Ctrl+S saves the range.
247
-
248
- `-r` and `/resume` share a session browser: Tab changes workspace scope, Ctrl+N
249
- filters named sessions, Ctrl+S cycles threaded/recent/relevance ordering, Ctrl+P
250
- shows paths, and Ctrl+R renames. Search supports `re:<pattern>` and quoted phrases.
251
- Ctrl+D asks before moving an inactive session into its sibling `.trash` directory;
252
- the original files remain recoverable by moving that directory back. All-workspace
253
- discovery uses registered session roots, with no 200-session result cap.
254
- The tree supports Ctrl+O filter cycling, Alt+Left/Right branch folding/navigation,
255
- Shift+L labels, Shift+T label timestamps, and Ctrl+X copy. These actions can be rebound.
256
- Enter toggles a model, Ctrl+A/Ctrl+X enables/disables filtered models, Ctrl+P
257
- toggles a provider, and Alt+Up/Down orders enabled models. An explicit empty
258
- range disables cycling. `/thinking` exposes off/minimal/low/medium/high/xhigh/max
259
- with model capability checks; Ctrl+S saves a default for that provider/model.
260
- Automatic model changes clamp effort to a supported level.
261
-
262
- `xeno --list-models [search]` searches the offline union of Pi and OpenCode's
263
- Models.dev directory: **226 providers and 7,501 model entries** in the pinned
264
- snapshot. Use `provider/model` when several providers expose the same ID.
265
- `xeno models --refresh` atomically updates `~/.xeno/models-cache.json`;
266
- startup never fetches and the user's `~/.xeno/models.json` remains untouched.
267
- Flat catalogs, Pi `providers` and OpenCode `provider` configuration are supported.
268
- See [provider configuration](docs/providers.md) for local servers, model overrides,
269
- credentials, native cloud protocols, and explicit coverage limits.
270
-
271
- ## Credentials
272
-
273
- Order: `--api-key`, `~/.xeno/auth.json`, `models.json` provider/model credentials,
274
- then the provider's environment variables. `/login` and `/connect` remain hidden
275
- aliases of `/provider`. Enter confirms the selected command argument; Tab inserts it.
276
- A failed explicit source does not
277
- fall through to another account. `/provider codex` uses the `openai-codex` protocol;
278
- ordinary OpenAI API models use `openai`.
279
-
280
- `/provider grok` uses official device authorization and refreshes the account token.
281
- Its model is `xai-grok/grok-build` on the official CLI inference proxy. xAI API keys
282
- remain on `xai`; credentials and rates are not shared between these accounts.
283
-
284
- Interactive sessions can start with no key and wait for `/provider`. `-p` and
285
- non-tty runs exit 1 and name `--api-key` or the variable; they do not mention
286
- `/provider`.
287
-
288
- Keys in `auth.json` may be a literal, `!cmd`, or `$VAR`. The file is written
289
- mode `0600`.
290
-
291
- ## Isolation
292
-
293
- This is not a sandbox. Tools run with the permissions of the user who
294
- started xeno. `read` / `write` / `edit` stay inside the workspace root.
295
- Shell entry points (`exec_command`, `environment`, `bash`, `target`) ask
296
- before they run so you can see the command. That ask is the last look at
297
- what is about to happen, **not a security
298
- boundary**.
299
-
300
- For untrusted repositories, generated code you do not intend to watch, or
301
- unattended automation, run xeno inside a container (or a VM) that holds
302
- only the files and credentials the task needs.
303
-
304
- Project trust (`/trust`, `--approve`) only decides whether to load
305
- `.xeno/settings.json` (and project-level skills, prompts, and UI files).
306
- It does not change what tools can do. `AGENTS.md` is loaded whether the
307
- project is trusted or not.
15
+ npm downloads one native binary for your platform: macOS, Linux (glibc or
16
+ musl) or Windows, each on arm64 or x64. Neither Node nor Bun is needed to run it.
308
17
 
309
- New sessions default to the ten-tool `coding` profile: read, grep, find,
310
- write, edit, environment, exec_command, write_stdin, history and note. `readonly`,
311
- `research` (with branch/resolve), `data` (with query) and `full` choose other
312
- builtin defaults. Extensions remain available; explicit `--tools` overrides
313
- the profile and exclusions apply last. Default session resume keeps the frozen
314
- tool selection; explicit tool flags apply at a resource checkpoint. `/reload`
315
- reselects tools using the current settings.
316
- Tool selection does not bypass permission checks; restoring a tool does not
317
- restore approvals from the previous process.
318
-
319
- After reading an existing file, normally omit `read_handle` and `expected_sha256`
320
- when writing or editing it: Session checks the latest observed file version.
321
- Pass an exact receipt only to select a specific observation; a stale version
322
- still requires a fresh read. Without any prior observation, omission provides
323
- no stale-version protection.
324
-
325
- `--tools` / `--exclude-tools` / `--no-tools` remove tools from the schema
326
- the model sees. `--allow-tools exec_command` lets commands run without asking, which
327
- is what a CI job that has no tty has to pass explicitly. Without a tty,
328
- an `ask` is a deny that names that flag.
329
-
330
- `--yolo` (or `-y`) allows every available tool without an approval prompt for
331
- the current process. It works in interactive, print, and app-server modes;
332
- resumed sessions use the current invocation's choice. Tool exclusions,
333
- read-only branch capabilities, input checks and file path limits still apply.
334
- YOLO does not enable project trust or get saved in settings or session history.
335
- Without the flag, the next launch uses the default approval rules again.
18
+ With Bun, trust the package so its install step can link the binary:
336
19
 
337
20
  ```bash
338
- bun run agent --yolo # interactive session from this checkout
339
- bun run agent --yolo -c # continue with approvals skipped
340
- bun run agent --yolo -p "run tests" # explicit approval-free automation
21
+ bun add -g --trust @visual-z/xeno
341
22
  ```
342
23
 
343
- The installed CLI accepts `xeno --yolo` in version 0.5.0 and later. To
344
- allow only host commands, use `--allow-tools exec_command,environment`.
345
-
346
- ## Workspace data
347
-
348
- Opening a session does not snapshot the working directory. File tools save the
349
- original bytes before editing and record the observed result. `/back` restores
350
- only recorded paths, preserves unrelated files, and refuses conflicting external
351
- edits. Conversation-only navigation leaves files unchanged.
352
-
353
- Shell effects are not automatically reversible. Opt in for a new session with
354
- `--checkpoint-shell` to capture eligible Git files around commands. This uses a
355
- private index and object store without changing your staging area or HEAD. Git
356
- ignored paths, non-regular files, untracked files over 2 MiB, and effects outside
357
- the workspace are excluded. Capture is best effort; unavailable recovery does
358
- not prevent a conversation or change the command's exit result. A running process
359
- has a pending checkpoint until its exit is observed; overlapping writes make that
360
- checkpoint unavailable. Initial capture can take time.
24
+ Without `--trust`, `xeno` still starts on macOS and Linux through a small
25
+ launcher script.
361
26
 
362
- Verification observes a bounded source scope separately from file recovery.
363
- Unknown observations cannot certify a completion claim. Old snapshot logs remain
364
- readable; new file records and scope markers are appended without rewriting them.
27
+ ## Start
365
28
 
366
- A session writes into the workspace:
367
-
368
- | Path | |
369
- |---|---|
370
- | `.xeno/sessions/<id>/` | node logs, handoffs, metadata journal, derived manifest, and observation artifacts |
371
- | `.xeno/blobs/` | content-addressed before/after file versions used by `/back` |
372
-
373
- That tree grows with every turn and every snapshot. There is no garbage
374
- collection yet. Dead branches from `/back` stay on disk.
375
-
376
- `/fork` and `/clone` copy the log graph and observation artifacts, then select an
377
- independent cursor. Historical nodes remain intact; a fork point limits the active
378
- context. Workspace snapshot blobs remain shared under `.xeno/blobs/`.
379
-
380
- Ignore it in the project:
381
-
382
- ```
383
- .xeno/
384
- ```
385
-
386
- Config and secrets live under `~/.xeno/` (or `$XENO_CONFIG_DIR`), not in
387
- the workspace: `auth.json`, `settings.json`, `trust.json`, optional
388
- `models.json` / `keybindings.json` / `prompts/` / `skills/`.
389
-
390
- ## What this does
391
-
392
- Shipped, not planned:
393
-
394
- - An agent loop with tools `read`, `write`, `edit`, `bash`, `note`,
395
- `branch`, `resolve`, `grep`, `find`, `ls`, `history`, `query`. `grep` / `find` use `rg` /
396
- `fd` when those binaries are on `PATH`, otherwise a TypeScript walk;
397
- both paths share one output format. They do not follow symlinks out of
398
- the workspace. Inside a Git work tree they skip git-ignored files, as
399
- Claude Code, OpenCode and Pi do; a path that names an ignored directory is
400
- still searched.
401
- - `history` searches the active ancestry, retrieves original events, and pages
402
- immutable full observations. `query` filters and computes aggregates over
403
- complete CSV, JSON, JSONL or text files, with source hashes. It evaluates a
404
- finite query language, not generated code; resource-limit errors reject the
405
- entire calculation instead of returning partial totals.
406
- Missing JSON pointers identify the failed level and available keys without
407
- copying source values. Writing branches inherit the same evidence tools,
408
- subject to the parent's tool restrictions.
409
- - Durable working-state guidance is appended when the next step is missing,
410
- an action/observation cycle repeats, or the request budget is nearly exhausted.
411
- Existing messages, the system prefix, and tool definitions stay frozen. Model
412
- notes remain annotations and cannot manufacture verified completion.
413
- - Ten native wire protocols through a pinned Pi runtime adapter, alongside the
414
- three existing verified transports. Streaming text, thinking, tools and opaque
415
- signatures project from the same append-only log; deltas remain UI events.
416
- - An offline provider/model union with **226 providers** and **7,501 entries**,
417
- user overrides by provider/model, and a separate explicit-refresh cache.
418
- Native protocol fixtures cover requests and responses; the directory is not
419
- a claim that every listed remote account/model was tested live.
420
- - Sessions, resume, `/new` / `/resume` / `/name` / `/session`, `/back`
421
- (files, context, or both), `/tree`, read-only `branch` / `resolve`, and
422
- write branches in their own git worktree.
423
- - Progress tracking counts new read observations and fresh successful checks.
424
- Repeated content, renamed completion claims and gate regressions do not reset
425
- the three-segment stop rule. This is an anti-stall heuristic, not proof of
426
- relevance or completion; [`research M.4`](docs/agent-harness-research.md) states its limits.
427
- - A terminal UI using pinned OpenTUI, a native text editor, autocomplete,
428
- Markdown, a command palette and searchable pickers. Durable history is a pure
429
- log projection across handoff boundaries. Includes tool diffs, historical
430
- folds, terminal colours, `keybindings.json`, `/settings` and `/hotkeys`.
431
-
432
- - Context files: `AGENTS.md` / `CLAUDE.md` and the override chain, plus
433
- `--system-prompt` / `--append-system-prompt` / `-nc`.
434
- - Skills (`~/.xeno/skills/`, `/skill:name`) and prompt templates
435
- support progressive loading, user visibility, explicit tool intersections
436
- and isolated `context: fork`. Unsupported execution fields are diagnosed.
437
- Loaded instructions keep frozen source hashes and recoverable artifacts.
438
- Templates use `~/.xeno/prompts/` and `/name`. Untrusted projects do not load
439
- project-level copies.
440
- - `/tasks` shows dependency readiness and claims. Long tasks can use
441
- `note(kind="next", work_id="b", depends_on=["a"], ...)`, then
442
- `claim_work` / `release_work`; these are scheduling intent, separate from
443
- the `done` command proof. Ordinary short tasks do not need a graph.
444
- - `branch(background=true)` returns an owned task reference. `/branches`
445
- lists its current capability; `/branches wait|cancel|status <node>` joins or
446
- controls it without a model request. `resolve` exposes the same actions.
447
- Restarted unfinished tasks remain unknown; sealed outcomes can be joined.
448
- - `/processes` separates the last logged observation from a live handle.
449
- Session exit drains its own processes and archives unread output.
450
- - `/reload` refreshes local models, settings, keybindings, context files, skills,
451
- templates and themes without losing the draft or active model. A changed system
452
- prefix checkpoints first; unchanged resources do not create a new segment.
453
- `/config` and `xeno config` share searchable resource provenance and enablement.
454
- Relative resource paths resolve from the settings file that declares them;
455
- project overrides cycle through inherit, load and skip. CLI paths remain explicit.
456
- `/trust` opens a selector; `once` grants no persistent trust. Global
457
- `defaultProjectTrust` cannot be overridden by project settings.
458
- Templates support Pi's `$1`, `$@`, `$ARGUMENTS`, defaults and slices as well as
459
- the existing `{{name}}` syntax. Arguments are substituted once.
460
- - Local TS/JS extensions can register commands, shortcuts, tools and lifecycle
461
- hooks through Pi's factory protocol. Discovery, project trust and `/reload`
462
- use the same resource inventory. Custom state and messages remain append-only
463
- log events. See [extension boundaries and usage](docs/extensions.md).
464
- - Packages can come from local paths, npm or git: `xeno install <source>`,
465
- `remove`, `update --extensions` and `list`. `--local` selects project scope;
466
- `-e` tries a package for one invocation. Manifests, per-kind filters and trust
467
- feed the same resource inventory. Normal startup stays offline.
468
- See [package management](docs/packages.md).
469
- - `/provider` for API keys and for Claude Pro/Max, Codex, GitHub Copilot,
470
- and official Grok account flows. See Known gaps.
471
-
472
- Images can be attached with `@path`, a dropped image path, or Ctrl+V (files,
473
- image, then text). Pasted and dropped images become `[Image #N]` tags at the
474
- caret. Left/Right cross a whole tag; Backspace/Delete remove it in one step,
475
- and Undo restores it. Moving the caret next to a tag shows its preview above
476
- the input (filename and dimensions when image display is unavailable).
477
- `/attachments` remains available for removal; queue recall and history
478
- forks retain them. The log stores immutable blob references. Provider adapters
479
- load verified bytes for Anthropic, Chat Completions and Responses; text-only
480
- models receive a visible placeholder. Custom models declare `input: ["text", "image"]`
481
- in `models.json`. `terminal.showImages`, `terminal.imageWidthCells`,
482
- `images.autoResize`, `images.blockImages` and `markdown.mermaid` are configurable
483
- through `/settings`. Pi syntax highlighting and Mermaid use the same rendering
484
- path for saved replies and live output. Image tokens are estimates until provider
485
- usage is available. Enabling image blocking checkpoints an existing image context;
486
- unblocking affects new submissions, preserving historical request prefixes.
487
-
488
- ## Known gaps
489
-
490
- - **No sandbox.** See Isolation. That is a decision, not a missing feature.
491
- - **Token counts are an estimate** (`chars/3.6`, labelled `kind: "estimate"`).
492
- The provider `count_tokens` API is not wired. Boundaries therefore fire
493
- on an approximation.
494
- - **OAuth has not been run against a live authorization or token endpoint.**
495
- The three flows exist and pass tests against an injected transport.
496
- - **Tiered provider prices are stored as the base rate.** Example: the
497
- catalog comment on `gpt-5.5-pro` notes a `context_over_200k` tier that
498
- is not applied. `/usage` reports `{kind:"partial"}` when cache prices
499
- are missing; it does not treat a missing cache price as zero.
500
- - **Package installation is separate from resource loading.** Local extensions,
501
- skills and templates load from explicit, trusted filesystem sources.
502
- There is no installer.
503
- - **Bun only.** Node has not been tested.
504
- - **`/back` does not restore symlinks.**
505
- - **`.xeno/` is not collected.** Snapshots and abandoned session branches
506
- stay until you delete them.
507
- - **No telemetry, `/share`, automatic updates, or `/compact`.** Those
508
- are refusals (`docs/PI_PARITY.md` D15, D16), not backlog. xeno does say
509
- when a newer version is published, checking automatically at most once a day.
510
- `/update` checks and installs when you ask; `xeno update --check` only checks;
511
- `docs/install.md` (Updates) lists what that request reveals and every
512
- way to turn it off.
513
-
514
- `docs/TUI_ARCHITECTURE.md` describes the active interaction path and verification.
515
- `docs/PI_PARITY.md` records deliberate differences and remaining Pi features.
516
- The native editor supports undo (Ctrl+_ or Ctrl+/) and redo (Ctrl+Shift+Z).
517
- Registered image tags move and delete as whole units and share text undo history.
518
- Ctrl+Z suspends the CLI on POSIX; `fg` restores the terminal and unsent draft.
519
-
520
- Fullscreen is the default. Ctrl+P opens commands, Ctrl+L selects a model,
521
- PgUp/PgDn scroll, and Ctrl+Home/End jump to the start or latest messages.
522
- Ctrl+O expands tools, Ctrl+T expands thinking, and Ctrl+B toggles the sidebar.
523
- Mouse selection copies plain text when `fullscreenCopyOnSelect` is enabled;
524
- Ctrl+X copies a selection or the last reply. Exiting restores the terminal and
525
- prints a bounded execution status and a resume command. Set
526
- `fullscreenExitOutput` to `transcript` in `/settings` for full replay on exit.
527
- The composer stays at the bottom
528
- and grows with the draft; pickers and forms use the same input area.
529
-
530
- An empty `write_stdin` in an agent session waits for new output, command exit,
531
- hard timeout, cancellation or user steering. The process owner holds that wait;
532
- quiet commands do not consume model requests through periodic polling.
533
- Sending input and low-level process polling keep their bounded yield contract.
534
- There is no request cap by default, as in Claude Code, Codex, Gemini CLI and
535
- OpenCode: the stall watchdog stops a run after 12 exchanges without new
536
- evidence. For `--max-turns N`, budgets above one reserve the last request for a text answer.
537
- Tools stay frozen and are disabled for that request, with host enforcement.
538
- Unsupported protocols or a failed final response use an evidence-based stop
539
- report inside the same budget. `/usage` labels provider durations as model time.
540
-
541
- `/settings theme` previews built-in and custom themes from the config directory's
542
- `themes/`. Escape restores the prior theme. Custom files reload after valid edits;
543
- `auto` follows terminal light/dark changes. Built-in themes keep the terminal's
544
- background and derive readable accents from its colour replies. Namespaced action IDs work in `keybindings.json`
545
- alongside existing xeno names; an empty array disables an action in its own scope.
546
-
547
- ## Why this shape
548
-
549
- Three constraints, each of which rules out the obvious alternative.
550
-
551
- **In-place eviction is the worst option under prefix caching.** Releasing tokens from
552
- the middle of the context changes the prompt prefix, which invalidates the cached KV
553
- state for everything after it. Under sustained pressure you pay the cache-write cost on
554
- every request and never amortize it through reads — worse than compaction, which at
555
- least produces one stable prefix per pass (this is the failure mode
556
- [Beyond Compaction](https://arxiv.org/abs/2606.11213) documents). So token release must
557
- be a rare, coarse event, not a continuous process. Hence segments.
558
-
559
- **Summarization is unpredictably lossy, and the loss is undetectable from the result.**
560
- What a summarizer keeps depends on its judgment of salience at that moment, which need
561
- not match what the next segment needs — and you cannot tell from the compacted context
562
- that anything is missing. Worse, the thing summarizers reliably drop is the record of
563
- failed attempts, so the agent repeats them. Hence a deterministic projection plus a log
564
- that is still on disk: a handoff that omits something is recoverable, because the agent
565
- can go read it.
566
-
567
- **A handoff that is only prose is autocompact with extra steps.** If the receiving agent
568
- cannot interrogate what was compressed away, the structure bought nothing. The log
569
- being intact is what makes the difference real rather than rhetorical.
570
-
571
- ## What is actually enforced
572
-
573
- The interesting part is not the field list. It is that the harness — the only layer that
574
- sees prompt assembly, tool mediation and lifecycle events together — can enforce a
575
- contract the prompt cannot.
576
-
577
- **A completion claim must cite a log event that exited zero.** The model calls a claim
578
- tool naming a gate; `deriveHandoff` resolves that citation against command exit codes
579
- recorded in the log. Unresolvable claims land in `state.unverified_claims` with a
580
- reason. They are neither accepted nor silently dropped, and the rendered prompt says
581
- they must be treated as not done.
582
-
583
- This directly targets the "migration applied successfully" failure: a tool call returned
584
- a nonzero exit code, nothing in the loop read it, and the model wrote a confident summary
585
- of a result it never saw. Here the model's account of a result carries no weight at all.
586
-
587
- Two related rules:
588
-
589
- - **Claims resolve against evidence at or before the claim.** A later failing run does
590
- not erase the recorded successful execution — appending an event must never
591
- rewrite that observation. That the gate is red *now* is separate
592
- information, carried by `verification` and repeated inline as `evidence_superseded`
593
- so a reader of `completed` cannot miss it.
594
- - **Evidence must come from the same segment.** A gate that passed three segments ago
595
- is not proof about code that has changed since.
596
-
597
- Other invariants (`src/core/handoff.ts`, `validateHandoff`): a `pass` status requires a
598
- zero exit; every file anchor carries a digest; every handoff identifies its source
599
- node and digest; a continuation is valid only with both remaining work and a concrete next
600
- action. A property test asserts that `deriveHandoff` can never produce a handoff that
601
- violates any of them.
602
-
603
- **Append references, never copies.** A boundary event stores the id of the handoff it
604
- produced and a ref to its predecessor — never the history it replaces. Codex CLI
605
- re-embeds the full prior history into its rollout JSONL on every compaction, which is
606
- quadratic on disk and has been reported at 42 GB
607
- ([openai/codex#41806](https://github.com/openai/codex/issues/41806)). The types here
608
- cannot express recursive history copies. Full structured state can still grow as
609
- new requirements, decisions and files accumulate. Handoff v2 carries a bounded
610
- suffix of each section and records its immutable source and exact ranges. The
611
- `history` tool rebuilds omitted pages from the log; no model summary is involved.
612
-
613
- The carried-state budget is 5,000 estimated tokens. A 100-node deterministic
614
- measurement grows the full state to about 14.7k while the carried view remains
615
- at or below 5k. This bounds the prompt payload; it does not claim constant disk
616
- space, replay time, or working memory for reconstructing the full history. The
617
- objective stays verbatim: an objective that cannot fit is refused explicitly.
618
-
619
- Session moves are committed to `metadata.jsonl`; `manifest.json` is a replaceable
620
- index rebuilt from it. Sealed node digests are checked on resume and restore.
621
- Interrupted tools receive an explicit unknown outcome instead of being run again.
622
- Tool previews that exceed their display budget include a content-addressed
623
- reference to the complete observation.
624
-
625
- Command evidence includes the observed workspace digest when scanning succeeds.
626
- Later edits mark old verification and completions as stale. A zero exit proves
627
- the recorded command succeeded; it does not prove the model's description is an
628
- adequate specification or that the test suite covers every requirement.
629
-
630
- ## Segment length
631
-
632
- New sessions default to **windowed replay**: preserve the active dialogue until model
633
- window pressure calls for a new projection. With an explicit model window, reserve
634
- the configured output tokens, prepare at 70% of the remaining capacity and cut at
635
- 80%. These are conservative hypotheses, not measured optima. Unknown model capacity
636
- uses the fixed segmented policy below; it is never treated as unlimited.
637
-
638
- The explicit segmented policy retains **30k trigger / 40k hard**. Its historical cost model
639
-
640
- ```
641
- per_turn(L) = 0.05*(H+L) + 1.25*d + 1.25*(H+R)*d/(L-H)
642
- ```
643
-
644
- (cache reads at 0.1x, writes at 1.25x; `H` = handoff size, `d` = per-turn growth,
645
- `R` = re-read cost after a boundary) was first evaluated with `H` *assumed* to be ~10k,
646
- which put the optimum near 37k. The original single-segment measurement
647
- (`prev=null`) gave the following historical figures:
648
-
649
- | turns | segment L | handoff H | H/L |
650
- |------:|----------:|----------:|----:|
651
- | 10 | 4.8k | 366 | 7.6% |
652
- | 50 | 25k | 986 | 3.9% |
653
- | 200 | 99k | 2218 | 2.2% |
654
- | 400 | 203k | 3201 | 1.6% |
655
-
656
- Those samples do not establish a bound over a continuous session: deduplication
657
- does not remove new, distinct facts. `bun run measure` now reports both this local
658
- diagnostic and 100 consecutive derivations with retained state. The cost formula
659
- models input caching at the stated rates; it omits task quality and cannot prove
660
- 30k/40k is globally optimal. These legacy bounds retain their 5k work floor.
661
-
662
- `eval/scripts/ab-suite.ts` now separates node, replay, round-preserving truncation and
663
- observation masking. It uses a seeded shuffled schedule and includes output cost
664
- and failed outcomes. Historical A/B figures predate these corrections and cannot
665
- establish superiority over the corrected baselines. No new live-model result is
666
- claimed until that experiment is run.
667
-
668
- There is also a floor with a principled reason: **a handoff only pays for itself once a
669
- segment's history exceeds the handoff.** Below that, replaying the history is cheaper —
670
- `test/log.test.ts` pins both sides of that crossover.
671
-
672
- ## Layout
673
-
674
- `SessionConfig.contextPolicy` and `--context-policy` select `windowed` (new-session
675
- default), `segmented`, `continuous`, or the experimental `adaptive` policy. They
676
- share the same durable log. Saved sessions keep their original policy, including
677
- legacy logs without a policy, which resume as segmented. Explicit CLI `--trigger`
678
- selects segmented unless `--context-policy` is also set. Continuous
679
- keeps the dialogue until the provider window guard stops it; adaptive may defer a
680
- soft cut when continuation state is missing or a conservative next-input cost
681
- estimate favors keeping the cached prefix. It still obeys the hard boundary.
682
- Windowed cuts keep a bounded recent suffix of complete exchanges alongside the
683
- derived handoff, through event references rather than copied transcript bytes.
684
- The replacement targets half the usable window and at most 20k recent-history
685
- tokens; these are testable assumptions. New prompts are checked before dispatch.
686
- If no useful replacement fits, the session stops explicitly. Retained events do
687
- not count twice toward derived state, and model switches discard old thinking.
688
- The segmented 30k/40k/5k values are unchanged. Missing working state gets one
689
- append-only preparation notice before the boundary. These mechanisms do not
690
- guarantee model compliance or lower whole-task costs; see research N.6.
691
-
692
- New sessions also stop before another model call after 12 complete tool exchanges
693
- without new observed evidence or fresh verification, with one warning halfway.
694
- This watchdog is independent of context cuts and reconstructs from original log
695
- events. `SessionConfig.stallLimit` accepts 0 to disable or an integer of at least 2;
696
- old saved sessions without it retain their prior behavior. Novel content need not
697
- be relevant, so this is a resource guard, not a task-success judge (research N.9).
698
-
699
- Dependency direction is one-way, enforced mechanically by
700
- `scripts/check-boundaries.ts`:
701
-
702
- ```
703
- apps -> runtime -> store -> core
29
+ ```bash
30
+ export ANTHROPIC_API_KEY=… # or OPENAI_API_KEY, GEMINI_API_KEY, OPENROUTER_API_KEY, …
31
+ xeno # interactive
32
+ xeno -p "explain this repo" # one prompt, then exit
33
+ xeno -c # continue the newest session
34
+ xeno -r # pick a session to resume
704
35
  ```
705
36
 
706
- Every path below was checked with `test -f` on this checkout.
37
+ In the app, `/provider` connects an account, an API key or a gateway. `/model` switches
38
+ models, `/settings` opens settings, `/changelog` shows what changed, and
39
+ `/update` installs a newer release.
707
40
 
708
- | Layer | |
709
- |---|---|
710
- | **`src/core/`** | **pure**: no I/O, no clock, no randomness, no model call |
711
- | `core/events.ts` | log event types; harness-derived vs model-annotated split |
712
- | `core/handoff.ts` | handoff schema, YAML field order, `validateHandoff` invariants |
713
- | `core/derive.ts` | `deriveHandoff` — events + previous handoff -> next handoff |
714
- | `core/project.ts` | `projectContext` — log -> messages |
715
- | `core/transcript.ts` / `file-references.ts` | pure human-history projection and explicit file references |
716
- | `core/boundary.ts` | `shouldCut`, `shouldStopAndAsk` |
717
- | `core/continuation.ts` / `history-query.ts` | append-only guidance and ancestry search contracts |
718
- | `core/context-policy.ts` | windowed replay, legacy policies and conservative cache-cost estimates |
719
- | `core/context-window.ts` | model-window budgets and exact recent-exchange retention |
720
- | `core/data-query.ts` | deterministic parsing, filtering, grouping and aggregates |
721
- | `core/yaml.ts` | restricted deterministic YAML emitter, no dependencies |
722
- | `core/tokens.ts` | token counter interface; the bundled one is an estimate and says so |
723
- | `core/permissions.ts` | `decide` / `selectTools` — pure rules; approval is a last look, not a boundary |
724
- | `core/skills.ts` / `prompts.ts` / `frontmatter.ts` | skill text and `/name` templates |
725
- | `core/settings.ts` / `theme.ts` / `keymap.ts` | settings merge, themes, bindings |
726
- | `core/queue.ts` | steering / follow-up queue |
727
- | **`src/store/`** | the only I/O: node JSONL, handoff files, manifest, blobs |
728
- | `store/log.ts` / `sessions.ts` | node tree and `.xeno/sessions/<id>/` |
729
- | `store/config.ts` | `~/.xeno/` paths; `auth.json` is 0600 |
730
- | `store/search.ts` | grep / find / ls walk |
731
- | `store/context-files.ts` | AGENTS.md discovery |
732
- | **`src/runtime/`** | impure but thin; the only layer allowed npm packages |
733
- | `runtime/provider.ts` / `openai.ts` | the two wire formats |
734
- | `runtime/catalog.ts` / `model-config.ts` / `model-sources.ts` | Pi + Models.dev union, offline overlays and private provider configuration |
735
- | `runtime/tools.ts` / `history-tools.ts` | confined tools, complete query results and history retrieval |
736
- | `runtime/benchmark.ts` | actual Session trials, bounded spending and cache diagnostics |
737
- | `runtime/loop.ts` | orchestration; every judgement delegates to a pure function in core |
738
- | `runtime/auth.ts` / `oauth.ts` | credential order and subscription flows |
739
- | **`src/tui/`** | OpenTUI view components and pure display helpers; no harness imports |
740
- | `tui/ui/composer.ts` / `atomic-draft.ts` / `messages.ts` / `screen.ts` | native editing, atomic image tags, messages and layout |
741
- | **`src/apps/`** | `cli.ts` — OpenTUI for TTY, clean print/JSON output otherwise |
742
- | `apps/ui/app.ts` / `project.ts` / `status-model.ts` | controller, transcript projection and status facts |
743
- | `apps/startup.ts` / `shell.ts` / `commands.ts` | flags, session, slash commands |
41
+ Sessions live in `.xeno/` inside the project; settings and credentials in
42
+ `~/.xeno/` (`auth.json` is created with mode `0600`).
744
43
 
745
- ## Properties the tests pin
44
+ ## Updates
746
45
 
747
- - **Identity.** With no handoff, the projection is the identity mapping of harness
748
- events onto messages. Segment 0 behaves exactly like a harness with no context
749
- management, so nothing is paid for until a boundary actually fires.
750
- - **Prefix stability.** Appending an event only appends to the projection; it never
751
- rewrites an earlier message. This pins prefix stability; actual cache hits
752
- remain provider-dependent.
753
- - **Purity.** Identical inputs produce byte-identical YAML. `deriveHandoff` mutates
754
- neither its inputs nor the previous handoff.
755
- - **Nothing silently dropped.** Every claim appears in exactly one of `completed` or
756
- `unverified_claims`; state buckets are pairwise disjoint; accumulated state is
757
- monotonic across segments.
758
- - **No history copies.** Tool output is referenced rather than recursively embedded.
759
- The carried handoff is budgeted; full structured state remains reconstructible.
760
- - **YAML round-trips.** Emit -> parse -> re-emit is byte-identical, verified against a
761
- real parser, with an idempotency gate and golden snapshots.
46
+ xeno checks the npm registry for a newer release at most once a day, in the
47
+ background. It sends no identifier. Set `XENO_NO_UPDATE_CHECK=1`, or turn off
48
+ *Check for updates* in `/settings`, to stop it. `xeno update --check` checks
49
+ now.
762
50
 
763
- ```
764
- bun run gate # bun test + tsc --noEmit + the boundary checks
765
- bun run measure # the segment-length measurement
766
- bun run regen-golden # regenerate snapshots, then read the diff
767
- ```
51
+ ## License
768
52
 
769
- Design notes: `docs/agent-harness-research.md`.
53
+ Proprietary (`UNLICENSED`). You may install and use the published binaries;
54
+ no right to copy, modify or redistribute them is granted.