OXYGENHUB
# b576d05cf862 spectra / docs / implementation-prompt.md
14.5 KiB · Markdown · last changed Specification Draft 0.3 and the implementation prompt 2 days ago renderedsource blame history raw

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:

  1. ~/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.
  2. ~/development/oxygen/: the project Spectra must feel identical to. Read README.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 in oxy-core, docs/ai_native_agent_workflows.md §2, and tests/cli_json.rs and tests/cli_mcp.rs.
  3. ~/development/oxygenhub/: Makefile, rustfmt.toml, crates/hub/src/{main.rs,config.rs,bus.rs,live.rs}, crates/hub/src/db/, one template under templates/ and templates/base.html, and one test under crates/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 OxygenIn 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_mangenThe 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
MakefileThe 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.shCopy verbatim
scripts/dist.shCopy 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.shCopy; 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 releaseThe same; your first entries go under ## Unreleased
README.md: one-paragraph description linking docs/spec.md, Status, Install (later), Building, Quick start, Layout table, LicenceThe 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 LogCreate 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 ~/.configtests/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 pagescrates/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 elseIdentical
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 bracketsIdentical; 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 init here and never push this project anywhere but its oxygenhub remote. The repository is tracked with oxy; commit with oxy commit -m "..." PATHS.. (name the paths, as oxy mcp makes you). Read oxygen/docs/mcp.md if you use oxy mcp.
  • Tests are hermetic. Nothing touches ~/.local/share/spectra, ~/.config or 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 sets NO_CHANGELOG=1 for 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, sqlx with SQLite, askama, serde, serde_json, blake3, rand, clap, console, indicatif, tracing, pulldown-cmark, ammonia, reqwest in tests). Add a crate only when nothing in that set does the job; ulid and cron are 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:

  1. Skeleton. The workspace, crates, Makefile, scripts, .flow, rustfmt.toml, .oxyignore, .oxyattributes, LICENSE, CHANGELOG.md, docs/plan.md, build.rs; spectra version [--json] and spectra --help work; make check passes on an empty project. Commit.
  2. The ledger (spec §9, §9.5): spectra-core::store opens <data>/spectra.db (WAL, synchronous=NORMAL, foreign keys), applies migrations, appends events in one transaction with gap-free seq, ULID id, at_ms, hlc (hybrid logical clock with the five-minute drift bound), prev, hash (deterministic CBOR through oxy-core, domain-separated BLAKE3) and auth, and publishes to the bus after commit. Checkpoints signed by the instance key every 256 events and ten minutes. spectra admin verify recomputes 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 check and admin rebuild.
  3. Principals (§8): spectra init reads the owner's identity from their OXY_HOME and makes the instance identity; spectra agent add --home DIR makes the agent's key pair in its own home and refuses to finish until the owner's identity delegates to it; ownership shown everywhere as NAME · OWNER's agent; expiry and revocation honoured from the delegation; spectra agent list|disable; spectra project add|list reading .oxy/ and .oxymodules; presence as a projection; sessions.
  4. 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; the inbox projection; FTS5 on messages.
  5. Tuner over HTTP (§15.1, §15.2): POST /mcp speaking 2026-07-28 (headers validated, server/discover, subscriptions/listen, ttlMs on lists, deterministic tool order, no sessions) and 2025-11-25 (initialize accepted); 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; tools brief, rules (site layer only), agents, status, say, read, inbox, wait, ack, search, redact, with the _meta fields, the rules-version line, the idle-wait guard (§14.1) and tool.called events. 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.
  6. 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.rs drives it over pipes as oxygen's does.
  7. Radar (§17): base.html, the stylesheet (start from oxygenhub's templates/style.css tokens and the GitHub-like look; Spectra's mark in assets/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 --open one-time link signed by the CLI key (§8.3; the passkey is 0.2), with its banner, CSRF, CSP, Origin validation, and /api/v1/events?follow=1 as the SSE stream with the pages re-fetching fragments. Every page renders without JavaScript.
  8. JSON API (§18) for what exists: /brief, /agents, /projects, /channels, /channels/{name}/messages, /threads/{id}, /inbox, /search, /events, /health, /version; spectra-api types with serde and JSON Schema derives; make ts.
  9. CLI for the human (§19): spectra say, spectra inbox [--follow], spectra search, each signing with the owner's key from OXY_HOME, with --json and --plain.
  10. Docs: README sections filled in, docs/plan.md ticked with notes and timings, spec §27 bumped for anything you changed, CHANGELOG.md under ## Unreleased. Then run the 0.1 acceptance test by hand against two real clients and record the result in plan.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 warnings clean; cargo fmt clean; every public function in spectra-core has a doc comment.
  • Tests: unit tests beside the code; integration tests under tests/ and each crate's tests/; 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 brief and say with a thousand events and record the numbers in plan.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.