@visual-z/xeno 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +498 -0
- package/docs/install.md +130 -0
- package/package.json +43 -0
- package/src/apps/approve.ts +49 -0
- package/src/apps/cli.ts +37 -0
- package/src/apps/commands.ts +226 -0
- package/src/apps/completions.ts +28 -0
- package/src/apps/input.ts +297 -0
- package/src/apps/render.ts +207 -0
- package/src/apps/shell.ts +2353 -0
- package/src/apps/startup.ts +1302 -0
- package/src/core/benchmark.ts +195 -0
- package/src/core/boundary.ts +174 -0
- package/src/core/churn.ts +59 -0
- package/src/core/completion-review.ts +66 -0
- package/src/core/context-policy.ts +60 -0
- package/src/core/context-window.ts +54 -0
- package/src/core/continuation.ts +114 -0
- package/src/core/cycle.ts +17 -0
- package/src/core/data-query.ts +201 -0
- package/src/core/deadline.ts +39 -0
- package/src/core/derive.ts +489 -0
- package/src/core/edit-plan.ts +200 -0
- package/src/core/environment.ts +29 -0
- package/src/core/event-validation.ts +99 -0
- package/src/core/events.ts +486 -0
- package/src/core/evidence-links.ts +71 -0
- package/src/core/evidence.ts +89 -0
- package/src/core/execution.ts +12 -0
- package/src/core/exhaustive.ts +18 -0
- package/src/core/experiment.ts +40 -0
- package/src/core/export.ts +169 -0
- package/src/core/file-references.ts +35 -0
- package/src/core/frontmatter.ts +213 -0
- package/src/core/handoff.ts +397 -0
- package/src/core/harness-comparison.ts +90 -0
- package/src/core/history-query.ts +103 -0
- package/src/core/history.ts +100 -0
- package/src/core/json-event.ts +135 -0
- package/src/core/json-pointer.ts +46 -0
- package/src/core/keymap.ts +241 -0
- package/src/core/observation-view.ts +87 -0
- package/src/core/outcome.ts +45 -0
- package/src/core/overflow.ts +59 -0
- package/src/core/permissions.ts +182 -0
- package/src/core/policy-evaluation.ts +55 -0
- package/src/core/progress.ts +101 -0
- package/src/core/project.ts +372 -0
- package/src/core/prompts.ts +83 -0
- package/src/core/queue.ts +60 -0
- package/src/core/read-bounds.ts +15 -0
- package/src/core/recall-analysis.ts +90 -0
- package/src/core/recall-trial.ts +153 -0
- package/src/core/response-recovery.ts +46 -0
- package/src/core/scheduling.ts +8 -0
- package/src/core/settings.ts +174 -0
- package/src/core/skills.ts +121 -0
- package/src/core/stall.ts +48 -0
- package/src/core/text-normalize.ts +81 -0
- package/src/core/theme.ts +179 -0
- package/src/core/tokens.ts +149 -0
- package/src/core/tool-contract.ts +102 -0
- package/src/core/tool-input.ts +38 -0
- package/src/core/transcript.ts +60 -0
- package/src/core/window-trial.ts +65 -0
- package/src/core/work-state.ts +103 -0
- package/src/core/yaml.ts +282 -0
- package/src/index.ts +10 -0
- package/src/runtime/auth.ts +255 -0
- package/src/runtime/benchmark.ts +187 -0
- package/src/runtime/catalog.ts +365 -0
- package/src/runtime/evidence-notes.ts +33 -0
- package/src/runtime/exec-sessions.ts +214 -0
- package/src/runtime/execution-control.ts +39 -0
- package/src/runtime/harness-comparison.ts +356 -0
- package/src/runtime/history-tools.ts +108 -0
- package/src/runtime/loop.ts +1983 -0
- package/src/runtime/model.ts +614 -0
- package/src/runtime/models-fetch.ts +155 -0
- package/src/runtime/oauth-device.ts +86 -0
- package/src/runtime/oauth.ts +759 -0
- package/src/runtime/openai-responses.ts +286 -0
- package/src/runtime/openai.ts +675 -0
- package/src/runtime/provider.ts +498 -0
- package/src/runtime/recall-trial.ts +226 -0
- package/src/runtime/resume.ts +66 -0
- package/src/runtime/retry.ts +297 -0
- package/src/runtime/tools.ts +1193 -0
- package/src/runtime/usage.ts +225 -0
- package/src/runtime/window-trial.ts +140 -0
- package/src/runtime/working-notes.ts +30 -0
- package/src/store/atomic.ts +31 -0
- package/src/store/auth-store.ts +50 -0
- package/src/store/blobs.ts +142 -0
- package/src/store/command.ts +75 -0
- package/src/store/config.ts +69 -0
- package/src/store/context-files.ts +356 -0
- package/src/store/file-index.ts +81 -0
- package/src/store/git-branch.ts +35 -0
- package/src/store/history-search.ts +19 -0
- package/src/store/log.ts +642 -0
- package/src/store/models.ts +41 -0
- package/src/store/observations.ts +181 -0
- package/src/store/query-source.ts +44 -0
- package/src/store/recovery.ts +39 -0
- package/src/store/replay.ts +63 -0
- package/src/store/resources.ts +361 -0
- package/src/store/restore.ts +302 -0
- package/src/store/search.ts +644 -0
- package/src/store/serial.ts +13 -0
- package/src/store/sessions.ts +463 -0
- package/src/store/trust.ts +69 -0
- package/src/store/workspace.ts +256 -0
- package/src/store/worktree.ts +233 -0
- package/src/tui/ansi.ts +67 -0
- package/src/tui/autocomplete.ts +29 -0
- package/src/tui/complete.ts +87 -0
- package/src/tui/diff.ts +160 -0
- package/src/tui/editor.ts +893 -0
- package/src/tui/exhaustive.ts +14 -0
- package/src/tui/fuzzy.ts +75 -0
- package/src/tui/host.ts +223 -0
- package/src/tui/input.ts +69 -0
- package/src/tui/keys.ts +378 -0
- package/src/tui/markdown.ts +17 -0
- package/src/tui/render.ts +153 -0
- package/src/tui/select.ts +240 -0
- package/src/tui/settings.ts +40 -0
- package/src/tui/statusline.ts +162 -0
- package/src/tui/style.ts +205 -0
- package/src/tui/terminal.ts +30 -0
- package/src/tui/text.ts +52 -0
- package/src/tui/toolview.ts +386 -0
- package/src/tui/transcript.ts +71 -0
- package/src/tui/tree.ts +405 -0
- package/src/tui/width.ts +567 -0
- package/src/vendor/pi-tui/LICENSE.upstream +21 -0
- package/src/vendor/pi-tui/VENDOR.md +23 -0
- package/src/vendor/pi-tui/alt-screen-search.ts +327 -0
- package/src/vendor/pi-tui/autocomplete.ts +835 -0
- package/src/vendor/pi-tui/components/alt-screen-flash.ts +51 -0
- package/src/vendor/pi-tui/components/box.ts +167 -0
- package/src/vendor/pi-tui/components/cancellable-loader.ts +40 -0
- package/src/vendor/pi-tui/components/editor.ts +2470 -0
- package/src/vendor/pi-tui/components/h-stack.ts +44 -0
- package/src/vendor/pi-tui/components/image.ts +127 -0
- package/src/vendor/pi-tui/components/input.ts +494 -0
- package/src/vendor/pi-tui/components/loader.ts +101 -0
- package/src/vendor/pi-tui/components/markdown.ts +1015 -0
- package/src/vendor/pi-tui/components/mouse-region.ts +33 -0
- package/src/vendor/pi-tui/components/scroll-view.ts +224 -0
- package/src/vendor/pi-tui/components/select-list.ts +273 -0
- package/src/vendor/pi-tui/components/settings-list.ts +328 -0
- package/src/vendor/pi-tui/components/spacer.ts +28 -0
- package/src/vendor/pi-tui/components/stack.ts +154 -0
- package/src/vendor/pi-tui/components/text.ts +107 -0
- package/src/vendor/pi-tui/components/truncated-text.ts +65 -0
- package/src/vendor/pi-tui/components/v-stack.ts +33 -0
- package/src/vendor/pi-tui/editor-component.ts +74 -0
- package/src/vendor/pi-tui/fuzzy.ts +138 -0
- package/src/vendor/pi-tui/index.ts +156 -0
- package/src/vendor/pi-tui/keybindings.ts +320 -0
- package/src/vendor/pi-tui/keys.ts +1401 -0
- package/src/vendor/pi-tui/kill-ring.ts +46 -0
- package/src/vendor/pi-tui/latex.ts +1506 -0
- package/src/vendor/pi-tui/layout-node.ts +51 -0
- package/src/vendor/pi-tui/layout.ts +449 -0
- package/src/vendor/pi-tui/native-modifiers.ts +13 -0
- package/src/vendor/pi-tui/native-module-path.ts +31 -0
- package/src/vendor/pi-tui/native-platform.ts +63 -0
- package/src/vendor/pi-tui/stdin-buffer.ts +444 -0
- package/src/vendor/pi-tui/terminal-colors.ts +73 -0
- package/src/vendor/pi-tui/terminal-image.ts +696 -0
- package/src/vendor/pi-tui/terminal.ts +547 -0
- package/src/vendor/pi-tui/tui-alt-screen.ts +1742 -0
- package/src/vendor/pi-tui/tui-main-screen.ts +655 -0
- package/src/vendor/pi-tui/tui.ts +1456 -0
- package/src/vendor/pi-tui/undo-stack.ts +28 -0
- package/src/vendor/pi-tui/utils.ts +1345 -0
- package/src/vendor/pi-tui/word-navigation.ts +117 -0
package/README.md
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
# xeno
|
|
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
|
+
Version **0.1.0**. The on-disk session format will still change; `0.x` is that
|
|
21
|
+
statement. Published as `@visual-z/xeno`; the license is `UNLICENSED` (readable and installable, no reuse granted).
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Bun is required. This tree was run on Bun 1.3.10. Node has not been tried.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm i -g @visual-z/xeno # or: bun add -g @visual-z/xeno
|
|
29
|
+
xeno --help
|
|
30
|
+
```
|
|
31
|
+
|
|
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
|
+
- Stable work IDs with explicit unblock, reopen, and cancel operations. Verified completion still requires fresh executed evidence.
|
|
51
|
+
- Shared schema validation and structured tool feedback. Reads return file versions; edits support an expected version and return a diff.
|
|
52
|
+
- Writing branches start from the parent's working copy, including uncommitted files, in an isolated Git worktree. Adopt continues that checkout.
|
|
53
|
+
- Independent readers and read-only branches run in a bounded window; writes and state changes are barriers. Results remain in request order.
|
|
54
|
+
- `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.
|
|
55
|
+
|
|
56
|
+
Use `/new` or `--fresh` to start with the current tool protocol. Existing sessions
|
|
57
|
+
keep their saved frozen schemas and concurrency policy. New sessions default to
|
|
58
|
+
three concurrent readers; programmatic callers can set `SessionConfig.maxParallelTools`.
|
|
59
|
+
This setting is not a CLI flag. Evidence freshness reflects the last logged observation.
|
|
60
|
+
|
|
61
|
+
The public-data evaluation protocol, architectural hypotheses, and measured
|
|
62
|
+
results are in [`docs/benchmarks.md`](docs/benchmarks.md). The LongBench v2 pilot
|
|
63
|
+
compares segmentation, full history, and observation masking with the same model;
|
|
64
|
+
its tool-based input protocol is explicitly separate from the official leaderboard.
|
|
65
|
+
The follow-up trial compares the enhanced working-state protocol and computation
|
|
66
|
+
tools with a control on six previously unused questions. Real process-kill recovery
|
|
67
|
+
checks are reported separately from model accuracy.
|
|
68
|
+
The explicit-policy follow-up separates segmented, continuous and adaptive context
|
|
69
|
+
views. Its budget-limited result and negative cases are recorded in the same report;
|
|
70
|
+
neither segmentation nor the experimental adaptive rule has established a quality advantage.
|
|
71
|
+
`bun run scripts/compare-harness.ts smoke --output /absolute/new/smoke-directory`
|
|
72
|
+
also exercises xeno-windowed, xeno-continuous and an installed Pi CLI with shared
|
|
73
|
+
confined tools, without paid model calls. Pi runs on Node through an isolated local
|
|
74
|
+
tool bridge; no Pi SDK is added to the project. Its `plan` / `run` protocol freezes
|
|
75
|
+
source, model, task order and spending policy, including summary calls. An explicitly
|
|
76
|
+
authorized `--budget unlimited` on both `plan` and `run` records costs without a local
|
|
77
|
+
dollar ceiling; upstream errors stop the trial, with HTTP 402 marked as awaiting top-up.
|
|
78
|
+
This checks a controlled configuration, not stock Pi or an official leaderboard.
|
|
79
|
+
|
|
80
|
+
## Usage
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
xeno [-m <model>] [--provider <name>] [--api-key <key>]
|
|
84
|
+
[-w <workspace>] [--log <dir>] [--max-turns N]
|
|
85
|
+
[--trigger N --hard N] [--list-models] [--fresh]
|
|
86
|
+
[models --refresh]
|
|
87
|
+
[--system-prompt <text-or-file>] [--append-system-prompt <text>]
|
|
88
|
+
[--no-context-files|-nc]
|
|
89
|
+
[--tools names] [--exclude-tools names] [--no-tools]
|
|
90
|
+
[--allow-tools names] [--approve|--no-approve]
|
|
91
|
+
[--theme <name|path>]
|
|
92
|
+
[--skill <path>] [--no-skills]
|
|
93
|
+
[--prompt-template <path>] [--no-prompt-templates]
|
|
94
|
+
[-p <prompt>] [prompt...]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- No prompt, a tty: interactive session.
|
|
98
|
+
- A prompt, or `-p` / `--print`: one shot, then exit. `-p` puts only the
|
|
99
|
+
assistant's final text on stdout; the banner, usage, thinking, and tool
|
|
100
|
+
lines go to stderr. Piped stdin is appended after the command-line prompt.
|
|
101
|
+
- A workspace that already holds a session is resumed. `--fresh` opens a
|
|
102
|
+
second session beside it. Nothing is deleted.
|
|
103
|
+
- A leftover `.xeno/log` is not migrated; continue it with `--log .xeno/log`.
|
|
104
|
+
|
|
105
|
+
Slash commands that exist in the session (from `/help`):
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
/model [id] search models, or switch (cuts a node)
|
|
109
|
+
/models refresh fetch models.dev into ~/.xeno/models.json
|
|
110
|
+
/login [provider] choose a login method, or store an API key
|
|
111
|
+
/login claude-pro|codex|github-copilot
|
|
112
|
+
subscription login (first-party client credentials)
|
|
113
|
+
/logout [provider] remove a stored credential
|
|
114
|
+
/new start a new session beside this one
|
|
115
|
+
/resume [id] search sessions, or switch to one
|
|
116
|
+
/name <name> name this session
|
|
117
|
+
/session id, path, events, usage
|
|
118
|
+
/back [n [files|context]] [confirm]
|
|
119
|
+
/tree search the session tree; navigate context at an exchange boundary
|
|
120
|
+
/fork [n] choose an exchange to copy into a new session
|
|
121
|
+
/clone copy the active branch into a new session
|
|
122
|
+
/trust [here|parent|never]
|
|
123
|
+
/settings [key v] theme, thinking, statusBar
|
|
124
|
+
/hotkeys bindings in effect
|
|
125
|
+
/usage /state /help /quit
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Type `/` for commands, templates and skills. The editor completes command
|
|
129
|
+
arguments and paths. `@file` or `@"file name"` attaches a project file anywhere
|
|
130
|
+
outside code literals; choosing a file keeps the prompt in the editor.
|
|
131
|
+
At line start, `!cmd` runs in the workspace and sends stdout/stderr/exit to the model; `!!cmd` runs without
|
|
132
|
+
sending output. During a turn, Enter queues steering (delivered after the
|
|
133
|
+
current tools finish); Alt+Enter queues a follow-up for after the turn.
|
|
134
|
+
Escape interrupts; pressing Escape twice on an empty idle editor opens the tree.
|
|
135
|
+
Ctrl+C clears the draft, then a quick second press exits; Ctrl+D exits an empty
|
|
136
|
+
editor. Ctrl+O and Ctrl+T toggle tools and thinking throughout the history.
|
|
137
|
+
|
|
138
|
+
`xeno --list-models` prints the built-in catalog (12 providers, 23 models)
|
|
139
|
+
and whether a credential resolved. `xeno models --refresh` writes
|
|
140
|
+
`~/.xeno/models.json`; startup never fetches.
|
|
141
|
+
|
|
142
|
+
## Credentials
|
|
143
|
+
|
|
144
|
+
Order: `--api-key`, then `~/.xeno/auth.json`, then the provider's environment
|
|
145
|
+
variable. A stored entry owns that provider — the environment is not consulted
|
|
146
|
+
after a stored value fails.
|
|
147
|
+
|
|
148
|
+
Interactive sessions can start with no key and wait for `/login`. `-p` and
|
|
149
|
+
non-tty runs exit 1 and name `--api-key` or the variable; they do not mention
|
|
150
|
+
`/login`.
|
|
151
|
+
|
|
152
|
+
Keys in `auth.json` may be a literal, `!cmd`, or `$VAR`. The file is written
|
|
153
|
+
mode `0600`.
|
|
154
|
+
|
|
155
|
+
## Isolation
|
|
156
|
+
|
|
157
|
+
This is not a sandbox. Tools run with the permissions of the user who
|
|
158
|
+
started xeno. `read` / `write` / `edit` stay inside the workspace root;
|
|
159
|
+
`bash` does not — it asks before it runs so you can see the command. That
|
|
160
|
+
ask is the last look at what is about to happen, **not a security
|
|
161
|
+
boundary**.
|
|
162
|
+
|
|
163
|
+
For untrusted repositories, generated code you do not intend to watch, or
|
|
164
|
+
unattended automation, run xeno inside a container (or a VM) that holds
|
|
165
|
+
only the files and credentials the task needs.
|
|
166
|
+
|
|
167
|
+
Project trust (`/trust`, `--approve`) only decides whether to load
|
|
168
|
+
`.xeno/settings.json` (and project-level skills, prompts, and UI files).
|
|
169
|
+
It does not change what tools can do. `AGENTS.md` is loaded whether the
|
|
170
|
+
project is trusted or not.
|
|
171
|
+
|
|
172
|
+
`--tools` / `--exclude-tools` / `--no-tools` remove tools from the schema
|
|
173
|
+
the model sees. `--allow-tools bash` lets bash run without asking, which
|
|
174
|
+
is what a CI job that has no tty has to pass explicitly. Without a tty,
|
|
175
|
+
an `ask` is a deny that names that flag.
|
|
176
|
+
|
|
177
|
+
## Workspace data
|
|
178
|
+
|
|
179
|
+
A session writes into the workspace:
|
|
180
|
+
|
|
181
|
+
| Path | |
|
|
182
|
+
|---|---|
|
|
183
|
+
| `.xeno/sessions/<id>/` | node logs, handoffs, metadata journal, derived manifest, and observation artifacts |
|
|
184
|
+
| `.xeno/blobs/` | content-addressed file snapshots used by `/back` |
|
|
185
|
+
|
|
186
|
+
That tree grows with every turn and every snapshot. There is no garbage
|
|
187
|
+
collection yet. Dead branches from `/back` stay on disk.
|
|
188
|
+
|
|
189
|
+
`/fork` and `/clone` copy the log graph and observation artifacts, then select an
|
|
190
|
+
independent cursor. Historical nodes remain intact; a fork point limits the active
|
|
191
|
+
context. Workspace snapshot blobs remain shared under `.xeno/blobs/`.
|
|
192
|
+
|
|
193
|
+
Ignore it in the project:
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
.xeno/
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Config and secrets live under `~/.xeno/` (or `$XENO_CONFIG_DIR`), not in
|
|
200
|
+
the workspace: `auth.json`, `settings.json`, `trust.json`, optional
|
|
201
|
+
`models.json` / `keybindings.json` / `prompts/` / `skills/`.
|
|
202
|
+
|
|
203
|
+
## What this does
|
|
204
|
+
|
|
205
|
+
Shipped, not planned:
|
|
206
|
+
|
|
207
|
+
- An agent loop with tools `read`, `write`, `edit`, `bash`, `note`,
|
|
208
|
+
`branch`, `resolve`, `grep`, `find`, `ls`, `history`, `query`. `grep` / `find` use `rg` /
|
|
209
|
+
`fd` when those binaries are on `PATH`, otherwise a TypeScript walk;
|
|
210
|
+
both paths share one output format. They do not follow symlinks out of
|
|
211
|
+
the workspace.
|
|
212
|
+
- `history` searches the active ancestry, retrieves original events, and pages
|
|
213
|
+
immutable full observations. `query` filters and computes aggregates over
|
|
214
|
+
complete CSV, JSON, JSONL or text files, with source hashes. It evaluates a
|
|
215
|
+
finite query language, not generated code; resource-limit errors reject the
|
|
216
|
+
entire calculation instead of returning partial totals.
|
|
217
|
+
Missing JSON pointers identify the failed level and available keys without
|
|
218
|
+
copying source values. Writing branches inherit the same evidence tools,
|
|
219
|
+
subject to the parent's tool restrictions.
|
|
220
|
+
- Durable working-state guidance is appended when the next step is missing,
|
|
221
|
+
an action/observation cycle repeats, or the request budget is nearly exhausted.
|
|
222
|
+
Existing messages, the system prefix, and tool definitions stay frozen. Model
|
|
223
|
+
notes remain annotations and cannot manufacture verified completion.
|
|
224
|
+
- Two wire adapters (`anthropic-messages`, `openai-completions`). Both
|
|
225
|
+
stream; deltas are UI events and are not written to the log.
|
|
226
|
+
- A built-in catalog of **12** API-key providers and **23** models
|
|
227
|
+
(anthropic, openai, google, deepseek, xai, groq, cerebras, mistral,
|
|
228
|
+
openrouter, zai, moonshotai, together). `~/.xeno/models.json` overrides
|
|
229
|
+
by id. Startup does not hit the network.
|
|
230
|
+
- Sessions, resume, `/new` / `/resume` / `/name` / `/session`, `/back`
|
|
231
|
+
(files, context, or both), `/tree`, read-only `branch` / `resolve`, and
|
|
232
|
+
write branches in their own git worktree.
|
|
233
|
+
- Progress tracking counts new read observations and fresh successful checks.
|
|
234
|
+
Repeated content, renamed completion claims and gate regressions do not reset
|
|
235
|
+
the three-segment stop rule. This is an anti-stall heuristic, not proof of
|
|
236
|
+
relevance or completion; [`research M.4`](docs/agent-harness-research.md) states its limits.
|
|
237
|
+
- A terminal UI using the pinned Pi renderer, raw input, editor, autocomplete,
|
|
238
|
+
Markdown, searchable pickers and settings. Durable history is a pure log
|
|
239
|
+
projection across handoff boundaries. Includes tool diffs, historical folds,
|
|
240
|
+
Pi dark/light palettes, `keybindings.json`, `/settings` and `/hotkeys`.
|
|
241
|
+
- Context files: `AGENTS.md` / `CLAUDE.md` and the override chain, plus
|
|
242
|
+
`--system-prompt` / `--append-system-prompt` / `-nc`.
|
|
243
|
+
- Skills (`~/.xeno/skills/`, `/skill:name`) and prompt templates
|
|
244
|
+
(`~/.xeno/prompts/`, `/name`). Untrusted projects do not load the
|
|
245
|
+
project-level copies.
|
|
246
|
+
- `/login` for API keys and for Claude Pro/Max, Codex, and GitHub
|
|
247
|
+
Copilot subscription flows. See Known gaps.
|
|
248
|
+
|
|
249
|
+
## Known gaps
|
|
250
|
+
|
|
251
|
+
- **No sandbox.** See Isolation. That is a decision, not a missing feature.
|
|
252
|
+
- **Token counts are an estimate** (`chars/3.6`, labelled `kind: "estimate"`).
|
|
253
|
+
The provider `count_tokens` API is not wired. Boundaries therefore fire
|
|
254
|
+
on an approximation.
|
|
255
|
+
- **OAuth has not been run against a live authorization or token endpoint.**
|
|
256
|
+
The three flows exist and pass tests against an injected transport.
|
|
257
|
+
- **Tiered provider prices are stored as the base rate.** Example: the
|
|
258
|
+
catalog comment on `gpt-5.5-pro` notes a `context_over_200k` tier that
|
|
259
|
+
is not applied. `/usage` reports `{kind:"partial"}` when cache prices
|
|
260
|
+
are missing; it does not treat a missing cache price as zero.
|
|
261
|
+
- **No packages or extensions.** Skills and templates are files on disk.
|
|
262
|
+
There is no installer.
|
|
263
|
+
- **Bun only.** Node has not been tested.
|
|
264
|
+
- **`/back` does not restore symlinks.**
|
|
265
|
+
- **`.xeno/` is not collected.** Snapshots and abandoned session branches
|
|
266
|
+
stay until you delete them.
|
|
267
|
+
- **No telemetry, `/share`, auto-update, or `/compact`.** Those are
|
|
268
|
+
refusals (`docs/PI_PARITY.md` D15, D16), not backlog.
|
|
269
|
+
|
|
270
|
+
`docs/TUI_ARCHITECTURE.md` describes the active interaction path and verification.
|
|
271
|
+
`docs/PI_PARITY.md` records deliberate differences and remaining Pi features.
|
|
272
|
+
Pi's editor supports undo, not redo; an old `editor.redo` binding is diagnosed
|
|
273
|
+
as unsupported rather than silently accepted. Ctrl+- and the existing Ctrl+Z
|
|
274
|
+
alias invoke Pi undo.
|
|
275
|
+
|
|
276
|
+
## Why this shape
|
|
277
|
+
|
|
278
|
+
Three constraints, each of which rules out the obvious alternative.
|
|
279
|
+
|
|
280
|
+
**In-place eviction is the worst option under prefix caching.** Releasing tokens from
|
|
281
|
+
the middle of the context changes the prompt prefix, which invalidates the cached KV
|
|
282
|
+
state for everything after it. Under sustained pressure you pay the cache-write cost on
|
|
283
|
+
every request and never amortize it through reads — worse than compaction, which at
|
|
284
|
+
least produces one stable prefix per pass (this is the failure mode
|
|
285
|
+
[Beyond Compaction](https://arxiv.org/abs/2606.11213) documents). So token release must
|
|
286
|
+
be a rare, coarse event, not a continuous process. Hence segments.
|
|
287
|
+
|
|
288
|
+
**Summarization is unpredictably lossy, and the loss is undetectable from the result.**
|
|
289
|
+
What a summarizer keeps depends on its judgment of salience at that moment, which need
|
|
290
|
+
not match what the next segment needs — and you cannot tell from the compacted context
|
|
291
|
+
that anything is missing. Worse, the thing summarizers reliably drop is the record of
|
|
292
|
+
failed attempts, so the agent repeats them. Hence a deterministic projection plus a log
|
|
293
|
+
that is still on disk: a handoff that omits something is recoverable, because the agent
|
|
294
|
+
can go read it.
|
|
295
|
+
|
|
296
|
+
**A handoff that is only prose is autocompact with extra steps.** If the receiving agent
|
|
297
|
+
cannot interrogate what was compressed away, the structure bought nothing. The log
|
|
298
|
+
being intact is what makes the difference real rather than rhetorical.
|
|
299
|
+
|
|
300
|
+
## What is actually enforced
|
|
301
|
+
|
|
302
|
+
The interesting part is not the field list. It is that the harness — the only layer that
|
|
303
|
+
sees prompt assembly, tool mediation and lifecycle events together — can enforce a
|
|
304
|
+
contract the prompt cannot.
|
|
305
|
+
|
|
306
|
+
**A completion claim must cite a log event that exited zero.** The model calls a claim
|
|
307
|
+
tool naming a gate; `deriveHandoff` resolves that citation against command exit codes
|
|
308
|
+
recorded in the log. Unresolvable claims land in `state.unverified_claims` with a
|
|
309
|
+
reason. They are neither accepted nor silently dropped, and the rendered prompt says
|
|
310
|
+
they must be treated as not done.
|
|
311
|
+
|
|
312
|
+
This directly targets the "migration applied successfully" failure: a tool call returned
|
|
313
|
+
a nonzero exit code, nothing in the loop read it, and the model wrote a confident summary
|
|
314
|
+
of a result it never saw. Here the model's account of a result carries no weight at all.
|
|
315
|
+
|
|
316
|
+
Two related rules:
|
|
317
|
+
|
|
318
|
+
- **Claims resolve against evidence at or before the claim.** A later failing run does
|
|
319
|
+
not erase the recorded successful execution — appending an event must never
|
|
320
|
+
rewrite that observation. That the gate is red *now* is separate
|
|
321
|
+
information, carried by `verification` and repeated inline as `evidence_superseded`
|
|
322
|
+
so a reader of `completed` cannot miss it.
|
|
323
|
+
- **Evidence must come from the same segment.** A gate that passed three segments ago
|
|
324
|
+
is not proof about code that has changed since.
|
|
325
|
+
|
|
326
|
+
Other invariants (`src/core/handoff.ts`, `validateHandoff`): a `pass` status requires a
|
|
327
|
+
zero exit; every file anchor carries a digest; every handoff identifies its source
|
|
328
|
+
node and digest; a continuation is valid only with both remaining work and a concrete next
|
|
329
|
+
action. A property test asserts that `deriveHandoff` can never produce a handoff that
|
|
330
|
+
violates any of them.
|
|
331
|
+
|
|
332
|
+
**Append references, never copies.** A boundary event stores the id of the handoff it
|
|
333
|
+
produced and a ref to its predecessor — never the history it replaces. Codex CLI
|
|
334
|
+
re-embeds the full prior history into its rollout JSONL on every compaction, which is
|
|
335
|
+
quadratic on disk and has been reported at 42 GB
|
|
336
|
+
([openai/codex#41806](https://github.com/openai/codex/issues/41806)). The types here
|
|
337
|
+
cannot express recursive history copies. Full structured state can still grow as
|
|
338
|
+
new requirements, decisions and files accumulate. Handoff v2 carries a bounded
|
|
339
|
+
suffix of each section and records its immutable source and exact ranges. The
|
|
340
|
+
`history` tool rebuilds omitted pages from the log; no model summary is involved.
|
|
341
|
+
|
|
342
|
+
The carried-state budget is 5,000 estimated tokens. A 100-node deterministic
|
|
343
|
+
measurement grows the full state to about 14.7k while the carried view remains
|
|
344
|
+
at or below 5k. This bounds the prompt payload; it does not claim constant disk
|
|
345
|
+
space, replay time, or working memory for reconstructing the full history. The
|
|
346
|
+
objective stays verbatim: an objective that cannot fit is refused explicitly.
|
|
347
|
+
|
|
348
|
+
Session moves are committed to `metadata.jsonl`; `manifest.json` is a replaceable
|
|
349
|
+
index rebuilt from it. Sealed node digests are checked on resume and restore.
|
|
350
|
+
Interrupted tools receive an explicit unknown outcome instead of being run again.
|
|
351
|
+
Tool previews that exceed their display budget include a content-addressed
|
|
352
|
+
reference to the complete observation.
|
|
353
|
+
|
|
354
|
+
Command evidence includes the observed workspace digest when scanning succeeds.
|
|
355
|
+
Later edits mark old verification and completions as stale. A zero exit proves
|
|
356
|
+
the recorded command succeeded; it does not prove the model's description is an
|
|
357
|
+
adequate specification or that the test suite covers every requirement.
|
|
358
|
+
|
|
359
|
+
## Segment length
|
|
360
|
+
|
|
361
|
+
New sessions default to **windowed replay**: preserve the active dialogue until model
|
|
362
|
+
window pressure calls for a new projection. With an explicit model window, reserve
|
|
363
|
+
the configured output tokens, prepare at 70% of the remaining capacity and cut at
|
|
364
|
+
80%. These are conservative hypotheses, not measured optima. Unknown model capacity
|
|
365
|
+
uses the fixed segmented policy below; it is never treated as unlimited.
|
|
366
|
+
|
|
367
|
+
The explicit segmented policy retains **30k trigger / 40k hard**. Its historical cost model
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
per_turn(L) = 0.05*(H+L) + 1.25*d + 1.25*(H+R)*d/(L-H)
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
(cache reads at 0.1x, writes at 1.25x; `H` = handoff size, `d` = per-turn growth,
|
|
374
|
+
`R` = re-read cost after a boundary) was first evaluated with `H` *assumed* to be ~10k,
|
|
375
|
+
which put the optimum near 37k. The original single-segment measurement
|
|
376
|
+
(`prev=null`) gave the following historical figures:
|
|
377
|
+
|
|
378
|
+
| turns | segment L | handoff H | H/L |
|
|
379
|
+
|------:|----------:|----------:|----:|
|
|
380
|
+
| 10 | 4.8k | 366 | 7.6% |
|
|
381
|
+
| 50 | 25k | 986 | 3.9% |
|
|
382
|
+
| 200 | 99k | 2218 | 2.2% |
|
|
383
|
+
| 400 | 203k | 3201 | 1.6% |
|
|
384
|
+
|
|
385
|
+
Those samples do not establish a bound over a continuous session: deduplication
|
|
386
|
+
does not remove new, distinct facts. `bun run measure` now reports both this local
|
|
387
|
+
diagnostic and 100 consecutive derivations with retained state. The cost formula
|
|
388
|
+
models input caching at the stated rates; it omits task quality and cannot prove
|
|
389
|
+
30k/40k is globally optimal. These legacy bounds retain their 5k work floor.
|
|
390
|
+
|
|
391
|
+
`scripts/ab-suite.ts` now separates node, replay, round-preserving truncation and
|
|
392
|
+
observation masking. It uses a seeded shuffled schedule and includes output cost
|
|
393
|
+
and failed outcomes. Historical A/B figures predate these corrections and cannot
|
|
394
|
+
establish superiority over the corrected baselines. No new live-model result is
|
|
395
|
+
claimed until that experiment is run.
|
|
396
|
+
|
|
397
|
+
There is also a floor with a principled reason: **a handoff only pays for itself once a
|
|
398
|
+
segment's history exceeds the handoff.** Below that, replaying the history is cheaper —
|
|
399
|
+
`test/log.test.ts` pins both sides of that crossover.
|
|
400
|
+
|
|
401
|
+
## Layout
|
|
402
|
+
|
|
403
|
+
`SessionConfig.contextPolicy` and `--context-policy` select `windowed` (new-session
|
|
404
|
+
default), `segmented`, `continuous`, or the experimental `adaptive` policy. They
|
|
405
|
+
share the same durable log. Saved sessions keep their original policy, including
|
|
406
|
+
legacy logs without a policy, which resume as segmented. Explicit CLI `--trigger`
|
|
407
|
+
selects segmented unless `--context-policy` is also set. Continuous
|
|
408
|
+
keeps the dialogue until the provider window guard stops it; adaptive may defer a
|
|
409
|
+
soft cut when continuation state is missing or a conservative next-input cost
|
|
410
|
+
estimate favors keeping the cached prefix. It still obeys the hard boundary.
|
|
411
|
+
Windowed cuts keep a bounded recent suffix of complete exchanges alongside the
|
|
412
|
+
derived handoff, through event references rather than copied transcript bytes.
|
|
413
|
+
The replacement targets half the usable window and at most 20k recent-history
|
|
414
|
+
tokens; these are testable assumptions. New prompts are checked before dispatch.
|
|
415
|
+
If no useful replacement fits, the session stops explicitly. Retained events do
|
|
416
|
+
not count twice toward derived state, and model switches discard old thinking.
|
|
417
|
+
The segmented 30k/40k/5k values are unchanged. Missing working state gets one
|
|
418
|
+
append-only preparation notice before the boundary. These mechanisms do not
|
|
419
|
+
guarantee model compliance or lower whole-task costs; see research N.6.
|
|
420
|
+
|
|
421
|
+
New sessions also stop before another model call after 12 complete tool exchanges
|
|
422
|
+
without new observed evidence or fresh verification, with one warning halfway.
|
|
423
|
+
This watchdog is independent of context cuts and reconstructs from original log
|
|
424
|
+
events. `SessionConfig.stallLimit` accepts 0 to disable or an integer of at least 2;
|
|
425
|
+
old saved sessions without it retain their prior behavior. Novel content need not
|
|
426
|
+
be relevant, so this is a resource guard, not a task-success judge (research N.9).
|
|
427
|
+
|
|
428
|
+
Dependency direction is one-way, enforced mechanically by
|
|
429
|
+
`scripts/check-boundaries.ts`:
|
|
430
|
+
|
|
431
|
+
```
|
|
432
|
+
apps -> runtime -> store -> core
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Every path below was checked with `test -f` on this checkout.
|
|
436
|
+
|
|
437
|
+
| Layer | |
|
|
438
|
+
|---|---|
|
|
439
|
+
| **`src/core/`** | **pure**: no I/O, no clock, no randomness, no model call |
|
|
440
|
+
| `core/events.ts` | log event types; harness-derived vs model-annotated split |
|
|
441
|
+
| `core/handoff.ts` | handoff schema, YAML field order, `validateHandoff` invariants |
|
|
442
|
+
| `core/derive.ts` | `deriveHandoff` — events + previous handoff -> next handoff |
|
|
443
|
+
| `core/project.ts` | `projectContext` — log -> messages |
|
|
444
|
+
| `core/transcript.ts` / `file-references.ts` | pure human-history projection and explicit file references |
|
|
445
|
+
| `core/boundary.ts` | `shouldCut`, `shouldStopAndAsk` |
|
|
446
|
+
| `core/continuation.ts` / `history-query.ts` | append-only guidance and ancestry search contracts |
|
|
447
|
+
| `core/context-policy.ts` | windowed replay, legacy policies and conservative cache-cost estimates |
|
|
448
|
+
| `core/context-window.ts` | model-window budgets and exact recent-exchange retention |
|
|
449
|
+
| `core/data-query.ts` | deterministic parsing, filtering, grouping and aggregates |
|
|
450
|
+
| `core/yaml.ts` | restricted deterministic YAML emitter, no dependencies |
|
|
451
|
+
| `core/tokens.ts` | token counter interface; the bundled one is an estimate and says so |
|
|
452
|
+
| `core/permissions.ts` | `decide` / `selectTools` — pure rules; approval is a last look, not a boundary |
|
|
453
|
+
| `core/skills.ts` / `prompts.ts` / `frontmatter.ts` | skill text and `/name` templates |
|
|
454
|
+
| `core/settings.ts` / `theme.ts` / `keymap.ts` | settings merge, themes, bindings |
|
|
455
|
+
| `core/queue.ts` | steering / follow-up queue |
|
|
456
|
+
| **`src/store/`** | the only I/O: node JSONL, handoff files, manifest, blobs |
|
|
457
|
+
| `store/log.ts` / `sessions.ts` | node tree and `.xeno/sessions/<id>/` |
|
|
458
|
+
| `store/config.ts` | `~/.xeno/` paths; `auth.json` is 0600 |
|
|
459
|
+
| `store/search.ts` | grep / find / ls walk |
|
|
460
|
+
| `store/context-files.ts` | AGENTS.md discovery |
|
|
461
|
+
| **`src/runtime/`** | impure but thin; the only layer allowed npm packages |
|
|
462
|
+
| `runtime/provider.ts` / `openai.ts` | the two wire formats |
|
|
463
|
+
| `runtime/catalog.ts` / `model.ts` | 12 providers, 23 models |
|
|
464
|
+
| `runtime/tools.ts` / `history-tools.ts` | confined tools, complete query results and history retrieval |
|
|
465
|
+
| `runtime/benchmark.ts` | actual Session trials, bounded spending and cache diagnostics |
|
|
466
|
+
| `runtime/loop.ts` | orchestration; every judgement delegates to a pure function in core |
|
|
467
|
+
| `runtime/auth.ts` / `oauth.ts` | credential order and subscription flows |
|
|
468
|
+
| **`src/vendor/pi-tui/`** | unmodified Pi terminal and component library, pinned in `VENDOR.md` |
|
|
469
|
+
| **`src/tui/`** | Pi input, component and theme adapters; no harness imports |
|
|
470
|
+
| `tui/markdown.ts` / `toolview.ts` / `statusline.ts` / `tree.ts` | display |
|
|
471
|
+
| **`src/apps/`** | `cli.ts` — Pi main-screen UI for TTY, clean print/JSON output otherwise |
|
|
472
|
+
| `apps/startup.ts` / `shell.ts` / `commands.ts` | flags, session, slash commands |
|
|
473
|
+
|
|
474
|
+
## Properties the tests pin
|
|
475
|
+
|
|
476
|
+
- **Identity.** With no handoff, the projection is the identity mapping of harness
|
|
477
|
+
events onto messages. Segment 0 behaves exactly like a harness with no context
|
|
478
|
+
management, so nothing is paid for until a boundary actually fires.
|
|
479
|
+
- **Prefix stability.** Appending an event only appends to the projection; it never
|
|
480
|
+
rewrites an earlier message. This pins prefix stability; actual cache hits
|
|
481
|
+
remain provider-dependent.
|
|
482
|
+
- **Purity.** Identical inputs produce byte-identical YAML. `deriveHandoff` mutates
|
|
483
|
+
neither its inputs nor the previous handoff.
|
|
484
|
+
- **Nothing silently dropped.** Every claim appears in exactly one of `completed` or
|
|
485
|
+
`unverified_claims`; state buckets are pairwise disjoint; accumulated state is
|
|
486
|
+
monotonic across segments.
|
|
487
|
+
- **No history copies.** Tool output is referenced rather than recursively embedded.
|
|
488
|
+
The carried handoff is budgeted; full structured state remains reconstructible.
|
|
489
|
+
- **YAML round-trips.** Emit -> parse -> re-emit is byte-identical, verified against a
|
|
490
|
+
real parser, with an idempotency gate and golden snapshots.
|
|
491
|
+
|
|
492
|
+
```
|
|
493
|
+
bun run gate # bun test + tsc --noEmit + the boundary checks
|
|
494
|
+
bun run measure # the segment-length measurement
|
|
495
|
+
bun run regen-golden # regenerate snapshots, then read the diff
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
Design notes: `docs/agent-harness-research.md`.
|
package/docs/install.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Install xeno
|
|
2
|
+
|
|
3
|
+
Published as `@visual-z/xeno`. The license is `UNLICENSED`: the package is
|
|
4
|
+
public to read and install, and no right to reuse the code is granted.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm i -g @visual-z/xeno # or: bun add -g @visual-z/xeno
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
The installed `xeno` still runs with Bun (below). Installing from a
|
|
11
|
+
checkout works the same way and is described after it.
|
|
12
|
+
|
|
13
|
+
## Bun, not Node
|
|
14
|
+
|
|
15
|
+
The entry point is `src/apps/cli.ts` with `#!/usr/bin/env bun`. The
|
|
16
|
+
process uses Bun APIs (`Bun.file`, `Bun.spawn`, `Bun.spawnSync`,
|
|
17
|
+
`for await (const line of console)`). Those are why the runtime is Bun.
|
|
18
|
+
|
|
19
|
+
`engines.bun` is `>=1.1.0`. This checkout was run on **Bun 1.3.10**.
|
|
20
|
+
Node is untested. That is a fact about this tree, not a promise that
|
|
21
|
+
Node support is coming.
|
|
22
|
+
|
|
23
|
+
Install Bun from https://bun.sh.
|
|
24
|
+
|
|
25
|
+
## From a checkout
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone <this-repo> xeno
|
|
29
|
+
cd xeno
|
|
30
|
+
bun install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`bun install` pulls the one runtime dependency (`@anthropic-ai/sdk`)
|
|
34
|
+
and the TypeScript dev tooling.
|
|
35
|
+
|
|
36
|
+
Run the CLI without linking:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bun src/apps/cli.ts --help
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Or put `xeno` on your PATH from this checkout:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
bun link
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then, in any directory:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
xeno --help
|
|
52
|
+
xeno --list-models
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`bun link` writes a shim that executes the `bin` field
|
|
56
|
+
(`src/apps/cli.ts`) with Bun. It does not copy the tree.
|
|
57
|
+
|
|
58
|
+
A workspace that already has a session is resumed. `--fresh` starts a
|
|
59
|
+
new session beside it; nothing is deleted.
|
|
60
|
+
|
|
61
|
+
## Credentials
|
|
62
|
+
|
|
63
|
+
Resolution order, first match wins:
|
|
64
|
+
|
|
65
|
+
1. `--api-key`
|
|
66
|
+
2. `~/.xeno/auth.json` (created `0600` by `/login`)
|
|
67
|
+
3. the provider's environment variable
|
|
68
|
+
|
|
69
|
+
A stored entry owns that provider. The environment is not a fallback
|
|
70
|
+
after a stored key fails.
|
|
71
|
+
|
|
72
|
+
| Provider | Environment variable |
|
|
73
|
+
|-------------|-----------------------------------------------------------|
|
|
74
|
+
| anthropic | `ANTHROPIC_API_KEY` |
|
|
75
|
+
| openai | `OPENAI_API_KEY` |
|
|
76
|
+
| google | `GOOGLE_API_KEY` or `GOOGLE_GENERATIVE_AI_API_KEY` or `GEMINI_API_KEY` |
|
|
77
|
+
| deepseek | `DEEPSEEK_API_KEY` |
|
|
78
|
+
| xai | `XAI_API_KEY` |
|
|
79
|
+
| groq | `GROQ_API_KEY` |
|
|
80
|
+
| cerebras | `CEREBRAS_API_KEY` |
|
|
81
|
+
| mistral | `MISTRAL_API_KEY` |
|
|
82
|
+
| openrouter | `OPENROUTER_API_KEY` |
|
|
83
|
+
| zai | `ZHIPU_API_KEY` |
|
|
84
|
+
| moonshotai | `MOONSHOT_API_KEY` |
|
|
85
|
+
| together | `TOGETHER_API_KEY` |
|
|
86
|
+
|
|
87
|
+
Interactive: export one of those, or run `/login <provider>`.
|
|
88
|
+
`-p` / no tty: pass `--api-key` or export the variable. `/login` is
|
|
89
|
+
not a script path.
|
|
90
|
+
|
|
91
|
+
`/login claude-pro`, `/login codex`, and `/login github-copilot` start
|
|
92
|
+
subscription flows (authorization-code + PKCE, or a device code for
|
|
93
|
+
Copilot). They use first-party client credentials; the terms-of-service
|
|
94
|
+
risk is on your account. Those flows have been tested against injected
|
|
95
|
+
transports, not against a live authorization endpoint.
|
|
96
|
+
|
|
97
|
+
## What a run writes
|
|
98
|
+
|
|
99
|
+
In the **workspace**:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
.xeno/sessions/<id>/ node-NNNN.jsonl, handoff-NNNN.yaml, manifest
|
|
103
|
+
.xeno/blobs/ content-addressed snapshots for /back
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
That directory grows. There is no garbage collection.
|
|
107
|
+
|
|
108
|
+
In **your home directory** (`~/.xeno/`, or `$XENO_CONFIG_DIR`):
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
auth.json credentials (0600)
|
|
112
|
+
settings.json theme, thinking, defaults
|
|
113
|
+
trust.json which directories may load project settings
|
|
114
|
+
models.json optional catalog overlay (written by `xeno models --refresh`)
|
|
115
|
+
keybindings.json optional
|
|
116
|
+
prompts/ skills/ optional
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
A leftover `.xeno/log` from before named sessions is not moved. Continue
|
|
120
|
+
it with `--log .xeno/log`.
|
|
121
|
+
|
|
122
|
+
Add this to the project's `.gitignore`:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
.xeno/
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Untrusted work
|
|
129
|
+
|
|
130
|
+
There is no sandbox. See the Isolation section in `README.md`.
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@visual-z/xeno",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "UNLICENSED",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Segmented append-only agent log with pure context and handoff projections",
|
|
7
|
+
"bin": {
|
|
8
|
+
"xeno": "src/apps/cli.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"README.md",
|
|
13
|
+
"docs/install.md"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"bun": ">=1.1.0"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"test": "bun test",
|
|
23
|
+
"typecheck": "bun run scripts/typecheck.ts",
|
|
24
|
+
"check": "bun run scripts/check-boundaries.ts",
|
|
25
|
+
"gate": "bun test && bun run typecheck && bun run scripts/check-boundaries.ts",
|
|
26
|
+
"verify-red": "bun run scripts/verify-red.ts",
|
|
27
|
+
"regen-golden": "bun run scripts/regen-golden.ts",
|
|
28
|
+
"measure": "bun run scripts/measure-handoff.ts",
|
|
29
|
+
"agent": "bun run src/apps/cli.ts"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typescript": "^5.7.0",
|
|
33
|
+
"@types/bun": "latest"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@anthropic-ai/sdk": "^0.127.0",
|
|
37
|
+
"get-east-asian-width": "1.6.0",
|
|
38
|
+
"marked": "18.0.11"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
43
|
+
}
|