v0 plan: AGENTS.md, gate, five task files with given tests, run-plan driver
Tests were run against a private reference implementation: gate ok after every task in order, smoke ok (stream spread ~1000 ms). The reference is not in the repository. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# v0 task 05: the smoke run, README and systemd unit
|
||||
|
||||
**Branch:** `v0` (run `git switch v0`; `git status --short` must be empty, otherwise stop)
|
||||
**Commit subject:** `Add the smoke run, README and systemd unit`
|
||||
|
||||
## Goal
|
||||
|
||||
Prove the whole binary works over real HTTP against two fake upstreams — routing, failover,
|
||||
recovery, streaming — with the given `tools/smoke.sh`, then document how to build, configure,
|
||||
run and point clients at crossbar.
|
||||
|
||||
## Context
|
||||
|
||||
`tools/smoke.sh` starts two `fakeupstream`s on `127.0.0.1:18081/18082` and `bin/crossbar` on
|
||||
`example.toml` (`poll_interval = "1s"`), then checks with `curl`: `opencode-a` goes to `alpha`
|
||||
and `hermes-x` to `beta`; an unknown route is 404; after `alpha` is taken down (its `-down-file`
|
||||
appears) requests fail over to `beta` and `/_crossbar/hosts` shows `alpha` unhealthy; after two
|
||||
good polls `alpha` is back; a streamed completion of five chunks 200 ms apart reaches the client
|
||||
spread over at least 600 ms, not in one burst; and crossbar wrote a request log line. It prints
|
||||
`smoke: ok (stream spread N ms)` or fails with the crossbar log.
|
||||
|
||||
## Files
|
||||
|
||||
- Copy (never edit): `tools/smoke.sh`
|
||||
- Create: `README.md`, `deploy/crossbar.service`
|
||||
- Modify: `docs/implementer-log.md`
|
||||
|
||||
## Steps
|
||||
|
||||
- [ ] **1. Copy and run the smoke test.**
|
||||
|
||||
```sh
|
||||
git switch v0
|
||||
mkdir -p tools deploy
|
||||
cp docs/plans/v0/files/tools/smoke.sh tools/
|
||||
make smoke
|
||||
```
|
||||
|
||||
Expected last line: `smoke: ok (stream spread N ms)` with N ≥ 600. If it fails, the message says
|
||||
which check failed and prints crossbar's log; the fault is in code from tasks 02–04 or in this
|
||||
machine's `curl`. Fix code only if a rule from an earlier task was broken; otherwise stop and
|
||||
report.
|
||||
|
||||
- [ ] **2. Write `deploy/crossbar.service`** with exactly this content:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=crossbar affinity router for llama-server
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/crossbar -config /etc/crossbar/crossbar.toml
|
||||
Restart=on-failure
|
||||
RestartSec=2s
|
||||
DynamicUser=yes
|
||||
StateDirectory=crossbar
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
PrivateTmp=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
- [ ] **3. Write `README.md`** with these sections, in this order, in plain prose (no
|
||||
hostnames, addresses or tokens other than the placeholders shown):
|
||||
1. `# crossbar` — two sentences: an affinity router in front of several `llama-server`
|
||||
routers; a client's identity is the first path segment of its base URL; v0 routes each
|
||||
to the first healthy host on that route's list and streams answers unbuffered.
|
||||
2. `## Build` — `make build` (binaries in `bin/`), `make gate`, `make smoke`.
|
||||
3. `## Configure` — paste `example.toml` in a fenced block and explain each key in a table:
|
||||
`listen` (a tailnet address, never `0.0.0.0`), `poll_interval` (60s in production),
|
||||
`queue_max` (reserved for v1), `hosts.<name>.base_url|weight|models`, `routes.<name>.hosts`
|
||||
(preference order) and `default_model`.
|
||||
4. `## Run` — copy `bin/crossbar` to `/usr/local/bin/`, the config to
|
||||
`/etc/crossbar/crossbar.toml`, the unit to `/etc/systemd/system/`, then
|
||||
`systemctl enable --now crossbar`.
|
||||
5. `## Point clients at it` — these two snippets verbatim:
|
||||
|
||||
OpenCode, one provider for every project; each instance is launched as
|
||||
`CROSSBAR_ROUTE="$(basename "$PWD")-$$" opencode`:
|
||||
```jsonc
|
||||
"provider": { "crossbar": { "npm": "@ai-sdk/openai-compatible",
|
||||
"options": { "baseURL": "http://crossbar.<tailnet>:7777/{env:CROSSBAR_ROUTE}/v1" },
|
||||
"models": { "ornith-1.5-35b-a3b": {} } } }
|
||||
```
|
||||
Hermes, in `config.yaml`:
|
||||
```yaml
|
||||
custom_providers:
|
||||
- name: crossbar
|
||||
base_url: http://crossbar.<tailnet>:7777/hermes-<agent>/v1
|
||||
models: { ornith-1.5-35b-a3b: {} }
|
||||
```
|
||||
Note under them: the route name in the URL must exist in `[routes]`; unknown routes are 404.
|
||||
6. `## Inspect` — `GET /_crossbar/hosts` and `GET /_crossbar/routes`, one example response each
|
||||
(take them from the smoke run).
|
||||
7. `## What v0 does not do` — leases and stickiness, SQLite, `/slots`, queueing, wake-on-LAN:
|
||||
see `PLAN.md`.
|
||||
|
||||
- [ ] **4. Run the gate.** `make gate`. Expected last line: `gate: ok`.
|
||||
- [ ] **5. Log and commit.** Row `v0/05-smoke-readme-deploy`; put the smoke line (`smoke: ok
|
||||
(stream spread N ms)`) in the Notes column.
|
||||
|
||||
```sh
|
||||
git add tools/smoke.sh README.md deploy/crossbar.service docs/implementer-log.md
|
||||
git commit
|
||||
```
|
||||
|
||||
## Done when
|
||||
|
||||
- `make smoke` prints `smoke: ok (…)`; `make gate` prints `gate: ok`; `README.md` has the seven
|
||||
sections; `cmp tools/smoke.sh docs/plans/v0/files/tools/smoke.sh` prints nothing.
|
||||
|
||||
## Stop and report if
|
||||
|
||||
- `make smoke` fails twice in the same way.
|
||||
Reference in New Issue
Block a user