Compare main … develop
0 changes in develop not in main; 1 the other way. 1 file differ between the two states.
removed docs/spec.md +0 −251
| 1 | - | # SpectraHub — Specification |
|
| 2 | - | ||
| 3 | - | | | | |
|
| 4 | - | |---|---| |
|
| 5 | - | | **Status** | Draft 0.5 | |
|
| 6 | - | | **Date** | 2026-11-03 | |
|
| 7 | - | | **Scope** | The hosted layer over Spectra: many Spectras on many machines, owned by many people, uplinked to one place with accounts, organisations, a shared archive, cross-machine routing between agents, the website over all of it, and the API the Android app and the VS Code extension use. It depends on nothing but Spectra. | |
|
| 8 | - | | **Depends on** | `spectra-core` and `spectra-api` from the Spectra workspace (spec Draft 0.7); Spectras speaking the uplink protocol of §4 | |
|
| 9 | - | | **Companion documents** | `../spectra/docs/spec.md` (the control plane this hosts), `../spectrahub-vscode/docs/spec.md`, the Android app (later) | |
|
| 10 | - | | **Audience** | Implementers, security reviewers, and the person who runs it | |
|
| 11 | - | ||
| 12 | - | The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119. |
|
| 13 | - | ||
| 14 | - | --- |
|
| 15 | - | ||
| 16 | - | ## Table of contents |
|
| 17 | - | ||
| 18 | - | 1. [Goals and non-goals](#1-goals-and-non-goals) |
|
| 19 | - | 2. [Do we need a Hub at all](#2-do-we-need-a-hub-at-all) |
|
| 20 | - | 3. [Architecture](#3-architecture) |
|
| 21 | - | 4. [Uplink: a Spectra joins a hub](#4-uplink-a-spectra-joins-a-hub) |
|
| 22 | - | 5. [Accounts, organisations and authorization](#5-accounts-organisations-and-authorization) |
|
| 23 | - | 6. [The merged log](#6-the-merged-log) |
|
| 24 | - | 7. [Routing between Spectras](#7-routing-between-spectras) |
|
| 25 | - | 8. [Web interface](#8-web-interface) |
|
| 26 | - | 9. [Relay: phones and chat bridges](#9-relay-phones-and-chat-bridges) |
|
| 27 | - | 10. [Notifications](#10-notifications) |
|
| 28 | - | 11. [Search and the archive](#11-search-and-the-archive) |
|
| 29 | - | 12. [HTTP API and webhooks](#12-http-api-and-webhooks) |
|
| 30 | - | 13. [Integrations](#13-integrations) |
|
| 31 | - | 14. [Security](#14-security) |
|
| 32 | - | 15. [Operations](#15-operations) |
|
| 33 | - | 16. [Required changes to Spectra](#16-required-changes-to-spectra) |
|
| 34 | - | 17. [Milestones](#17-milestones) |
|
| 35 | - | 18. [Open questions](#18-open-questions) |
|
| 36 | - | 19. [Changelog](#19-changelog) |
|
| 37 | - | ||
| 38 | - | --- |
|
| 39 | - | ||
| 40 | - | ## 1. Goals and non-goals |
|
| 41 | - | ||
| 42 | - | 1. **Everything a Spectra shows, for every Spectra you own, in one place.** Live, channels, tasks, agents, decisions and the log, across the laptop, Earth and whichever machine runs overnight, from any browser or the phone. |
|
| 43 | - | 2. **Agents on different machines talk as if on one.** A task delegated on the laptop to an agent on Earth arrives in that agent's inbox on Earth within a second, through the hub, with the same tools and no new concepts. |
|
| 44 | - | 3. **The archive outlives the machine.** The merged log is the long-term memory: searchable for years, backed up as one directory, exportable. |
|
| 45 | - | 4. **A people model of its own.** Accounts, organisations, teams, roles, scoped tokens and device sign-in for phones, specified here (§3.4, §8) and owing nothing to any other product. |
|
| 46 | - | 5. **One binary, one directory.** `spectrahub serve` links `spectra-core`, keeps SQLite for hub state and the merged log, and renders its own pages. PostgreSQL is possible later, because `sqlx` keeps it open. |
|
| 47 | - | 6. **A Spectra never needs the hub.** The uplink is additive. A hub outage loses nothing on the machine; events queue and resume. |
|
| 48 | - | ||
| 49 | - | Non-goals for 1.0: hosting agents (a runner that starts Claude Code sessions on the hub's machines; §18), federation between hubs, public or multi-tenant service, billing. |
|
| 50 | - | ||
| 51 | - | ## 2. Do we need a Hub at all |
|
| 52 | - | ||
| 53 | - | The honest answer, written down so the adversarial review can argue with it: **not for the first problem.** One person, one machine and several agents is Spectra alone (its spec §26.1). The Hub earns its existence on three things, in this order: |
|
| 54 | - | ||
| 55 | - | 1. **A second machine.** As soon as agents run on Earth overnight while the laptop is closed, the laptop's Spectra cannot see them and the agents cannot see each other. Routing (§7) is the Hub's reason to be. |
|
| 56 | - | 2. **The phone.** The Android app needs a server that is up when the laptop is not, that holds a token safely, and that can push. That is a Hub, even for one person. |
|
| 57 | - | 3. **Other people.** Shared house rules, a colleague's agent in a related project, review of what an agent did: accounts and roles, which Spectra deliberately lacks. |
|
| 58 | - | ||
| 59 | - | A local tool with a hosted superset is therefore the right split: the local tool stays simple and complete, and the hosted layer links the local tool's crates rather than reimplementing them. The cost is a second deployment to run. The mitigation is that until (1) or (2) happens, nothing in Spectra waits for the Hub, and the Hub's first milestone is small. |
|
| 60 | - | ||
| 61 | - | ## 3. Architecture |
|
| 62 | - | ||
| 63 | - | ### 3.1 One process |
|
| 64 | - | ||
| 65 | - | `spectrahub` is a Rust binary in its own Cargo workspace at `../spectrahub`, depending on `spectra-core` and `spectra-api` by path (developer edition, pinned under `deps/`) or by version (release). It runs one tokio runtime with: |
|
| 66 | - | ||
| 67 | - | - an axum router serving pages, static assets, the JSON API, the uplink endpoints and the relay endpoints; |
|
| 68 | - | - askama templates (every page: Spectras, channels, agents, briefs, the Constellation, accounts, organisations, settings, admin), compiled in; one stylesheet; |
|
| 69 | - | - SQLite through `sqlx` at `<data>/hub.db` for accounts, organisations, tokens, sessions, notifications and the merged log (§6); |
|
| 70 | - | - the same event bus as Spectra, carrying every merged event to pages' SSE streams, to routing (§7), to the relay (§9) and to notifications (§10); on PostgreSQL, across processes over `LISTEN/NOTIFY`; |
|
| 71 | - | - workers for webhook delivery, push notifications, email and search indexing. |
|
| 72 | - | ||
| 73 | - | No front-end build; a little JavaScript for the live stream, editors and the Constellation. Every page works without it. |
|
| 74 | - | ||
| 75 | - | ### 3.2 Layout on disk |
|
| 76 | - | ||
| 77 | - | ``` |
|
| 78 | - | <data>/ |
|
| 79 | - | hub.db SQLite: accounts, orgs, tokens, sessions, spectras, the merged log and projections |
|
| 80 | - | hub.toml configuration (§15.1) |
|
| 81 | - | keys/ cookie key, secrets key (seals relay and webhook secrets), TLS material |
|
| 82 | - | attachments/<blake3> attachments uplinked from Spectras, content addressed, deduplicated |
|
| 83 | - | cache/ rebuildable |
|
| 84 | - | ``` |
|
| 85 | - | ||
| 86 | - | ### 3.3 Crate layout |
|
| 87 | - | ||
| 88 | - | ``` |
|
| 89 | - | spectrahub/ |
|
| 90 | - | Cargo.toml workspace: crates/hub (binary), crates/hub-api (types the hub adds to spectra-api) |
|
| 91 | - | crates/hub/src/ |
|
| 92 | - | main.rs CLI: serve, init, admin |
|
| 93 | - | config.rs |
|
| 94 | - | db/ migrations and queries |
|
| 95 | - | auth/ sessions, passwords, TOTP, tokens, device sign-in, sign in with GitHub/Google |
|
| 96 | - | uplink/ the Spectra-facing endpoints and the per-Spectra state |
|
| 97 | - | merge/ the merged log and its projections |
|
| 98 | - | route/ routing events between Spectras |
|
| 99 | - | relay/ phone and chat-bridge relay |
|
| 100 | - | web/ every page; the Constellation's script and the stylesheet |
|
| 101 | - | api/ JSON handlers |
|
| 102 | - | jobs/ workers |
|
| 103 | - | deps/spectra subrepo pinned to the Spectra the hub was built with |
|
| 104 | - | templates/, assets/, migrations/, docs/ |
|
| 105 | - | ``` |
|
| 106 | - | ||
| 107 | - | ### 3.4 Accounts |
|
| 108 | - | ||
| 109 | - | Accounts with a username, a display name and a verified email; passwords (Argon2id) with TOTP as a second factor, or a passkey alone; sessions as opaque, HttpOnly, SameSite cookies with CSRF tokens on every unsafe form; invitations and registration modes (open, invite-only, closed); device sign-in for phones and new machines; tokens with scopes, shown once and stored hashed; organisations and teams; an audit log of every account, token and permission change; outgoing mail for verification and notifications; admin pages. Lessons from other hosted tools (OxygenHub among them) inform these; nothing is shared with or required from them. |
|
| 110 | - | ||
| 111 | - | ## 4. Uplink: a Spectra joins a hub |
|
| 112 | - | ||
| 113 | - | ### 4.1 Registration |
|
| 114 | - | ||
| 115 | - | On the hub, under **+ New Spectra** (or `POST /api/v1/spectras`), the owner names it (`laptop`, `earth`), picks an owner (themselves or an organisation), and gets an **uplink token** once (`spxu_` plus 64 hex, hashed in the db). On the machine: |
|
| 116 | - | ||
| 117 | - | ```sh |
|
| 118 | - | spectra admin uplink https://spectrahub.example --token-env SPECTRA_UPLINK_TOKEN |
|
| 119 | - | ``` |
|
| 120 | - | ||
| 121 | - | which writes `[uplink]` into `spectra.toml` and verifies the token with `GET /api/v1/uplink/hello`, answering with the hub's name, the Spectra's name on the hub, its id, and the last `seq` the hub holds. The first batch must begin with the Spectra's `identity.owner` and `identity.instance` events (Spectra spec §9.5); the hub records the instance identity against the Spectra, requires that the owner's identity is linked to the registering account (§5) and delegates to the instance key, and from then on the uplink token is transport only: what makes a batch this Spectra's is its chain and its checkpoint signatures. |
|
| 122 | - | ||
| 123 | - | ### 4.2 Streaming events |
|
| 124 | - | ||
| 125 | - | `POST /api/v1/uplink/events` takes a batch of events (JSONL, at most 1 000 or 4 MiB) from the Spectra, in `seq` order from the hub's last acknowledged `seq`; the hub stores each with the Spectra's id, acknowledges the highest `seq`, and the Spectra persists that as its uplink cursor. Attachments referenced by events are uploaded first with `PUT /api/v1/uplink/attachments/{blake3}` (skipped when the hub has the hash). A Spectra offline for a week catches up on reconnect. Every event arrives with its `prev`, `hash` and `auth.proof` (Spectra spec §9.1); the hub recomputes each hash, checks the chain against what it already holds, verifies each proof against the identities and delegations in the ledger so far, and verifies each `ledger.checkpoint` against the instance identity. A batch that fails any of these is refused whole, with the first failing `seq`, and the refusal is audited; the hub never stores an event it could not verify. Accepted checkpoints are appended to the hub's own append-only transparency log, so a Spectra cannot later present a different history. Batches are signed by the token (bearer) and carry the Spectra's `id` in the body; a batch whose `seq` range overlaps what the hub holds is checked for equal event ids and refused otherwise (a rebuilt or pruned Spectra registers afresh rather than rewriting history). |
|
| 126 | - | ||
| 127 | - | ### 4.3 Receiving routed events |
|
| 128 | - | ||
| 129 | - | The Spectra holds `GET /api/v1/uplink/stream` open (SSE, keep-alive every 15 s, resumed from the last routed id) to receive events the hub routes to it (§7). Each is applied through Spectra's ordinary core as an event with `actor`, `auth` and the originating Spectra's hash preserved and `via: hub`, so a message from an agent on Earth shows on the laptop as that agent's message, still carrying that agent's signature, delivered by the hub. The receiving Spectra verifies the proof against the identities the hub forwards with it before applying it. |
|
| 130 | - | ||
| 131 | - | ### 4.4 Identity across Spectras |
|
| 132 | - | ||
| 133 | - | Agents are named `NAME@SPECTRA` on the hub (`claude-oxygen@laptop`). A bare name resolves on the Spectra it was used on. Projects with the same name under one owner, or linked by the owner on the hub, are the **same project** across Spectras (the folder on each machine, if any, is a *location*). |
|
| 134 | - | ||
| 135 | - | ## 5. Accounts, organisations and authorization |
|
| 136 | - | ||
| 137 | - | Accounts as §3.4, with these words: |
|
| 138 | - | ||
| 139 | - | - **Owner** of a Spectra: a user or an organisation. Roles on a Spectra: `read` (see everything, post as the human in its channels), `operate` (plus tasks, pause, schedules, answering human requests), `admin` (plus rules, agents, tokens, deletion). An organisation's members get its default role on its Spectras. |
|
| 140 | - | - **The human on a Spectra** is its owner's account when the owner is a user; when an organisation, every member who posts is a distinct human principal on the hub, and routed down to the Spectra as `human` with the account name in the event, so the machine's single-human model holds. |
|
| 141 | - | - **Tokens:** `spectra:read`, `spectra:operate`, `spectra:admin`, `user:read`, `hooks:admin`, optionally restricted to listed Spectras. Device sign-in (RFC 8628 shape) for the Android app and `spectra` on a new machine. |
|
| 142 | - | - **Linked Spectra identities**: the owner links their Spectra identity (Spectra spec §8.0) to their account with a signed challenge, and every agent's owner then resolves to an account, so the hub shows `claude-oxygen@laptop · Andy McCall's agent` from the delegation in the ledger, never from a label. A Spectra whose owner identity is not linked cannot register (§4.1). |
|
| 143 | - | ||
| 144 | - | ## 6. The merged log |
|
| 145 | - | ||
| 146 | - | The hub's `events` table is the union of every uplinked Spectra's events, keyed by `(spectra_id, seq)`, unique on event `id`, with a hub-assigned `hseq` giving the order of arrival. Where events from different Spectras are shown together (mirrored threads, the All views) the order is each event's `hlc` then `id` (Spectra spec §9.1), never arrival or wall clock, so a reply cannot sort before its question because one machine's clock is behind. Projections (channels, tasks, agents, decisions, presence, inbox, FTS) are maintained per Spectra exactly as Spectra's own (`spectra-core` builds them; the hub calls the same code with the Spectra id as a partition key), plus hub-wide ones: the **All** views, cross-Spectra threads (§7), and per-account inboxes. `spectrahub admin rebuild` rebuilds everything from `events`; the test suite asserts projection equality after each scenario, as Spectra's does. |
|
| 147 | - | ||
| 148 | - | Retention is per Spectra (`[retention]` on the hub overrides the machine's: the machine may prune its tool-call events after 30 days while the hub keeps them a year). |
|
| 149 | - | ||
| 150 | - | ## 7. Routing between Spectras |
|
| 151 | - | ||
| 152 | - | A message or task addressed to a principal on another Spectra (`@claude-oxygen@earth`, `delegate(to: "claude-oxygenhub@earth")`) is an ordinary event on the sending Spectra. Its uplink carries it to the hub; the hub sees an address it holds on another Spectra and **routes** it: it writes a routed copy for the target Spectra (same event id, `routed_from`), delivers it on that Spectra's stream (§4.3), and the target's core applies it, putting it in the agent's inbox and (for a task) its project queue. Transitions on a routed task go back the same way. A thread with participants on two Spectras is one thread on the hub and a mirrored thread on each machine, kept consistent because every message is an immutable event and order is by event time then id. |
|
| 153 | - | ||
| 154 | - | **One home per task.** A task's state machine lives on one Spectra, its **home**: the assignee's Spectra (the requester's until a queued task is accepted). Every transition made elsewhere is a proposal routed to the home, which applies it in its own log in arrival order and refuses one its state does not allow (`task.transition_refused`, routed back and shown in the proposer's inbox). A local `cancel` and a remote `complete` racing are therefore never merged: the home sees one first, refuses the other, and both machines converge on the home's log. The merged log needs no CRDT: events are immutable, their order is `hlc` then `id`, and the only mutable thing, task state, has one writer. |
|
| 155 | - | ||
| 156 | - | Cross-Spectra channels: `#general` and `#humans` exist on the hub as the union of every Spectra's; a hub-level channel (`#release`) is created on the hub and mirrored to the Spectras whose agents join it. Direct channels between agents on different machines are hub channels mirrored to both. |
|
| 157 | - | ||
| 158 | - | Addressing without the hub fails plainly: `delegate(to: "x@earth")` on a Spectra with no uplink is refused with "no hub configured". |
|
| 159 | - | ||
| 160 | - | ## 8. Web interface |
|
| 161 | - | ||
| 162 | - | The website for Spectra (Spectra spec §17: Spectra itself has no web pages). Every page is behind the hub's authentication, with a **Spectra picker** in the band (All · laptop · earth · …) and the owner's name beside every human principal. The pages: |
|
| 163 | - | ||
| 164 | - | | Path | Page | |
|
| 165 | - | |---|---| |
|
| 166 | - | | `/` | Signed in: every Spectra you may see as a card (online, agents, open human requests, last event), your inbox, then Live across them. Anonymous: sign in | |
|
| 167 | - | | `/s/{owner}/{spectra}/…` | That Spectra: `live`, `c/<name>` (channels with replies shown under their message), `agents`, `briefs`, `constellation`, `tasks`, `decisions`, `schedules`, `log` (with verification), `search`, `settings` | |
|
| 168 | - | | `/constellation` | The **Constellation** across every Spectra you may see: projects as prisms linked by dependency, agents orbiting their project in the colour of their presence, the owner at the centre; every message a beam of light from its author to its channel, tool calls a pulse, guard trips a flare. SVG and plain script from the live stream; a still picture without JavaScript | |
|
| 169 | - | | `/all/…` | The same pages across every Spectra you may see | |
|
| 170 | - | | `/inbox` | Human requests and permission prompts from every Spectra, answerable here, and notifications (§10) | |
|
| 171 | - | | `/{owner}` | A person or organisation: their Spectras, members, teams | |
|
| 172 | - | | `/settings/*`, `/orgs/{name}/settings/*`, `/admin/*` | Profile, sessions, tokens, organisations, members and teams, mail and registration, plus Relay (§9) and Uplink tokens | |
|
| 173 | - | ||
| 174 | - | The Briefs page sets a Spectra's briefs as `brief.set` events routed to that Spectra and proven by the owner's passkey (Spectra spec §12, §8.5), so a brief set on the hub is as attributable as one set from the command line. |
|
| 175 | - | ||
| 176 | - | ## 9. Relay: phones and chat bridges |
|
| 177 | - | ||
| 178 | - | The relay is the Spectra's `[relay]` (Spectra spec §16.2) pointed at the hub. Human requests and permission prompts arrive at `POST /api/v1/relay/{spectra}`; the hub shows them in `/inbox`, pushes them to the Android app and to any configured bridge (Telegram or Discord through the hub, with a sender allowlist as the Claude Code channel plugins keep), and sends the answer back down the uplink stream as `human.answered` or a permission verdict. An answer given on any surface closes the request on every other. |
|
| 179 | - | ||
| 180 | - | ## 10. Notifications |
|
| 181 | - | ||
| 182 | - | Per account: an inbox with unread count, subscriptions (a Spectra, a channel, a task), mentions, human requests, guard trips, and agent offline-for-long warnings; optional email through the hub's mail settings; push to the Android app. Each kind can be turned off per account, and per Spectra or channel by unsubscribing. |
|
| 183 | - | ||
| 184 | - | ## 11. Search and the archive |
|
| 185 | - | ||
| 186 | - | FTS5 over the merged log, limited to what the viewer may see, with the Spectra as a filter; the same query grammar as Spectra's `search`. `GET /api/v1/spectras/{o}/{s}/export?since=` streams the Spectra's events as JSONL for an offline copy or a migration to another hub. |
|
| 187 | - | ||
| 188 | - | ## 12. HTTP API and webhooks |
|
| 189 | - | ||
| 190 | - | `/api/v1`, bearer tokens, `application/json`, RFC 7807 problems, cursor pagination, ETags. Resources: `/spectras` (list, create), `/spectras/{o}/{s}` and beneath it every Spectra API resource (`/brief` as the human, `/agents`, `/channels/{name}/messages`, `/tasks`, `/tasks/{id}/{transition}`, `/decisions`, `/rules`, `/schedules`, `/events?follow=1`, `/search`), `/all/…` for the cross-Spectra views, `/inbox`, `/user`, `/user/spectras`, `/users/{name}`, `/orgs/{name}`, `/device/code` and `/device/token`, `/uplink/*` (§4), `/relay/*` (§9), `/hooks`. Types are `spectra-api` plus `hub-api`; `make ts` writes both for the extensions and the Android app's Rust core. |
|
| 191 | - | ||
| 192 | - | Webhooks per Spectra and per organisation: `message`, `task.*`, `human.asked`, `guard.tripped`, `agent.presence`, `decision`, `ping`; an HMAC-SHA256 signature header as Spectra's own routes take (Spectra spec §16.2); delivery log with redeliver. |
|
| 193 | - | ||
| 194 | - | ## 13. Integrations |
|
| 195 | - | ||
| 196 | - | None is required. Outside systems reach SpectraHub as they reach a Spectra: signed webhooks routed to a Spectra's projects (Spectra spec §16.2, configured once here instead of on each machine), and the API (§12). A code forge, a document editor or a chat bridge connects that way; any deeper integration is a separate, optional tool on top of the API. |
|
| 197 | - | ||
| 198 | - | ## 14. Security |
|
| 199 | - | ||
| 200 | - | Threat model: a network attacker (TLS everywhere, HSTS), a malicious account holder (permissions checked on every request, per Spectra), and a stolen token (scoped, revocable, hashed at rest); plus **a compromised Spectra uplink token**, which can deliver batches for that Spectra only, and only ones whose chain and proofs verify, so it can delay or withhold and nothing else; **a compromised Spectra** (a machine), which holds its own keys and so can say anything in its own principals' names, nothing in another Spectra's, and cannot rewrite what it already checkpointed; and **a compromised hub**, which can deny service and forge hub-only data (accounts, notifications, routing) but cannot forge, alter or reorder a Spectra's events, since each carries a proof it cannot make and each checkpoint a signature it does not hold. Web pages carry a strict Content Security Policy, forms a CSRF token and our own Origin; passwords are Argon2id; sessions and tokens are opaque and stored hashed. Message bodies from any Spectra are content, never templates. Relay bridges MUST gate on sender identity before anything reaches an agent (Spectra spec §20.3 applies on the way down). Rate limits per token and per Spectra on the uplink (events per second, bytes per minute) with a queue depth that refuses, not drops. |
|
| 201 | - | ||
| 202 | - | ## 15. Operations |
|
| 203 | - | ||
| 204 | - | ### 15.1 Configuration |
|
| 205 | - | ||
| 206 | - | `hub.toml`, every key overridable by `SPXHUB_<SECTION>_<KEY>`: `[server]` (`bind = "0.0.0.0:7360"`, `tls_bind = "0.0.0.0:7363"`, `base_url`, `behind_proxy`, `roles`), `[registration]`, `[email]`, `[auth]`, `[retention]`, `[relay]` (bridges), `[limits]`. The shapes are OxygenHub's §17.1. |
|
| 207 | - | ||
| 208 | - | ### 15.2 Command line |
|
| 209 | - | ||
| 210 | - | `spectrahub init --base-url … [--self-signed]`, `serve`, `admin user create|list|reset-password`, `admin spectra list|delete`, `admin rebuild`, `check`. |
|
| 211 | - | ||
| 212 | - | ### 15.3 Backup |
|
| 213 | - | ||
| 214 | - | Copy the data directory; the merged log is also reconstructible from each Spectra's own log, so a hub is never the only copy of anything a machine still holds. |
|
| 215 | - | ||
| 216 | - | ## 16. Required changes to Spectra |
|
| 217 | - | ||
| 218 | - | - The event envelope with `hlc`, `prev`, `hash` and `auth`, frozen at Spectra 0.1 (Spectra spec §9.1, §9.5): nothing the hub merges changes shape later, and the hub verifies rather than trusts. |
|
| 219 | - | - Spectra's `admin verify` as a library function in `spectra-core`, so the hub runs the same verification on a batch that the machine runs on its own ledger. |
|
| 220 | - | - `[uplink]` configuration, the cursor, batching, the resume protocol (§4.2) and the inbound stream (§4.3): Spectra 0.5. |
|
| 221 | - | - `task.transition_refused` and the task home rule (§7): Spectra 0.5. |
|
| 222 | - | - Principal addresses with `@SPECTRA` and the "no hub configured" refusal (§7). |
|
| 223 | - | - `spectra-core` projections take a partition key so the hub can run them per Spectra (§6). |
|
| 224 | - | - `brief.set` routed from the hub, proven by a passkey assertion (§8). |
|
| 225 | - | ||
| 226 | - | ## 17. Milestones |
|
| 227 | - | ||
| 228 | - | The Hub starts now (2026-11-03): Spectra is in daily use, and with Radar removed the Hub is Spectra's only website. Its first milestone brings the uplink (§4) forward into Spectra. What the Hub merges, the event envelope, is frozen at Spectra 0.1. |
|
| 229 | - | ||
| 230 | - | | | Delivers | Done when | |
|
| 231 | - | |---|---|---| |
|
| 232 | - | | **0.1 Uplink and view** | Workspace with `deps/spectra` pinned, config, SQLite, the owner's account with a passkey, a Spectra registered with its instance identity and an uplink token, Spectra's uplink (§4), the merged and verified log, the pages of §8 read-only (Spectras, channels with replies, agents, briefs, log), the Constellation, served over TLS at `spectrahub.io` | Earth's Spectra is visible on the hub from a browser on the workstation and a phone, live, with the Constellation | |
|
| 233 | - | | **0.2 Route** | Addresses with `@SPECTRA`, routing, mirrored threads and channels, human requests answered on the hub, relay to the Android app | A task delegated on the laptop to an agent on Earth is accepted and completed there, and the result shows on the laptop | |
|
| 234 | - | | **0.3 People** | Organisations, teams, roles, tokens with scopes, device sign-in, sign-in providers, notifications with email, webhooks, the API complete, `make ts` | spectrahub-vscode and the Android app work against the API with scoped tokens | |
|
| 235 | - | | **0.4 Bridges and integrations** | Telegram and Discord bridges with allowlists, webhook routing configured on the hub, project links across Spectras | A task is created on one machine from an outside system's signed webhook and approved from a phone | |
|
| 236 | - | | **1.0** | Hardening, load test, security review, PostgreSQL option, packaging, documentation | — | |
|
| 237 | - | ||
| 238 | - | ## 18. Open questions |
|
| 239 | - | ||
| 240 | - | 1. **A runner.** The hub could start agent sessions itself (a Claude Code `-p` session in a sandbox) when a task is queued for a project with no agent online. That makes Spectra a scheduler of agents, not just a switchboard, and changes the threat model. Not before 1.0; decide with a worked example. |
|
| 241 | - | 2. **Sharing account code with other hubs.** Accounts, tokens and mail are the same shape in any hosted tool. A shared crate would save work, but would tie SpectraHub to another product's releases. Kept apart; SpectraHub owns its account code. |
|
| 242 | - | 3. **Cross-Spectra ordering.** Settled in Draft 0.2: events carry a hybrid logical clock from Spectra 0.1 and tasks have one home (§6, §7). Open: whether a home should move when a task is reassigned across machines, or stay where it was created. |
|
| 243 | - | 4. **Multi-tenant.** Nothing here stops a public hub, and nothing here is reviewed for one. Explicitly single-organisation until someone needs more. |
|
| 244 | - | ||
| 245 | - | ## 19. Changelog |
|
| 246 | - | ||
| 247 | - | - Draft 0.5 (2026-11-03): Spectra has no web interface (Spectra spec Draft 0.7), so the Hub renders every page itself, the Constellation among them, instead of mounting Radar (§8); briefs replace rule files (§8); the Hub starts now rather than after Spectra 0.3 (§17); 0.1 is one owner, Earth's Spectra, read-only pages and the Constellation. |
|
| 248 | - | - Draft 0.4 (2026-11-03): SpectraHub stands alone, as Spectra does (Spectra spec Draft 0.5): accounts are specified here (§3.4) instead of by reference to OxygenHub; owners link their Spectra identity, not an Oxygen one (§8); projects match across Spectras by name or by the owner's link (§6); webhooks are HMAC-signed and integrations are optional (§12, §13); nothing depends on Oxygen, OxygenHub or OxygenFlow. |
|
| 249 | - | - Draft 0.3 (2026-11-02), security: the hub verifies every uplinked event's chain and proof and every checkpoint's instance signature, refuses what does not verify, and witnesses checkpoints in its transparency log (§4.2); a Spectra registers with its instance identity under a linked owner (§4.1); routed events keep their origin's signature (§4.3); the threat model says what a compromised hub can and cannot do (§14). |
|
| 250 | - | - Draft 0.2 (2026-11-02), after review: order by `hlc` (§6), one home per task instead of a CRDT (§7), the Hub deferred until Spectra 0.3 is in use and 0.5 exists (§17). |
|
| 251 | - | - Draft 0.1 (2026-11-02): initial specification. |