Implementation prompt: Spectra 0.1
This is the prompt to hand to the implementing agent (Opus 5.5) to start Spectra. Paste everything below the line.
You are implementing Spectra, an agentic control plane in Rust, from its specification. You are working for Andy, in ~/development/spectra, which is an Oxygen repository (not Git). Read these before writing any code, in this order:
~/development/spectra/docs/spec.md, Draft 0.3, the whole thing. It is the source of truth. Where it says MUST, do that; where it is silent, follow Oxygen.~/development/oxygen/: the project Spectra must feel identical to. ReadREADME.md,Cargo.toml,Makefile,build.rs,scripts/changelog-check.sh,.flow/pipeline.kdl,.oxyignore,.oxyattributes,CHANGELOG.md(the first 60 lines),docs/plan.md,src/main.rs,src/cli/mod.rs,src/cli/ui.rs,src/cli/json.rs,crates/oxy-core/src/mcp.rs,crates/oxy-core/src/identity.rs(identities, delegates, composite signatures,sign_challenge), the deterministic CBOR encoding inoxy-core,docs/ai_native_agent_workflows.md§2, andtests/cli_json.rsandtests/cli_mcp.rs.~/development/oxygenhub/:Makefile,rustfmt.toml,crates/hub/src/{main.rs,config.rs,bus.rs,live.rs},crates/hub/src/db/, one template undertemplates/andtemplates/base.html, and one test undercrates/hub/tests/. The hub is the reference for axum, sqlx, askama, the event bus, SSE and the test harness that starts a server on a loopback port.
The one rule about shape
If it looks like something in Oxygen, it must look the same in Spectra. A developer who moves from oxygen or oxygenhub to spectra must find every file where they expect it, with the same name, the same targets, the same flags and the same conventions. When you are about to invent a file, a target, a flag, a directory, a test helper or an output format, first look for how Oxygen does it and copy that. Concretely:
| In Oxygen | In Spectra |
|---|---|
Cargo.toml workspace with [workspace.package] (version, edition 2021, license MIT OR Apache-2.0), members crates/* and ., the binary package at the root with src/main.rs, default-run, mimalloc, clap derive, clap_complete, clap_mangen | The same, package spectra, binary spectra, version 0.1.0, members crates/spectra-core, crates/spectra-mcp, crates/spectra-api, crates/radar, . |
crates/oxy-core (library, no CLI concerns) | crates/spectra-core, which depends on oxy-core (by path during development, pinned as a subrepo under deps/ as the hub pins its dependencies) for identities, signatures, deterministic CBOR and hashing. Never reimplement those |
oxy-core::mcp (hand-rolled JSON-RPC 2.0, Tool, ToolOutput, PROTOCOL_VERSIONS, nothing on stdout but protocol) | crates/spectra-mcp starts from a copy of that module's shape and adds the stateless Streamable HTTP endpoint and server/discover (spec §15.1); keep the names Tool, ToolOutput, read_only, destructive |
src/cli/mod.rs (clap tree), src/cli/ui.rs (colour, glyphs, spinners, --plain, NO_COLOR, non-TTY detection), src/cli/json.rs (--json printing one document) | Copy ui.rs and json.rs as they are, with the names changed; every listing command takes --json and --plain exactly as oxy does |
build.rs and OXY_BUILD (the build identity from oxy describe in --version) | build.rs and SPECTRA_BUILD, the same mechanism; spectra version --json as oxy version --json |
Makefile | The targets of oxygenhub's Makefile (build, check: changelog fmt clippy test, changelog, fmt, clippy, test, run, ts) plus oxygen's install target (release build with the build identity, symlink into ~/.local/bin, print --version). run is cargo run -- --data data serve. ts writes crates/spectra-api/ts/index.d.ts the way hub-api does |
scripts/changelog-check.sh | Copy verbatim |
scripts/dist.sh | Copy and adapt the names; the artifact list is spectra-<os>-<arch>.tar.gz, spectra_<arch>.deb, spectra-src.tar.gz, SHA256SUMS |
.flow/pipeline.kdl, .flow/warm-target.sh | Copy; the jobs are fmt, clippy, test (nextest with llvm-cov, junit and coverage artifacts), build, dist; s/oxy/spectra/; keep the sandbox definitions and the comments explaining them; drop riscv64 for now |
rustfmt.toml (oxygenhub's: max_width = 140, use_small_heuristics = "Max") | Copy |
.oxyignore (/target, *.tmp, /.claude), .oxyattributes (CHANGELOG.md merge=union with its comment) | Copy |
LICENSE (MIT or Apache-2.0 at your option, both texts) | Copy with the names changed |
CHANGELOG.md: ## Unreleased at the top, one bold line per change (**Added:/Changed/Fixed/Security), the issue number, versions change only at release | The same; your first entries go under ## Unreleased |
README.md: one-paragraph description linking docs/spec.md, Status, Install (later), Building, Quick start, Layout table, Licence | The same sections; the existing README.md is the start of it |
docs/plan.md: the overnight loop ("pick the first unchecked item, implement with tests, run the gated checks, commit with oxy, tick the box with a one-line note, commit again"), a Rules section, Items as checkboxes, a Log | Create it with the 0.1 items from this prompt, and work the loop |
tests/cli_*.rs: integration tests that run the built binary against a scratch directory, hermetic (OXY_HOME), never touching ~/.config | tests/cli_*.rs with SPECTRA_DATA pointing at a temp directory; a hermetic() helper with the same name and shape |
oxygenhub crates/hub/tests/*.rs: start the server on a loopback port, drive it with a real client, fetch pages | crates/radar and crates/spectra-mcp tests do the same: start spectra serve in-process on a temporary socket and port 0, call tools over the socket with signed requests, fetch pages |
oxy output: colour and glyphs on a UTF-8 terminal, plain when piped, --plain, NO_COLOR; errors on stderr, non-zero exit; --json is one document on stdout and nothing else | Identical |
| Doc comments: a module comment at the top of every file saying what it is and why, in prose, with the issue or spec section in brackets | Identical; cite spec sections as (spec §14.1) |
Where Oxygen has no counterpart (the event log, tasks, rules, Radar's pages), follow the spec and the hub's idioms (sqlx migrations under migrations/, one module per table group under db/, askama templates under templates/ with base.html, the stylesheet compiled in, the bus in bus.rs, SSE in live.rs).
Rules (as in oxygen/docs/plan.md)
- Never run
git inithere and never push this project anywhere but itsoxygenhubremote. The repository is tracked withoxy; commit withoxy commit -m "..." PATHS..(name the paths, asoxy mcpmakes you). Readoxygen/docs/mcp.mdif you useoxy mcp. - Tests are hermetic. Nothing touches
~/.local/share/spectra,~/.configor the network. Every test uses a temporary data directory and port 0. - Gate every commit on
make check: the changelog check,cargo fmt --all -- --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test --workspace. A commit that fails the gate does not happen. - Every code change adds a CHANGELOG.md line under
## Unreleased, or setsNO_CHANGELOG=1for a change users will not notice. - The spec is updated when behaviour the spec describes changes, with a line in its §27 changelog and a Draft bump. If the spec is wrong or ambiguous, make the smallest decision that keeps it consistent, record it in §26 or the changelog, and carry on; do not stop to ask unless the decision would change the data model.
- No new external services, no publishing, no front-end build, no JavaScript framework. Radar is askama plus one hand-written stylesheet plus a small vendored script, as the hub.
- Dependencies: prefer what Oxygen and OxygenHub already use (
tokio,axum,axum-server,sqlxwith SQLite,askama,serde,serde_json,blake3,rand,clap,console,indicatif,tracing,pulldown-cmark,ammonia,reqwestin tests). Add a crate only when nothing in that set does the job;ulidandcronare expected additions. Pin versions the way the two workspaces do.
What to build: milestone 0.1, "Talk"
From spec §25, 0.1 is done when: Claude Code in oxygen and Antigravity in oxygenhub each call brief, post in #general, and see each other's messages via wait within a second; the owner watches it on Live. Work in this order, one plan item per iteration, each with tests, the gate, and an oxy commit:
- Skeleton. The workspace, crates,
Makefile, scripts,.flow,rustfmt.toml,.oxyignore,.oxyattributes,LICENSE,CHANGELOG.md,docs/plan.md,build.rs;spectra version [--json]andspectra --helpwork;make checkpasses on an empty project. Commit. - The ledger (spec §9, §9.5):
spectra-core::storeopens<data>/spectra.db(WAL,synchronous=NORMAL, foreign keys), applies migrations, appends events in one transaction with gap-freeseq, ULIDid,at_ms,hlc(hybrid logical clock with the five-minute drift bound),prev,hash(deterministic CBOR throughoxy-core, domain-separated BLAKE3) andauth, and publishes to the bus after commit. Checkpoints signed by the instance key every 256 events and ten minutes.spectra admin verifyrecomputes the chain and every proof from the ledger alone. The envelope is frozen: write the test that asserts its field set, and the test that an edited row breaks verification.spectra admin checkandadmin rebuild. - Principals (§8):
spectra initreads the owner's identity from theirOXY_HOMEand makes the instance identity;spectra agent add --home DIRmakes the agent's key pair in its own home and refuses to finish until the owner's identity delegates to it; ownership shown everywhere asNAME · OWNER's agent; expiry and revocation honoured from the delegation;spectra agent list|disable;spectra project add|listreading.oxy/and.oxymodules; presence as a projection; sessions. - Channels and messages (§10):
#general,#humans,#system, one per project, direct on first use; messages with kinds, threads, mentions, refs, the 64 KiB limits, redaction; theinboxprojection; FTS5 on messages. - Tuner over HTTP (§15.1, §15.2):
POST /mcpspeaking 2026-07-28 (headers validated,server/discover,subscriptions/listen,ttlMson lists, deterministic tool order, no sessions) and 2025-11-25 (initializeaccepted); the Unix socket with peer credentials and signed requests (Spectra-Key,Spectra-Time,Spectra-Nonce,Spectra-Signature) verified against the ledger's identities and delegations, the assurance level on every event (§8.5), bearer tokens only behind[security] allow_tokens; toolsbrief,rules(site layer only),agents,status,say,read,inbox,wait,ack,search,redact, with the_metafields, the rules-version line, the idle-waitguard (§14.1) andtool.calledevents. Test every tool over the socket with signed requests; fuzz the JSON-RPC parser with random and mutated bodies (as oxygen's CBOR tests do) and assert it never panics. - The stdio shim (§15.1):
spectra mcp --agent NAME, signing each forwarded request with the agent's key from its home and forwarding over the socket;tests/cli_mcp.rsdrives it over pipes as oxygen's does. - Radar (§17):
base.html, the stylesheet (start from oxygenhub'stemplates/style.csstokens and the GitHub-like look; Spectra's mark inassets/icons/spectra.svg), the Live (with each agent's owner), Channels, thread and Log pages (the Log with each event's hash and proof, and the head's hash and last verification at the top), the owner's level-2 sign-in through the--openone-time link signed by the CLI key (§8.3; the passkey is 0.2), with its banner, CSRF, CSP,Originvalidation, and/api/v1/events?follow=1as the SSE stream with the pages re-fetching fragments. Every page renders without JavaScript. - JSON API (§18) for what exists:
/brief,/agents,/projects,/channels,/channels/{name}/messages,/threads/{id},/inbox,/search,/events,/health,/version;spectra-apitypes withserdeand JSON Schema derives;make ts. - CLI for the human (§19):
spectra say,spectra inbox [--follow],spectra search, each signing with the owner's key fromOXY_HOME, with--jsonand--plain. - Docs: README sections filled in,
docs/plan.mdticked with notes and timings, spec §27 bumped for anything you changed,CHANGELOG.mdunder## Unreleased. Then run the 0.1 acceptance test by hand against two real clients and record the result inplan.md's Log.
Not in 0.1: the passkey and the assurance policy (0.2), committed rules and ref.verified (0.3), checkpoints into OxygenHub's transparency log (0.5), tasks, claims, decisions, rule layers beyond site.md, hooks, spectra trigger, the channel shim, schedules, webhooks, the uplink, SpectraHub, the extensions. Do not start them; leave the modules' names in place as empty files with a comment only if a 0.1 piece needs a seam.
Quality bar
cargo clippy --workspace --all-targets -- -D warningsclean;cargo fmtclean; every public function inspectra-corehas a doc comment.- Tests: unit tests beside the code; integration tests under
tests/and each crate'stests/; the projection-equality test (append a random mix of events, rebuild, compare every table) runs after every scenario; a server test per tool; a page test per Radar page. - Performance targets of spec §24 for what exists: measure
briefandsaywith a thousand events and record the numbers inplan.md's Log, as oxygen's plan records its benchmarks. - Output and errors read like
oxy's: short, declarative, naming the thing and what to do.
How to work
Work the loop in docs/plan.md exactly as oxygen's: one unchecked item per iteration; implement with tests; make check; oxy commit naming the paths; tick the item with a one-line note and the time; commit again; append a Log line. If an item cannot be finished in two iterations, note why under it and move on. Write the plan first, as the first commit of the skeleton, and keep it honest.
Never weaken what §5 promises to make a test pass: if a security rule in the spec is impractical, stop and say so rather than skip it.
When done with 0.1, stop and report: what is built, what the acceptance test showed, every decision you recorded in the spec, and the measured numbers.