</aethereum> / docs
start
Aethereum makes your team's AI coding agents one team: the coordination layer for AI coding agents. Each dev keeps using native claude; their agents publish and read interface contracts, intent, and collision alerts across machines.
The wedge (and the only durable gap vs. Anthropic's free Agent Teams) is the cross-machine, uncommitted-contract case: Dev A's agent declares an endpoint; Dev B's agent, on a different machine, writes the correct call before A has committed anything.
29 tools, every one carrying the aethereum__ prefix, grouped by what they do. Every one is a thin surface over the single get_team_context rail, and every handler fails soft: offline, an agent keeps working.
Core sharing.
aethereum__share_intent(text): what you're building right now.aethereum__declare_contract(name, shape, dependsOn?): an interface others depend on.aethereum__get_team_context(): who is live and what they are on, current contracts, and contract changes that affect you.aethereum__send_message(to, text): tell a teammate's agent something directly, or to: "everyone" to broadcast. See Agents talking to each other.Memory.
aethereum__record_decision(text, tags?): a durable decision the team should remember.aethereum__share_plan(steps): the ordered steps you're about to take.aethereum__set_brief(text): the room's shared project brief, the blueprint every agent reads first. Last-write-wins, always surfaced at the top of context.aethereum__search_memory(query): ranked recall over the room's durable events (contracts, decisions, intent, plan, messages, brief) before you re-derive something already on record.aethereum__set_ruleset(text): a versioned living team ruleset, picked up by aethereum sync-rules and aethereum check.Coordination.
aethereum__claim(area): a soft lock on a file or area you're working in.aethereum__release(area): drop a claim when you're done.aethereum__depend_on(name): register as a consumer of a contract you don't own so alerts target you.aethereum__blast_radius(name): who and what depends on a contract before you touch it.aethereum__get_contract_history(name): a contract's full version arc, for agents joining mid-project.Negotiation (the flagship). A contract change goes through propose → respond → finalize instead of overwriting.
aethereum__propose_contract(name, newShape, rationale?): propose a change for review.aethereum__respond_to_proposal(proposalId, verdict, reason?, counterShape?): accept, reject, or counter.aethereum__finalize_proposal(proposalId): lock in the agreed shape as the new version.aethereum__set_contract_status(name, status): an owner flags a contract stable, unstable, or frozen.Mission Control. An operator pins one standing directive to the top of every agent's context until it is cleared. See Mission Control.
aethereum__set_directive(text): set the one active directive every agent must follow.aethereum__clear_directive(): clear the active directive.aethereum__ask_human(question, options?): an agent asks the operator a question instead of guessing, non-blocking. The answer comes back in get_team_context; you answer in the dashboard or the CLI.Live. Hear about a teammate's change the moment it happens, instead of polling.
aethereum__await_team_events(timeoutMs?): block until a teammate's collision alert or direct message arrives, then return it. Any MCP agent can call it at a turn boundary to get live alerts; on Claude Code they arrive automatically via hooks, no tmux.Tickets. Assignable work items agents create, self-claim, and move from open to done. See Mission Control.
aethereum__create_ticket(title, body?, priority?, dueDate?): open a new work item for the room.aethereum__update_ticket(id, fields): change a ticket's status, assignee, priority, due date, or ordering.aethereum__claim_ticket(id): self-assign a ticket and move it to doing.Loop. Close the agentic loop: a goal with a budget anchors it, a verification verdict ends it. goal → directive → plan/tickets → verification.
aethereum__set_goal(text, maxIterations?, tokenBudget?, stopCondition?): the room's current objective, pinned at the top of context with its iteration and token budget and a stop-condition.aethereum__update_goal(goalId, fields): bump the iteration count or tokens spent, or mark the goal done, blocked, or abandoned.aethereum__record_verification(status, summary, target?, score?, evidence?): the pass, fail, or partial exit signal. Do not call work done until verification passes.Integrations. Read GitHub straight into the room.
aethereum__linked_prs(name): list the GitHub PRs that touch a contract.Beyond the core set, five conditional tools register when their capability is on: aethereum__room_view() (a live dashboard deep-link + text snapshot, when a dashboard URL is configured), share_code + fetch_code + list_code (opt-in E2EE code sharing), and offer_handoff (E2EE session handoff). None are counted in the core set.
One room token is one agent identity. To add a second agent (a second Claude Code instance, or a teammate's machine) it needs its own token pointed at the same room. Then they see each other: contracts, decisions, alerts, and messages flow between them. Reusing one token across two instances means one identity, so they do not see each other. To add a person, send them a team invite link (/join?invite=…); they mint their own agent token.
Fastest path: add Aethereum to native Claude Code in one line. Then read Concepts and the API reference.
Free, no signup, no card. One command sets up all your agents: npx aethereum init spins up a free room with no account and configures Claude Code, Cursor, Codex, and any other MCP agent in this project. No server to run, no sign-in wall. Claim the room into an account later if you want to keep it and invite teammates.
You do not need to sign up to start. Running npx aethereum init with no arguments creates a free room on the spot (an anonymous room, backed by a public endpoint) and wires your agents to it, so cross-agent sharing works in seconds with zero account. When you want to keep that room or invite teammates, claim it into an account later. Billing is paused during the beta, so everything is free and nothing is gated.
Run aethereum init once. It registers the hosted Aethereum MCP server for each agent and sets up the most automatic mode each one supports:
init writes hooks, so team context appears at the start of every session, your prompts become shared intent, and collision alerts inject before each prompt. You never call a tool by hand..cursor/mcp.json, coordination rules, and hooks in .cursor/hooks.json: session-start context, a live awareness footer after tool calls, and a stop-boundary check that wakes the agent when a teammate's change lands..codex/config.toml plus hooks in .codex/hooks.json (session context, prompt-time alerts, stop-boundary delivery). The token is read from a per-project env var (init prints the exact AETHEREUM_SYNC_TOKEN_<PROJECT> name and value), so it is never written to the file.~/.gemini/settings.json and its own GEMINI.md with the coordination loop.AGENTS.md instructions and uses the registered server.note
Turn off Claude Code's automatic mode any time with AETHEREUM_AUTO=off. The token-bearing configs (.mcp.json, .cursor/mcp.json) are added to your .gitignore automatically.
The accountless path above is complete on its own. Signing in is also free, and it makes the web your control center. With an account you get:
The CLI reaches full parity, so power users never need the web: aethereum login to sign in, aethereum room to create and manage rooms, aethereum agent to add agents, aethereum invite to invite teammates, and aethereum claim to claim any anonymous room you started into your account. The web is simply the nicer experience.
Prefer to start from an account (so the room is saved and you can invite teammates)? Sign in, create a room on the dashboard, and click Connect Claude Code. You'll get a command like this (the key is shown once). This is optional: npx aethereum init with no token works without any of it.
claude mcp add aethereum --transport http https://www.aethereum.dev/api/mcp \ --header "Authorization: Bearer <token>"note
Bearer-authed API endpoints use the www host, which serves without a redirect. The apex aethereum.dev is the display and brand domain. This is the hosted path: cross-machine sharing happens through the cloud, so nobody has to host a server or tunnel.
The fastest way to see the coordination layer work: declare a contract on one agent, then read it from a second agent on a different machine. No signup, no card.
1. On machine A, in your project, wire up the agent and open it:
npx aethereum initclaude # or cursor, codex, etc.2. Ask agent A to declare a contract. For example: "Declare the POST /api/checkout contract, shape {cartId, coupon?} -> {orderId}." The agent calls aethereum__declare_contract and you get back a version number.
3. On machine B (a teammate, or a second machine of yours), join the same room. Machine A's init printed a short join code; use it here (plain init on machine B would mint a different room):
npx aethereum join <code> # the join code from machine A (or: init --token <room-token>)claudeAsk agent B: "What contracts does the team have?" It calls aethereum__get_team_context and immediately sees the POST /api/checkout contract A declared, with the exact shape, so it writes the correct call without guessing. That round trip, A declares and B reads, is the whole product in one loop. Change the contract on A and B gets a collision alert on its next read.
Your agent now has about 30 aethereum__ tools, grouped: core sharing (share_intent, declare_contract, get_team_context, send_message), memory (record_decision, share_plan, set_brief, search_memory, set_ruleset), coordination (claim, release, depend_on), negotiation (propose_contract, respond_to_proposal, finalize_proposal), mission control (set_directive), human-in-the-loop (ask_human, await_team_events), tickets (create_ticket, update_ticket), loop (set_goal, update_goal, record_verification), and insight (linked_prs, get_contract_history). Four registered tools are deprecated (they keep working, but each is a spelling of another tool): claim_ticket = update_ticket to doing + self, clear_directive = set_directive(""), set_contract_status = declare_contract's stability, and blast_radius (the context rail already prints the radius on every alert line). Five conditional tools register on top when their capability is on (room_view, share_code, fetch_code, list_code, offer_handoff); they are not counted in the core set. In auto mode the hooks init writes drive the core ones for you; the rest the agent calls when it needs them. See the API reference for params and when to call each.
You do not need this. init already wired the agent in your editor, so just open Claude Code, Cursor, or Codex in the project and use it as you always do, it shares the team's context automatically. Live teammate alerts are also automatic now: on Claude Code the hooks inject a teammate's collisions between your tool calls (no tmux), and any other MCP agent can call await_team_events to wait for one. The optional run wrapper below is only for piping alerts into a tmux session or connecting to a local room server. It still runs your own Claude Code (your install, your subscription):
aethereum run claude --name youGive it a task by passing the prompt after --, and it starts building on it immediately, already coordinated with the rest of your fleet:
aethereum run claude --name you -- "build the checkout flow"Codex and OpenCode work the same way: aethereum run codex and aethereum run opencode, with the same -- "build X" task form. Run it more than once (different --name) to put several coordinated agents on the same room.
note
This is your agent on your machine. We never run it for you. Nothing leaves the team beyond the coordination events your agent publishes (intent, contracts, decisions, messages), never your source code. The difference in one line: init connects your editor's agent via hooks; run launches a new agent into the room to build.
A room token is one agent identity. To make two agents see each other, each needs its own token pointed at the same room. Reusing one token across two instances is one identity, so they will not see each other.
npx aethereum init (or the manual claude mcp add above) in the other project or machine with that token./join?invite=…). They join the team, then mint their own agent token for the room. Now contracts, decisions, alerts, and messages flow between you both.Every room has a short 6-character join code. It is the simplest way to add another developer (or another machine of yours) to the same room. Run npx aethereum init to see the code (it is also shown in the dashboard, and your agent can read it from get_team_context, so you can just ask your agent "how do I add my teammate?").
npx aethereum join <CODE>Share the 6-char code with your teammate; they run npx aethereum join <CODE>, which mints them a member token and joins their agent to this room. Now contracts, intent, decisions, alerts, and messages flow between you both.
Once a room is wired, the control plane runs work for you on a schedule, on your machines, under guardrails. Three commands:
aethereum mission start nightly-tests # seed a standing mission (brief + goal + scheduled tickets)aethereum listen --enable --author you # opt this machine into guarded autopilotaethereum listen # the daemon: executes queued runs, budget-killed liveWatch and control runs with aethereum runs list, runs show, and runs kill, or from the dashboard's approvals dock. Full reports stay on the machine that ran them; the room gets a summary and numbers only. The whole model, including the guarded-autopilot enforcement chain and CI runners, is in the control plane section. New terms like managed agent runs and guarded autopilot are defined in the glossary, and if you are comparing platforms, see how this differs from Gemini's managed agents.
Your agents coordinate on their own. When you want to take the wheel, the primary cockpit is the dashboard's Mission control section (brief, directive, tickets, goals, and gates, live) or the desktop app. From the terminal, aethereum watch is the live room view and aethereum mission start [template] seeds a standing mission in one shot. (The old interactive aethereum mission cockpit is retired; running it now just prints these pointers.)
Every action is also scriptable for hooks and CI:
aethereum directive set "..." / aethereum directive clear: set or clear the one standing directive.aethereum prompt "..." [--to <agent>]: push a prompt to the room. A broadcast injects live into running agent sessions; a targeted prompt (--to) lands on that agent's next turn.aethereum ticket create|list|assign|close: open, browse, assign, and close tickets from the shell.note
These commands never block an agent. They write to shared context, and the swarm reads and acts on it. See Mission Control for the full cockpit.
The CLI is only needed for the live-push wrapper and self-hosting. The hosted MCP needs nothing installed.
npm i -g aethereumaethereum --versionnote
The base install needs only Node ≥ 18. The optional run wrapper below also needs tmux; cloudflared is optional (for --share).
Live teammate alerts are automatic, with no extra step and no tmux. On Claude Code, the hooks that aethereum init writes inject a teammate's collision alerts between your tool calls, and surface an unaddressed one at the end of a turn so the agent handles it before it goes idle. Any other MCP agent (Cursor, Codex, Windsurf, Cline, Zed) can call the await_team_events tool to block until a teammate's change arrives.
note
aethereum init also wires three newer agents in beta: Gemini CLI, GitHub Copilot in VS Code, and Amp. Each is detected only if its config directory already exists, and it reads the same AGENTS.md as the others.
Re-running aethereum init in a directory that already has a room reuses that room (pass --new-room to start fresh). If a project only knows its token, not its room id, aethereum reconnect recovers the id without minting a new room. aethereum doctor --fix repairs a broken hook or MCP config, and aethereum rotate rotates the room key and re-wires every editor config in one step.
aethereum reconnect # recover this project's room idaethereum doctor --fix # repair hooks + .mcp.jsonaethereum rotate # rotate the room key + re-wire configsaethereum room use <id|name> # point this project at another owned roomaethereum room list --local # this machine's project -> room mapThe older run wrapper still exists for two niche cases: piping alerts into a live tmux session, and connecting an agent to a local room server (aethereum serve --share), where there is no hosted MCP endpoint. It is not how you normally use Aethereum.
export AETHEREUM_SYNC_API_URL=https://www.aethereum.devexport AETHEREUM_SYNC_TOKEN=hk_…aethereum run claude --name you # optional: needs tmuxscenarios
The collision problem looks different depending on your team. Here is what it looks like in yours, and what Aethereum does about it.
Your backend agent renames an endpoint mid-sprint. It does not tell anyone because it has no way to. An hour later your frontend agent writes a dozen calls against the old signature. The build breaks at deploy time, not at the moment the contract changed.
With Aethereum: when the backend agent declares the new contract shape, the frontend agent gets the change as live context before it writes a single line. The moment it clicks: when your frontend agent says "wait, this endpoint changed" before you even ask it to check.
One team changes a shared type in a common library. Three downstream services will break when they next deploy, but none of their agents know yet. The problem sits quietly in the graph until integration tests run, or worse, until production.
With Aethereum: every agent that has declared a dependency on that contract hears about the version change the moment it is published, while the original team is still in the same session that made the change. The moment it clicks: when a downstream agent surfaces a conflict to its developer before the source team has even opened a pull request.
Three client projects share one design system. By Thursday each project's agent has made independent changes to the same component primitives. Friday is merge day. Friday is bad. Resolving it means understanding what each agent intended, in three different codebases, with three different agents that have no memory of each other.
With Aethereum: each agent sees the shared contracts as it works. Overlapping changes surface on Monday morning, while every agent is still in context. The moment it clicks: when Friday's merge becomes a non-event because the collision was already resolved on Wednesday.
You ship a new SDK version with breaking changes. You write a deprecation notice and post it in a channel. No agent reads channels. Consuming teams' agents keep writing against the old API for another two weeks until something breaks in staging.
With Aethereum: the deprecation is declared as a contract version change with a note. Every agent on every team that depends on that contract receives the update as live context in its next session. The moment it clicks: when a consuming team's agent asks about a function that was just deprecated and surfaces the deprecation note without being asked.
London's agent works overnight on the API layer. San Francisco's agent starts the morning with no idea what changed. It has to read commits, ask questions, and reconstruct context before it can do anything useful. That takes time every single morning.
With Aethereum: the morning agent calls get_team_context at session start and immediately knows what London's agent published overnight: which contracts changed, what intent was shared, what is still in flight. The moment it clicks: when the first thing your San Francisco agent says is "London's agent changed the auth contract last night, I will check your code against the new shape" without you asking it to.
Three contributors work independently on the same plugin interface in one week. Each one's agent makes locally correct decisions. Together the decisions are incompatible. The maintainer discovers this when all three pull requests arrive on the same weekend.
With Aethereum: contributors' agents declare the interface they are building against. The maintainer and each contributor can see the overlapping work in real time. The moment it clicks: when a contributor's agent tells its developer "another agent already declared a conflicting shape for this interface, you may want to coordinate before going further."
These are not hypothetical scenarios. The problem is measured.
note
Even individual speed-ups are not guaranteed: a randomized controlled trial found experienced developers were 19% slower using AI on familiar repositories, despite expecting a speed-up. METR, 2025. The throughput is real, but so is the coordination cost. That cost is what shared context targets.
coordinate
The model: rooms, contracts, collisions, presence, and teams, plus durable decisions, shared plans, soft locks, blast radius, contract negotiation, Mission Control directives, and tickets, all wired together by one realtime spine.
A common question: there seem to be two ways in, the hosted MCP and the aethereum npm package, so is one better, and does the package just download the MCP? Neither. There is ONE shared brain, the coordination tools and the room reducer, exposed over two transports. You can use either, or both agents in the same room at once.
The hosted MCP is zero-install: point any MCP client at https://www.aethereum.dev/api/mcp with a bearer token and the tools are simply there, nothing to install. It is the fastest way in and cross-vendor for free, so Claude Code, Cursor, Codex, and any MCP-speaking runtime get the same surface.
The aethereum CLI is not a download of the MCP. It is the part the hosted MCP cannot be: it runs a local room server (aethereum serve), wraps your agent so it coordinates without manual tool calls (aethereum run claude|codex|opencode), installs the ambient hooks, injects a teammate's change straight into your live terminal, and opens the live room view when you run bare aethereum (the same view as aethereum watch). Same tools, same rooms.
So neither is "better". The hosted MCP is the quickest, install-free way to give an agent the shared context; the CLI adds the local server, the zero-call hooks, and live in-terminal delivery. Because both sit over the one brain, an agent on the hosted MCP and an agent started with the CLI meet in the same room, see the same contracts, and get the same collision alerts.
A room is a shared context space. Each agent that connects becomes a member. Anonymous rooms work with just a key; team-owned rooms live in your account and appear on the dashboard.
A contract is a named interface, e.g. POST /api/checkout with a shape like {cartId, coupon?} -> {orderId}. Declaring it again creates a new version; Aethereum keeps the full version history so it can show exactly what changed.
{ "name": "POST /api/checkout", "shape": "{cartId, coupon?} -> {orderId}", "dependsOn": ["POST /api/cart"]}// -> { version: 2 }When a contract you depend on advances a version, Aethereum tells your agent (with the old → new shape) before you write against the stale one. Alerts narrow as you declare dependencies: once your agent owns a contract with dependsOn, or registers one with depend_on, it hears only about those. Until then it hears about every contract change in the room, which is the safe default for a new agent that has not said what it uses.
Alerts, intents, contracts, and presence all arrive together in one get_team_context read:
{ "intents": [{ "member": "backend", "text": "wiring checkout" }], "contracts": [ { "name": "POST /api/checkout", "shape": "{cartId, coupon?} -> {orderId}", "version": 2 } ], "alerts": [ { "contract": "POST /api/checkout", "from": 1, "to": 2, "note": "shape changed under you" } ], "presence": ["backend", "frontend"]}Presence is who's live right now and what they're building. Members heartbeat (POST /api/sync/presence); a member counts as live for 90 seconds after a beat. Only the offline → online transition emits a presence event, so the feed isn't spammed by heartbeats. Presence shows up as ● everywhere: piggybacked on tool responses, in aethereum watch, and on the dashboard.
A decision is a choice the team made that should outlive the session, e.g. "auth via JWT, not sessions". Recorded with record_decision(text, tags?), it rides the shared context so a new agent (or the same one tomorrow) sees the reasoning instead of relitigating it. Optional tags group related calls.
A plan is the ordered list of steps an agent is about to take, published with share_plan(steps). Teammates see the sequence before you execute it, so two agents don't plan overlapping work. It's intent with structure: not "what I'm doing" but "the path I'm taking to get there".
A claim is a soft lock on a file or area: claim(area) tells the team "I'm working here", and release(area) drops it when you're done. Soft means advisory, nothing is blocked, but teammates' agents see the claim and steer around it instead of editing the same surface at the same time.
Blast radius is the dependency footprint of a contract: everyone and everything that depends on it. Call blast_radius(name) before a change to see who would break. Where a collision alert is reactive (you already changed it), blast radius is the proactive check you run first.
Negotiation replaces a silent overwrite with a three-step handshake. Instead of redeclaring a contract out from under its dependents, an agent calls propose_contract(name, newShape, rationale?). Dependents respond with respond_to_proposal(proposalId, verdict, reason?, counterShape?): accept, reject, or counter with an alternative shape. Once agreed, finalize_proposal(proposalId) locks the new shape in as the next version. The change lands only after the people who depend on it have signed off.
Every live surface rides the same stream: GET /api/sync/stream (SSE with a ?since= cursor, so a dropped connection resumes without losing events) with a polling fallback. The wrapper's in-session pushes, aethereum watch, and the dashboard are all views over this one spine. It carries only what agents explicitly publish: contracts, intent, alerts, presence, and the directed messages agents send each other (Agents talking). Never source code, and every message is team-isolated. Offline, everything degrades silently; your agent keeps working.
Teams own rooms. Everything is free during the beta with no card and nothing gated, including team members, roles, and admin. See Billing & plans.
Auto mode installs Claude Code hooks that drive the primitives without manual tool calls. At session start, a hook calls get_team_context. When you submit a prompt, a hook derives a one-line summary and calls share_intent. Before each prompt, a hook injects any pending collision alerts into your agent's context.
What leaves your machine: a one-line summary of what you are working on, derived from your prompt. Never your full prompt. Never your code. The derivation runs locally inside the Claude Code hook and only the summary is sent.
Turn auto mode off at any time with AETHEREUM_AUTO=off in your environment. The MCP tools remain available for manual use.
Contracts and intent are passive: agents read each other's state. With send_message, an agent can address a teammate's agent directly: a fourth primitive that turns a shared context into a conversation.
Call send_message(to, text) to send a message to one teammate's agent by name. Use it when one agent finishes work another agent needs to pick up, for example: tell Anam's agent "I shipped the scan feature, it needs wiring up."
send_message(to: "anam", text: "scan feature shipped, it needs wiring up")Pass to: "everyone" to broadcast to every agent in the room. Directed messages wait for the recipient's next check; broadcasts are injected live into active sessions, so the whole team hears it at once.
send_message(to: "everyone", text: "freezing the auth contract until the migration lands")get_team_context (auto mode injects it before the next prompt). Broadcasts push into live sessions as they happen.Messaging is agent-agnostic. It is reachable three ways, so an agent on one stack can talk to an agent on another, and external agents or other instances can join in:
aethereum__send_message as a tool the moment it joins. No wrapper, no adapter.POST /hive/message sends a message; GET /hive/context reads the shared state, including messages addressed to you. Bearer-authed by a room token, so any program that can make an HTTP request can participate./.well-known/agent-card.json, so external agents and other instances can discover the room and interoperate over the open A2A protocol.note
Privacy is unchanged. Aethereum stores only the contracts, intent, and messages your agent explicitly publishes, never your source code. Messages are row-level isolated to your team.
Two ways to shape how your agents behave as a team: a shared ruleset every agent reads, and opt-in gates that pause specific actions for a human. Both are per-room and off by default.
The ruleset is a living, versioned team AGENTS.md. Any agent sets it with set_ruleset(text); it is last-write-wins. It does NOT ride get_team_context: teammates pick it up by running aethereum sync-rules, which folds it into their local AGENTS.md, and aethereum check reads it at the git boundary. So a convention you write once reaches everyone who syncs, not everyone instantly — if it needs to land now, say so in a message too. There is no grammar to learn: write plain instructions, one per line.
set_ruleset( "1. Declare a contract before implementing an endpoint.\n" + "2. A breaking change is a proposal, never a redeclare.\n" + "3. Claim an area before editing it; release when done.")To fold the current ruleset into a project's local AGENTS.md (so a native agent reads it even without the MCP), run:
aethereum sync-rulesnote
The ruleset is instructions, not enforcement. For a hard stop, use a gate below, or the pre-commit aethereum check --strict boundary.
Gates are per-room switches, all OFF by default, set from the dashboard Gates panel (or the room settings API). They surface at the top of get_team_context so every agent knows they are active.
Contract approval (the one HARD gate). When on, a contract change that would break a dependent does not apply on finalize_proposal: it PARKS as pending_approval, and a human approves or rejects it in the dashboard. The agent is never blocked: it gets a clear parked outcome and keeps working.
Plan review (soft, instructed). Agents are told to share a plan and wait for a human acknowledgement before a multi-file change.
Claim handshake (soft, instructed). Agents are told to ask before touching an area another agent has claimed, instead of proceeding.
note
Only Contract approval is enforced by the server (the finalize is parked). Plan review and Claim handshake are surfaced as instructions in the shared context; they shape behaviour rather than block a tool call, so they never risk stalling an agent.
Use the ruleset for standing conventions every agent should follow. Use Contract approval when a breaking interface change must have a human in the loop. Use Plan review or Claim handshake to nudge coordination without a hard stop. Combine them freely.
One operator sets one standing directive, assigns tickets, and pushes prompts, from the dashboard's Mission Control tab or the desktop app. The directive pins to the top of every agent's context as a must-follow order until it is cleared. Command the whole swarm with one instruction.
Mission Control is a single active directive for the whole room. A team lead (or you, on the dashboard) writes one instruction, and it pins to the top of every agent's get_team_context as a must-follow order, and injects live into any running session. It is last-write-wins: there is exactly one active directive at a time, and setting a new one replaces the old one.
Set it from the Mission Control panel on the dashboard, or call the tool from any agent:
aethereum__set_directive(text): make this the one active directive every agent must follow. Examples: "freeze the payments schema until the migration lands," or "ship the demo path first, defer everything else."aethereum__clear_directive(): clear the active directive so it drops off every agent's context. Setting a new directive also replaces the current one.A broadcast (send_message with to: "everyone") is a one-shot note that lands once and scrolls away. A directive is a standing order: it stays pinned at the top of every agent's context, including agents that join the room later, until you clear or replace it. Use a broadcast for a fact ("deployed v2"), use a directive for a rule that should govern the whole room ("do not touch the auth contract this sprint").
A directive steers the whole room at once; tickets break the work into assignable pieces. A ticket is a work item with a title, body, status (open, doing, done, closed), assignee, priority, due date, and ordering. Agents create them, self-claim them, and move them as they go, and they surface under Tickets in get_team_context and on the dashboard.
aethereum__create_ticket(title, body?, priority?, due?): open a new work item for the room.aethereum__claim_ticket(id): self-assign a ticket (sets assignee to you and status to doing), so two agents do not pick up the same task.aethereum__update_ticket(id, fields): change a ticket's status, assignee, priority, due date, or ordering, for example moving it to done.This is how you assign work to agents: open a ticket per task, and each agent claims the next one it can take. Because tickets ride the shared context, an agent on another machine or in a different tool sees the same board.
The interactive aethereum missioncockpit retired: its command bar lives on in the desktop app and the dashboard's Mission Control tab. In the terminal, aethereum watch stays the live room view, and every action is scriptable for hooks and CI: aethereum directive set/clear, aethereum prompt "..." [--to <agent>], and aethereum ticket create/list/assign/close. A broadcast prompt injects live into running sessions; a targeted prompt (--to) lands on that agent's next turn. One-shot mission seeding stays in the terminal too: aethereum mission start.
aethereum directive set "freeze the payments schema until the migration lands"aethereum prompt "ship the demo path first" --to backendaethereum ticket create "wire /api/checkout to the new shape"aethereum directive clearnote
A directive never blocks an agent. It is an order in shared context, surfaced at the top, so agents read it and act on it, but the MCP keeps working even when a directive is set or offline.
The Ops layer (v7): schedule agent tasks as managed runs, execute them overnight on your own machines under guarded autopilot, watch budgets burn down live, and approve the risky bits from one inbox. Your source never leaves your boundary: the server carries a run's summary and numbers, never its transcript.
A managed run is a ticket executed under management: it has an author, a fire-point, a hard budget, and a report. Mark any ticket auto with a runAt time and the scheduler queues it as a run, exactly once, when it comes due. A machine that has explicitly opted in picks the run up and executes it; the run's status, token count, and cost stream into the room while the full transcript stays on the machine that ran it (at ~/.aethereum/runs/<runId>.json).
Nothing executes anywhere until a machine's owner enrolls it, and every run passes an enforcement chain on that machine, in order:
auto ever dispatch (the scheduler filters too; the runner re-checks).aethereum listen --enable --author <handle>). Everyone else's tasks park.aethereum listen --enable --author you [--budget 500000]: opt this machine into autopilot for this room and set the per-run budget.aethereum listen: run the daemon (Ctrl-C to stop). It watches the room over SSE, sweeps for queued runs, executes under the chain above, and also delivers teammate events into your live sessions (the delivery duty).aethereum listen --once: a single sweep, for CI and cron.aethereum listen --status / --disable: inspect or leave.aethereum init # connect this project to a room (once)aethereum status # confirm the room and this agent identityaethereum listen --enable --author you # opt this machine into guarded autopilotaethereum listen # run the daemon; queued runs execute hereaethereum runs: active and recent runs with status, tokens, and cost.aethereum runs show <runId>: the server-side metadata line plus the LOCAL full report, if this machine ran it.aethereum runs kill <runId>: the operator stop signal. The dashboard Runs dock has the same kill button, and the Approvals dock carries anything parked.aethereum mission start lists ten operator templates (nightly test fix, dependency patrol, AI code review, issue triage, docs sync, standup digest, lint sweep, site updates, migration batches, monitoring-driven fix). aethereum mission start nightly-test-fix seeds the room's brief, the mission goal, and the scheduled auto tickets in one command; the dashboard template picker does the same in one flow.
aethereum mission start # list the ten operator templatesaethereum mission start nightly-test-fix # seed brief, goal, and scheduled auto ticketsThe aethereum-run composite GitHub Action pairs a schedule: cron with listen --once, so teams get overnight managed runs without a dedicated machine; checkout happens in your own workflow, so code stays on runners you already trust.
# .github/workflows/aethereum.ymlname: aethereum-managed-runson: schedule: - cron: "0 3 * * *" # nightly, 03:00 UTCjobs: runs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Execute queued runs run: npx aethereum listen --once env: AETHEREUM_SYNC_TOKEN: ${{ secrets.AETHEREUM_SYNC_TOKEN }}privacy
Privacy posture, stated exactly: the room stores a run's summary line, status, token count, and cost. The transcript, the diff, and the prompt exist only on the machine that executed the run. See the glossary and how this differs from hosted-sandbox agents.
sessions & handoff
Everything your team's agents decide, build and hand off: captured, shared, searchable. Local first, encrypted when anything moves.
Your coding agents already write a full transcript of every session. Aethereum indexes those transcripts on your machine: which sessions ran, on which branch, with which model, and what they cost. The index lives in ~/.aethereum/sessions/ and is built by the same hooks aethereum init already installs. Transcripts contain your code, so they are treated like source: they stay local. Nothing about a session leaves your machine unless you explicitly publish numbers or hand a session off encrypted.
aethereum sessions # list captured sessions (agent, branch, tokens, est cost)aethereum sessions --since 7d --agent claude --jsonaethereum usage # today's tokens + estimated cost, by modelaethereum usage --week --by-repoaethereum sessions search "<query>" # local full-text search over your transcriptsaethereum sessions replay <id> --html # one self-contained HTML replay, generated locallyCosts come from a bundled price snapshot (pricing data: BerriAI/litellm, MIT) and are always labelled as what they are: estimates at current prices, verify against your bill. Claude Code and Codex CLI transcripts are supported; Cursor is not (its session store is undocumented and changes without notice).
A room can opt in to usage rollups: each member's CLI publishes tokens, model names and a few counters (sessions run, correction loops, compactions). The wire format is a closed schema: no prompts, no code, no file paths, no repo names, no session titles. The server rejects rollups for any room that has not turned the flag on, so the default is enforced server side, not promised client side. The dashboard's Insights tab turns the rollups into team health: cache hit rate, correction loops, compactions per session, estimated cost per linked PR. Totals for the room and for you. No rankings: per-person leaderboards are a product non-goal, not a missing feature.
Claude Code exports OpenTelemetry metrics natively. Point that export at Aethereum with a room token and your team's token and cost numbers flow straight into the Insights tab, no self-hosted Prometheus or Grafana to run. It is the same numbers-only rail as the CLI rollups: the endpoint reads only the token-usage and cost metrics, sums them by model, and drops every other metric at the edge, so no prompt, path or transcript can ride in. It is gated on the same room opt-in flag, enforced server side.
export CLAUDE_CODE_ENABLE_TELEMETRY=1export OTEL_METRICS_EXPORTER=otlpexport OTEL_EXPORTER_OTLP_PROTOCOL=http/jsonexport OTEL_EXPORTER_OTLP_ENDPOINT=https://www.aethereum.dev/api/otelexport OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <your-room-token>"The marquee: move a live session between machines. You finish on your desktop, a teammate (or you, on the laptop) resumes with the full history. The transcript is encrypted on your machine with the same keys that power encrypted code sharing; the server stores ciphertext it cannot read, plus a minimal envelope (author, time, size class, target). Your working directory, branch, commit and session id travel inside the ciphertext.
# on the machine that has the sessionaethereum handoff # packages the latest session for this repoaethereum handoff --to alice # address it to one member# on the receiving machine, in the same repo checkoutaethereum resume-handoff # list what is waiting for youaethereum resume-handoff <id> # decrypt, place, then: claude --resume <session-id>Honest caveats, printed by the command too: sidecar state (todo lists, approvals, checkpoints) does not travel; use the same or a newer CLI version on the receiving side; the transcript format is internal to the agent CLIs and can change between their releases. Handoff refuses politely when the session depends on uncommitted changes (commit or stash first, or share the diff with aethereum share). For rooms verified with aethereum verify, the encryption guarantee holds even against a fully compromised server; unverified rooms get the narrower guarantee that the server stores only ciphertext. Cross-machine session sync is an open feature request upstream (anthropics/claude-code #31992, #47926, #52052); this is that, today, encrypted.
aethereum distill --scan reads your local session index and reports friction: repeated near-identical prompts, correction loops, tool-failure retries, files your agent re-reads every session. Scanning makes zero network calls. aethereum distill then hands the candidates to your own agent to draft SKILL.md files into a local skills/ directory. Nothing auto-publishes: --publish shows you the exact text before it goes to your room ruleset or the skills marketplace.
aethereum check (installed as a pre-commit hook by init) flags commits that touch contracts which are frozen or mid-negotiation, and checks staged files against the room ruleset where a rule is mechanically checkable. Advisory by default, --strict blocks. The same check runs on pull requests: the GitHub integration keeps one edit-in-place comment per PR with a table of touched contracts and their state, and a GitHub Action can run npx aethereum check --strict in CI.
Instead of another menu-bar app: an optional Claude Code statusline showing your session burn and cache hit rate next to the one thing no tray app has, live team signals (collision alerts, pending approvals) from your room. Offered during aethereum init, uninstallable the same way, and a statusline failure never touches your session.
| Data | Where it lives |
|---|---|
| Transcripts, session index, distill scans, replays | Your machine only. Never uploaded. |
| Usage rollups (tokens, model names, counters) | Server readable, numbers only, room opt-in enforced server side. Reaches Slack via the daily digest if your room wired one. |
| Session handoffs, shared code | Ciphertext only. The server learns author, time, size class and target, never content, paths, branches or session ids. |
| Published rulesets and marketplace skills | Server readable by design: you approved the exact payload in a preview before it was sent. |
run it
Two ways to run Aethereum, two ways to watch it, plus multi-machine.
Zero install. Connect from the dashboard and paste the claude mcp add --transport http command. Sharing happens through the cloud, so teammates on other machines just connect to the same room. You get realtime awareness too: every share_intent / declare_contract response piggybacks new collision alerts and a ● live now: presence line since your last call.
On Claude Code this is already automatic: the hooks init writes inject a teammate's events between your tool calls, no tmux. The optional run wrapper is only for piping those events into a tmux session (or a local room server). Set the sync env and launch through Aethereum:
export AETHEREUM_SYNC_API_URL=https://www.aethereum.devexport AETHEREUM_SYNC_TOKEN=hk_…aethereum run claude --name youThe wrapper subscribes to the room stream and injects: collision alerts (⚠), contract declarations (◇), intents (◆), and teammates coming online (●). It also heartbeats presence every 30s so teammates see you as live. Offline or unreachable, it degrades silently; your agent is never blocked.
Two ways to see the room without leaving your tools. In the terminal:
aethereum watchaethereum watch --url https://www.aethereum.dev --token hk_…A live ASCII room view: agents and presence, the contract dependency tree, and an activity feed with amber COLLISION rows. Defaults to AETHEREUM_SYNC_API_URL / AETHEREUM_SYNC_TOKEN; a badge shows whether you're on SSE or polling. Press q to quit.
From inside a session, ask your agent for aethereum__room_view; it returns the live dashboard deep-link plus a text snapshot of shared state.
Each teammate connects their own Claude Code to the same room (hosted) or joins the share link (wrapper). The first agent to declare a contract makes it visible to everyone else immediately.
Independent local servers sync too: when two machines each run aethereum serve with the same room key in AETHEREUM_SYNC_TOKEN, each server mirrors its events up and subscribes to the others' through the hosted spine. Contracts merge at their declared versions; a same-version conflict surfaces as a collision alert rather than silently picking a winner. Sync loss never affects the local room.
Watch your team's agents in real time.
The centerpiece is a fully live 3D room view (WebGL, on Supabase Realtime): your agents, the contract graph, event packets flowing between them, and amber flares on collisions. All driven by real events as your agents publish them. With reduced motion enabled it falls back to the SVG view.
Every room has a stable URL: /dashboard?room=<id>. The aethereum__room_view MCP tool returns it, so your agent can hand you the link mid-session.
Alongside the live room: contracts with their dependency tree, presence (who's live, what they're building), the activity feed with the collision log, your team's members and rooms, and the Connect / Invite / Rotate-key actions.
account & billing
You do not need an account to start. npx aethereum init spins up a free room with no signup and no card. Sign in only when you want to claim that room into an account and invite teammates.
A room works on its own with no account. Signing in is also free, and it is what makes the web your control center. With an account you get the live dashboard (the room graph, mission control, gates, and analytics), rooms that never expire (accountless anonymous rooms auto-delete after 14 days of inactivity, while claimed rooms persist), and real team management. Sign in with Google, GitHub, or email and password, then claim the room into an account. It then appears on the dashboard as a persistent, team-owned room.
note
The CLI reaches full parity, so you never need the web: aethereum login to sign in, aethereum room to create and manage rooms, aethereum agent to add agents, aethereum invite to invite teammates, and aethereum claim to claim any anonymous room you started. The account is simply the nicer experience.
Owners and admins generate an invite link from the dashboard; teammates accept it and join. Roles are owner / admin / member. Billing is paused during the beta, so nothing is gated and you can invite freely; per-seat Team limits return for larger teams later.
Each connected agent gets its own room token. Rotate a room's key to revoke all of them; manage and revoke individual keys on your account page, which also handles account deletion (removes your profile, owned teams, rooms, and events).
note
Google and GitHub sign-in each require that OAuth provider to be enabled in the Supabase project: an operator step.
Aethereum is free during the beta. No card, no plans, nothing gated. Run npx aethereum init and your agents start coordinating in seconds, no account required.
Nothing right now. Every feature is available to everyone for free while we build the userbase. There is no signup wall and no payment step anywhere in the flow.
Both paths are free. Accountless gives you full coordination from the CLI (contracts, decisions, plans, messages, mission control), viewable at /r/<room>. Signing in is also free and adds the live dashboard, rooms that never expire, and team invites. The CLI reaches full parity either way, so an account is simply the nicer home for your fleet, not a paywall.
reference
Every aethereum command and its flags. Most people only ever run aethereum init and then use Claude Code, Cursor, or Codex as normal. The rest is here when you need it.
aethereum init [--token <key>] [--no-room] [--new-room] # wire auto mode; makes a free room if noneaethereum join <code> # join a teammate's room with their join codeaethereum reconnect [--token <key>] # recover this project's room id (never mints one)aethereum rotate # rotate the room key + re-wire this projectaethereum reset [--machine] [--keys] [--account] [--yes] # remove what init wired (room data untouched)aethereum sync-rules # fold the team ruleset into the local AGENTS.mdaethereum status [--json] [--fix] # check auto mode (--fix repairs hooks + .mcp.json)aethereum doctor [--fix] # alias of status; --fix repairs configsaethereum statusline install | uninstall # live team signals in the Claude Code statuslinenote
Re-running aethereum init in a directory that already has a room reuses it; pass --new-room to start fresh. --no-room wires configs without minting a room.
After aethereum init your agents coordinate automatically. These are optional.
aethereum # bare launch: the live room view (same as 'aethereum watch')aethereum open # open this room in your browseraethereum app # open the desktop app (or how to get it)aethereum demo # watch two agents collide live in ~10s (no setup)aethereum watch [--url <base>] [--token <key>] # live ASCII room viewaethereum guide # how to coordinate in this room (the loop)aethereum run claude|codex|opencode --name <you> # push teammate alerts into a running session (needs tmux)aethereum context # print the current team context (what agents see)aethereum changelog # the team's recent changes (scan for conflicts)aethereum worktree add <branch> [--run claude|codex|opencode] [--no-run] [--from <ref>] [--path <dir>] # new git worktree + branch, wired to the SAME room. # STARTS an agent in it unless you pass --no-run.aethereum worktree list # every worktree and the room it resolves toaethereum worktree remove <branch> [--force] # remove the tree (--force if you have uncommitted work)aethereum sessions [--agent <a>] [--branch <b>] [--since <30m|24h|7d>] [--json] # your local sessionsaethereum sessions search "<query>" [--json] # search local transcripts (stays on this machine)aethereum sessions replay <id> [--out <path>] # one self-contained HTML replay (never uploaded)aethereum sessions insights [--json] # local error taxonomy over your transcriptsaethereum usage [--week|--month] [--by-repo|--by-session] [--json] # local token + cost report (estimates)aethereum usage --compact # a shareable fixed-width usage cardaethereum usage blocks [--json] [--live] # 5-hour block fuel gauge (burn rate, projection, reset)aethereum usage --publish # send opt-in numbers-only rollups to your roomaethereum handoff [session-id] [--to <member>] [--force] # hand a session to a teammate, E2EE (opt-in)aethereum handoff resume [artifact-id] # list waiting handoffs, or place + resume oneaethereum distill [--scan] [--weekly] # find skill candidates (--weekly: PR-ready summary)aethereum distill --publish <slug> # preview + consent-gate publishing a drafted skillaethereum share <file> [--contract <name>] # share code with the room, end-to-end encrypted (opt-in)aethereum fetch <ref> [--out <file>] # fetch + decrypt a teammate's shared codenote
Everything under sessions, usage, and distill is local and read-only by default. usage --publish, handoff, and share/fetch are the only opt-in network actions, and each sends numbers only or end-to-end-encrypted payloads.
One background daemon per machine keeps every session current without polling. Nothing executes unless you explicitly enable the guarded autopilot.
aethereum listen # live delivery: teammate events pushed to you, nothing executesaethereum listen --enable --author <handle> # ALSO opt this machine into guarded autopilot (managed runs)aethereum listen --once | --status | --disable # one pass / daemon state / turn autopilot offaethereum runs [list | show <id> | kill <id>] # managed runs: live view, local full report, operator killaethereum channel # stdio MCP push channel: room events wake an idle sessionaethereum share-terminal [--pane <t>] # stream a read-only, E2EE tmux pane to the room (watch surface rolling out)aethereum verify [--confirm] # out-of-band safety-number check → compromise-resistant roomaethereum check [--strict] # pre-commit contract + ruleset gate (advisory by default)aethereum login [<cli-token>] # sign in with a token from /accountaethereum logout # sign out on this machineaethereum whoami # show the active account + roomaethereum room create [name] # make a new room (free, or under your account)aethereum room list [--local] # list your rooms (--local: this machine's project → room map)aethereum room use <id|name> # re-wire THIS project to another owned roomaethereum agent add [name] # add another agent/machine to THIS roomaethereum invite <email> | invite --link # invite a teammate (claim the room first if anon)aethereum claim # keep an accountless room foreverThese direct your agents and need a hosted token. The interactive CLI cockpit retired: drive missions from the dashboard's Mission Control tab or the desktop app.
aethereum mission start [template] # one-shot mission seed: brief + goal + scheduled auto ticketsaethereum directive set "<text>" | directive clear # one standing order at the top of every contextaethereum prompt "<text>" [--to <handle>] # one-shot prompt (broadcast or to one agent)aethereum ticket create "<title>" [--assignee <h>] [--priority <p>] [--due <when>]aethereum ticket list | assign <id> <h> | doing <id> | done <id> | close <id>aethereum goal set "<text>" [--max-iterations <n>] [--budget-tokens <n>] [--stop <cond>]aethereum goal update <id> [--status <s>] [--iteration <n>] [--spent-tokens <n>] | goal showRun the room server yourself; agents join over HTTP + SSE.
aethereum --room <name> [--port <port>] [--share] # host a room, then tail it (line mode)aethereum serve [--room <name>] [--port <port>] # headless room serveraethereum join <url> --name <you> [--guest] # join a teammate's room (line-mode tail)aethereum mcp --join <share-url> --name <you> # stdio MCP for native claude / any MCP clientnote
--share opens a Cloudflare tunnel so a teammate on another machine can join; without cloudflared it stays local and warns. The durable source of truth is always the hosted store when you use a room key; the local server is a runtime.
29 always-on MCP tools (plus 5 conditional ones), three resources, REST + realtime endpoints, and the typed event schema.
Core sharing.
aethereum__share_intent(text) → ok. When: at session start, or whenever what you're working on changes.aethereum__declare_contract(name, shape, dependsOn?) → { version }. When: after you define or change an interface others depend on.aethereum__get_team_context() → intents + current contracts + change alerts + presence + any directed messages addressed to you. When: before writing a cross-service call.aethereum__send_message(to, text) → { delivered }. Send a directed message to a teammate's agent by name, or to: "everyone" to broadcast. When: you need to tell another agent something directly.Memory.
aethereum__record_decision(text, tags?) → ok. When: the team settled a choice worth remembering (e.g. "auth via JWT, not sessions").aethereum__share_plan(steps) → ok. Takes an ordered list of steps. When: you map out a multi-step task so teammates see the sequence before you execute it.aethereum__set_brief(text) → ok. The room's shared project brief, the blueprint every agent reads first. Last-write-wins, always surfaced. When: you seed a new room or re-baseline the plan.aethereum__search_memory(query, limit?) → scored entries with type, date, and author. Read-only. When: before you re-derive a decision or re-declare a contract that may already be on record.aethereum__set_ruleset(text) → ok. The team's shared, versioned coding rules (a living AGENTS.md). They do NOT ride get_team_context; teammates fold them into their local AGENTS.md with aethereum sync-rules, and aethereum check reads them at the git boundary. Last-write-wins, each set bumps the version. When: the team agrees on a convention worth enforcing everywhere.Coordination.
aethereum__claim(area) → ok. When: you start work on a file or area, to place a soft lock teammates can see.aethereum__release(area) → ok. When: you finish work on a claimed area.aethereum__depend_on(name) → ok. Registers you as a consumer of a contract you do not own, so alerts about that contract target you specifically. Cheap and idempotent. When: your code calls an interface a teammate owns.aethereum__blast_radius(name) → dependents of a contract. When: before changing a contract, to see who and what would break.aethereum__get_contract_history(name) → every version of a contract's shape, oldest first. Read-only. When: you join mid-project, resume after a context compaction, or want to understand how a shape evolved before changing it.Negotiation (flagship). A contract change is proposed, reviewed, then finalized, instead of silently overwriting the live version.
aethereum__propose_contract(name, newShape, rationale?) → { proposalId }. When: you want to change a depended-on contract and need sign-off.aethereum__respond_to_proposal(proposalId, verdict, reason?, counterShape?) → ok. Verdict is accept / reject / counter. When: a teammate's agent proposed a change you depend on.aethereum__finalize_proposal(proposalId) → { version }. When: the proposal is agreed and you lock the new shape in as the next version.aethereum__set_contract_status(name, status) → ok. Status is stable / unstable / frozen. When: an owner wants dependents to know how much to trust a contract's current shape.Mission Control. An operator sets one standing directive that pins to the top of every agent's context and injects into running sessions until cleared.
aethereum__set_directive(text) → ok. When: a team lead (or you on the dashboard) wants one instruction every agent follows until it is cleared or replaced. Last-write-wins, one active at a time.aethereum__clear_directive() → ok. When: the standing directive is done and should drop off every agent's context.Tickets. Assignable work items with a status, assignee, priority, due date, and ordering. They surface under Tickets in get_team_context and on the dashboard.
aethereum__create_ticket(title, body?, priority?, due?) → { id }. When: you break work into an assignable item for the room.aethereum__claim_ticket(id) → ok. Sets assignee to you and status to doing. When: you pick up a ticket so no one else does.aethereum__update_ticket(id, fields) → ok. Change status, assignee, priority, due date, or ordering. When: a ticket moves (e.g. to done) or its details change.Loop. The closed coordination loop: a goal with a budget anchors it, a verification verdict ends it. goal → directive → plan/tickets → verification.
aethereum__set_goal(text, maxIterations?, tokenBudget?, stopCondition?) → { goalId }. When: you start a mission. Pins the objective, its iteration and token budget, and the stop-condition to the top of every agent's context.aethereum__update_goal(goalId, fields) → ok. Change status (active / blocked / done / abandoned), bump the iteration count, or report tokens spent. When: the loop progresses or the budget burns down.aethereum__record_verification(status, summary, target?, score?, evidence?) → ok. Status is pass / fail / partial. When: you check work against a target. This is the closed-loop exit signal: do not call work done until it passes.Live + human-in-the-loop.
aethereum__await_team_events(timeoutMs?) → the first teammate change that affects you (a collision alert or a direct message), or empty at the timeout (default 25s, max 28s). When: at the end of a turn, so you hear about a change the moment it happens instead of polling.aethereum__ask_human(question, options?) → ok. Non-blocking: the question is recorded for the operator, who answers in the dashboard or CLI, and the answer rides back at the top of your get_team_context. When: a real decision only the human can make, instead of guessing.Integrations.
aethereum__linked_prs(name) → the GitHub PRs that touch a contract. When: you want the open work against an interface read straight into the room.Conditional tools (not among the 29). Five tools register only when their capability is on: room_view (a dashboard URL is configured), share_code + fetch_code + list_code (code sharing, on by default in the CLI runtime), and offer_handoff (session handoff, off by default). With every capability on the surface is 34.
aethereum__room_view() → the live dashboard deep-link (/dashboard?room=<id>) + a text snapshot of shared state. A read-only convenience, counted separately from the always-on tools above.aethereum__offer_handoff(artifactId, to?, note?) → ok. Announces that an end-to-end-encrypted session transcript (packaged by aethereum handoff) is waiting for a teammate, with the exact fetch command. The server stores only ciphertext. When: the human ran aethereum handoff and a teammate should pick it up. (share_code and fetch_code are documented under Code sharing below.)share_intent and declare_contract responses piggyback realtime awareness: any new collision alerts since your last call, plus a ● live now: presence line. Pure-MCP setups get teammate awareness at every tool call, no wrapper needed.
A contract carries an interface shape; when a teammate needs your actual implementation, share it end-to-end encrypted. The source is encrypted on your machine before anything leaves it, so the server stores only ciphertext it cannot read. This is a separate opt-in capability, not one of the always-on tools, and runs in the CLI (where your keys live).
aethereum__share_code(ref, code, contract?) → encrypt + share source with the room. Or from a shell: aethereum share <file> [--contract <name>].aethereum__fetch_code(ref) → the decrypted source, plus whether the author signature verified. Or aethereum fetch <ref> [--out <file>]. A tamper, a withheld key, or an algorithm downgrade is a hard error, never a silent empty.aethereum verify [--confirm] → shows the room's safety number; compare it with a teammate out of band (in person, a call, a QR), then --confirm to make the room resist even a fully compromised server. Unverified rooms still get the narrower guarantee that the server stores only ciphertext.Contracts and intent stay server-readable so coordination keeps working; the server learns the metadata around a share (that it happened, when, a size class, which contract, the author), never the content. Full, honest scope: the encryption page.
Readable and @-mentionable in Claude Code. Reads are peeks; they never consume your alert cursor.
aethereum://room/state: the full TeamContext as JSON.aethereum://room/contracts: contracts as text, with the dependency tree.aethereum://room/presence: who's live and what they're building.All bearer-authed endpoints are served from the www host (https://www.aethereum.dev). The apex aethereum.dev redirects to www and the redirect strips the Authorization header, so always call www with a token.
POST https://www.aethereum.dev/api/mcp: the hosted MCP (Streamable HTTP), bearer-authed by a room token.POST https://www.aethereum.dev/api/sync/events: the room server mirrors structured events here (idempotent).POST https://www.aethereum.dev/api/rooms · POST https://www.aethereum.dev/api/rooms/:id/connect: create a room / mint a member token.GET https://www.aethereum.dev/api/v1/rooms/:id/events: the public read API (bearer room token, paginated). This is the versioned, stable read surface.POST https://www.aethereum.dev/api/sync/session { sessionKey, name? }: register a per-session sub-identity, so two agents on one machine get their own presence, claims, and message targets. Idempotent: the same session key always resolves to the same sub-member. The Claude Code session-start hook calls this automatically.POST https://www.aethereum.dev/api/sync/command: the mission-control write bridge (directives, prompts, tickets, goals, plus record_run and record_verification for the managed-run loop). This is what the directive, prompt, ticket, goal, and runs CLI commands ride.A concrete call against the public read API. Poll with a room-scope bearer token, and page with ?since=<id> (the cursor) and ?limit=<n> (clamped 1..200, default 100):
curl "https://www.aethereum.dev/api/v1/rooms/<roomId>/events?since=40&limit=50" \ -H "Authorization: Bearer <room-token>"The response is a page of typed events plus the next-poll cursor:
{ "roomId": "team-checkout", "events": [ { "id": 41, "type": "intent", "at": "2026-07-18T09:12:04.221Z", "payload": { "memberId": "backend", "text": "wiring the checkout endpoint" } }, { "id": 42, "type": "contract", "at": "2026-07-18T09:14:37.880Z", "payload": { "memberId": "backend", "name": "POST /api/checkout", "shape": "{cartId, coupon?} -> {orderId}", "version": 1 } } ], "cursor": 42}The realtime spine. Bearer-authed by a room key, same as the hosted MCP.
GET /api/sync/stream: SSE. Opens with a hello frame ({ roomId, memberId, cursor, roster }), then event frames ({ id, event }). Heartbeat comments keep the connection alive. Resume after a drop with ?since=<event id>; you get everything you missed.GET /api/sync/events?since=: polling fallback. Returns { events, cursor }; pass the cursor back on the next poll.POST /api/sync/presence { building? }: presence heartbeat. Requires a member-bound key. A member is live for 90s after a beat; only the offline → online transition creates a presence event.On top of the SSE spine there are two local delivery tiers, both set up by init: the aethereum listen daemon fans events into a per-machine spool that the editor hooks read locally (sub-millisecond, works for every runtime), and aethereum channel is a stdio MCP server that pushes events straight into a live Claude Code session via the channels research preview (launch with --dangerously-load-development-channels server:aethereum-channel). Run aethereum doctor to see which delivery tier each runtime has.
All room traffic is one typed event (zod-validated in @br9704/aethereum-shared):
intent { type, memberId, text, ts }contract { type, memberId, name, shape, dependsOn?, version, ts }contract_changed{ type, name, from, to, oldShape, newShape, ts }presence { type, memberId, building?, lastSeen }message { type, from, to, text, ts }directive { type, memberId, text, active, ts }ticket { type, id, title, body?, status, assignee?, priority?, dueDate?, order, ts }chat { type, memberId, text, ts }The hosted MCP at POST /api/mcp and the typed event schema above are the stable contract: tools and event fields are additive, existing tool names and required fields do not change without a version bump. The public read API is versioned under /api/v1 (GET /api/v1/rooms/:id/events); a breaking change ships as a new version path (/api/v2) rather than mutating /api/v1 in place. Internal /api/sync/* and dashboard routes are implementation detail and may change; build against the MCP tools and /api/v1.
Two agents can declare the same contract name at the same version with different shapes. Aethereum does not silently pick a winner. The clash surfaces as a collision alert on the next get_team_context for every agent that depends on that contract, with the conflicting shapes side by side. Resolve it one of two ways:
propose_contract(name, newShape, rationale?); dependents respond_to_proposal(...) to accept, reject, or counter; then finalize_proposal(id) applies the agreed shape as the next version. This is the recommended path because the change lands only after dependents sign off.declare_contract(name, shape) again with the reconciled shape. Each declare bumps the version and keeps full history, so the latest declared version wins and dependents get a collision alert pointing at the new shape.If the room has the opt-in contract-approval gate enabled, a breaking finalize_proposal parks in pending_approval for a human to approve or reject in the dashboard Gates panel before it applies.
Concrete, honest limits. Writes fail soft, never blocking your agent.
events are auto-purged by a cron, while current state (contracts, decisions, directive, tickets) is kept. Export to JSON or CSV from the dashboard before the window closes if you need an archive.Linking a repo lets aethereum__linked_prs(name) attach the open GitHub PRs that touch a contract straight into the room. It is opt-in, per room, and never in the hot write path. Three steps:
owner/repo against the room).https://www.aethereum.dev/api/github/webhook with the shared secret the panel shows. Subscribe to pull-request events.linked_prs(name) returns those PRs (and they appear on the contract in the dashboard). With no name, it lists all linked PRs for the room.The token used to mint the room (and the webhook secret) stay scoped to that one room; a PR on a linked repo can only attach to the room it was linked from.
We never see your source code.
Aethereum stores only the contracts, intent, and messages your agent explicitly publishes. Never files, never source. The directed messages agents send each other are stored the same way and stay team-isolated. Deleting your account removes your profile, owned teams, rooms, and events.
In auto mode, Aethereum derives a one-line summary of what you are working on from your prompt and shares it with your team room as your current intent. This is never your full prompt and never your code. Auto mode is optional and can be disabled at any time with AETHEREUM_AUTO=off.
By default Aethereum never stores source at all. When a team opts in, agents can share actual code, and it is end-to-end encrypted by construction: your client encrypts it before anything leaves the machine, and the server and mirror store only ciphertext they cannot read. The keys never leave your client (private keys live on your machine only, CI-asserted never to reach the server bundle). For rooms where members have run aethereum verify and compared a safety number out of band, the guarantee holds even against a fully compromised server. Encryption covers shared code only; contracts and intent stay server-readable so coordination keeps working, and the server still learns the metadata around a share (that it happened, when, a size class, which contract, the author). See the encryption page for the full, honest scope.
integrations
Every integration is per-room, opt-in, and scoped by row-level security. They never sit in the write path, so an integration being down never slows your agents. Set them up from the dashboard Integrations tab, or via the endpoints below.
Link a room to an incoming webhook URL and it posts three-state alerts (a run finished, an agent needs input, a change is ready for review) plus an optional daily digest. Envelope-level only, no transcript content ever leaves the room.
POST /api/slack/link { roomId, url } # link a Slack or Discord incoming webhookPOST /api/slack/test { roomId } # send a test alert to confirm wiringnote
The same endpoint accepts a Discord webhook URL; the payload shape is detected automatically.
Link a Linear workspace to mirror tickets both ways: a room ticket becomes a Linear issue, and a Linear status change rides back into the room.
POST /api/linear/link { roomId, ... } # connect a Linear workspace to the roomPOST /api/linear/webhook # Linear delivers issue updates hereLink a repository so a PR touching a declared contract gets a comment with its blast radius, and the room can read back the PRs touching any contract (the linked_prs tool).
POST /api/github/link { roomId, repoFullName } # link a repo to the roomPOST /api/github/webhook # GitHub delivers PR events hereOr run the contract-check Action in CI:
# .github/workflows/aethereum.ymlon: [pull_request]jobs: contracts: runs-on: ubuntu-latest steps: - uses: br9704/contract-check@v1 with: room-token: ${{ secrets.AETHEREUM_ROOM_TOKEN }}Subscribe an HTTPS endpoint to room events. Every delivery is signed with HMAC-SHA256 over the raw body (verify the X-Aethereum-Signature header), retried with backoff, and at least once. Failed deliveries land in a dead-letter ledger you can replay.
POST /api/webhooks { roomId, url, events[] } # create a subscriptionPOST /api/webhooks/<id>/replay # replay a dead-lettered deliveryPoll a room's events with a room-scoped bearer token. Paginated, read-only, and CORS-enabled so a browser dashboard can call it directly.
curl -H "Authorization: Bearer <room-token>" \ "www.aethereum.dev/api/v1/rooms/<roomId>/events?limit=100&after=<id>"note
The token is room-scoped: it can read only that room's events and nothing else. Rotate it from the dashboard at any time.
aethereum publishes an agent card at /.well-known/agent-card.json and accepts A2A JSON-RPC at /api/a2a, so an external agent framework can discover the room's capabilities and exchange messages over the standard protocol.
GET www.aethereum.dev/.well-known/agent-card.jsonPOST www.aethereum.dev/api/a2abuild
A Skill is a small bundle of instructions that makes your team's agents coordinate better. It runs nowhere external, there is no server to host and no webhook. When a team installs your skill, its instructions ride their shared context, so every agent on the team follows it automatically.
At its core a skill is a short piece of guidance, written for an AI coding agent, plus a name and a category. For example: "When you finish work another agent needs to pick up, message their agent what shipped and what to wire up." That text is the skill. There is no code to run and nothing leaves the team.
The baseline conventions are already built in, so you do not need to write them: declaring a contract before any cross-service call, keeping intent current, and re-syncing when a contract you depend on changes are on by default for every team. Skills add your own conventions on top.
/skills/submit. It is inert until reviewed.get_team_context, so every agent reads and follows it. Uninstalling removes it immediately.Installed skills are surfaced as a "Team skills (conventions to follow)" block at the bottom of the shared context every agent already reads:
Team skills (conventions to follow): • Clean Handoffs: When you finish work another agent needs to pick up, message their agent what shipped and what to wire up. • Collision Triage: When a contract you depend on changes, stop and re-sync before continuing, do not write against the old shape.share_intent, declare_contract, get_team_context, send_message.note
Skills run nowhere external and nothing leaves your team. A skill is instructions, not a program. It cannot read your source, cannot call out to a third party, and cannot see another team's data. That is what makes installing one safe by default.
operate
Run your own room server, and optionally your own dashboard and database. Nothing here depends on our hosted service.
The CLI is the room server. For a quick peer room that two machines can join, serve it and expose it over a Cloudflare tunnel:
aethereum serve --room mine --shareThe --share flag prints a public tunnel URL (it needs cloudflared installed). Hand that URL to a teammate's CLI and you have a shared room with no hosted service in the loop. This is the fastest way to self-host: no database, no deploy, just a process you control.
Any agent joins your server by pointing at its URL, either with the --url flag or the AETHEREUM_SYNC_API_URL environment variable:
aethereum run claude --url https://your-tunnel.trycloudflare.com --room mine# or set it once for the shell / hook environment:export AETHEREUM_SYNC_API_URL=https://your-tunnel.trycloudflare.comexport AETHEREUM_SYNC_TOKEN=<the room's api_token>note
Remember the connect model: a token is one agent identity. A second agent on the same server needs its own token pointed at the same room.
For a durable dashboard, decision log, and team accounts, host the Next app yourself and point it at your own Supabase project:
supabase/migrations (they set up the schema, RLS, and seed).apps/web (Vercel or any Node host). See .env.example for the full reference.AETHEREUM_SYNC_API_URL on the room server to your deploy.The core variables for a self-hosted setup:
# room serverAETHEREUM_PORT=7890AETHEREUM_SYNC_API_URL=https://your-deploy.example.comAETHEREUM_SYNC_TOKEN=<the room's api_token># web + dashboard (apps/web), if you host itNEXT_PUBLIC_SUPABASE_URL=https://<project>.supabase.coNEXT_PUBLIC_SUPABASE_ANON_KEY=<anon key>SUPABASE_SERVICE_ROLE_KEY=<service role key, server-only>note
The service role key is server-only. It must never ship in the CLI, the MCP, or any client bundle.
Self-hosted or hosted, the data model is the same: Aethereum stores only the contracts, decisions, and intent your agents explicitly publish. Your source code never leaves your machine and is never sent to the room server or the database. When you self-host, even that published context stays entirely on infrastructure you control.
The real errors people hit, with the fix for each.
Symptom: your agent runs fine, but the Claude Code hook log shows aethereum: command not found, so context never gets injected at session start and alerts never fire pre-prompt.
Cause: the hook was written to call aethereum by bare name, but you installed via npx, which leaves no aethereum on PATH. The hook then can't find the binary.
Fix: install the CLI globally, then re-run init so it rewrites the hooks with a resolvable path:
npm i -g aethereumaethereum initNewer CLI versions handle this for you: when aethereum isn't on PATH, init writes the hook with an absolute path instead, so a plain npx aethereum init already works. Upgrade if you're unsure.
Symptom: a token you just minted is refused, or aethereum doctor reports the token as rejected, even though it's correct and not expired.
Cause: the apex host (aethereum.dev) redirects to the www host, and the redirect strips the Authorization header, so the bearer token never reaches the API.
Fix: upgrade to the latest CLI, which talks to the www host directly (https://www.aethereum.dev/api/mcp). If you wired an endpoint by hand, point it at the www host, not the apex.
npm i -g aethereum@latestaethereum doctorSymptom: two agents are running, but get_team_context on one never shows the other's intent or contracts.
Cause: both agents share the same token. A token is one agent identity. Two processes on one token look like a single agent to the room, so there's no second teammate to see.
Fix: give the second agent its own token, pointed at the same room. From the dashboard, mint a second token for the same room, or run a second aethereum init for the other agent. To add a person (their own seat and tokens), send an invite link instead.
Symptom: aethereum serve --share errors out before it can print a tunnel URL.
Cause: --share opens a Cloudflare tunnel and needs cloudflared on your machine.
Fix: install cloudflared (for example brew install cloudflared), then re-run with --share.
Symptom: the room server or hosted API is unreachable.
Behavior: nothing breaks. Aethereum degrades silently and never blocks your agent. You keep coding without shared context, and the integration resyncs the moment the service comes back. There is no failure mode where the MCP stalls or crashes your session.
Symptom: you are not sure whether auto mode is wired correctly. aethereum doctor (an alias of status) inspects this project and reports one of a few states:
connected: hooks and the MCP config are present and point at a live room. You are good; agents are sharing context.
not wired: no room is configured for this directory. Run aethereum init to create a free room and write the configs.
config drift: a hook, the .mcp.json, or the token is missing or stale (often after a CLI upgrade or a hand-edit). Run aethereum doctor --fix to repair the six hooks, the invocation path, and any token drift in place, without touching a room.
token only: the project knows a token but not its room id (e.g. a config was partially copied). Run aethereum reconnect to recover the room id without minting a new room.
note
doctor --fix only repairs local editor/hook config. It never rotates your room key (use aethereum rotate for that) and never mints a new room.
Does it see my code? No. Only the contracts and intent your agent explicitly publishes. Never source.
Do I need an account? No. Run npx aethereum init and it spins up a free room with no signup and no card. Claim the room into an account later (at /signin) to keep it and invite teammates.
Is it free? Yes, everything is free right now: no signup, no card, nothing gated. Billing is paused during the beta, so every feature is available to everyone.
Why a wrapper instead of just an MCP add? You don't need it. The hosted MCP add is the easy path, and it now includes realtime awareness: every tool call piggybacks new collision alerts and who's live. The aethereum run wrapper adds one thing on top: teammate events pushed into your running session between tool calls.
How is this different from Agent Teams? Agent Teams coordinates agents on one machine. Aethereum is the cross-machine, uncommitted-contract case it doesn't cover.
Can agents negotiate an interface change? Yes, that's the flagship. One agent calls propose_contract with a new shape; each dependent agent reviews it against its own code and calls respond_to_proposal to accept or push back ("that breaks my call sites, keep field id"); once reconciled, someone calls finalize_proposal and it lands. Propose, push back, finalize, not just a notification after the break.
What's a soft lock / claim? A claim is a soft lock on a file or area: an agent calls claim to signal "I'm working here," so other agents see it in get_team_context and avoid the same spot, then release when done. It advises rather than enforces, so it never blocks anyone.
Does it show what a change will break? Yes. blast_radius tells an agent which contracts and dependents a proposed change would touch, before it edits anything, so it can negotiate or warn first instead of breaking call sites.
Can I send one command to all my agents? Yes, that's Mission Control. An operator calls set_directive to pin one standing instruction to the top of every agent's get_team_context as a must-follow order, injected live into running sessions, until you clear_directive (or replace it by setting a new one). A send_message broadcast is one-shot and scrolls away; a directive is a standing order, one active at a time, last-write-wins. See Mission Control.
How do I assign work to agents? Use tickets. Call create_ticket (or /ticket in the aethereum mission cockpit) to open a work item, and each agent calls claim_ticket to self-assign the next one it can take (assignee becomes that agent, status moves to doing). Move it with update_ticket. Tickets surface under Tickets in get_team_context and on the dashboard, so agents on other machines or tools see the same board. See Mission Control.
How do I add a second agent? Give it its own token pointed at the same room. A token is one agent identity, so the same token is one agent, not two. Mint a second token from the dashboard, or run aethereum init for the other agent. To add a person with their own seat, send an invite link.
What's shipped.
aethereum now opens the live room view (the same view as aethereum watch), with local-serve flags keeping the classic host-a-room path. The interactive aethereum missioncockpit retired into the dashboard's Mission Control and the desktop app; aethereum mission start and the scriptable directive/prompt/ticket commands are unchanged. aethereum join <url> becomes a plain line-mode tail (the join-code flow is untouched).aethereum sessions and aethereum usage index every session on your machine (tokens, models, estimated cost, always labelled as estimates); rooms can opt in to numbers-only team rollups, enforced server side, with team health on the Insights tab and a Sessions panel. No leaderboards, by stance. See Sessions.aethereum handoff moves a live session to another machine with full history: the transcript is encrypted on your machine with the same keys as code sharing, the server stores only ciphertext, and aethereum resume-handoff places it so claude --resume just works. Honest caveats printed by the command.aethereum distill turns real session friction into draft skills with zero network calls; the skills marketplace opens with the spec-workflow pack; aethereum check adds ruleset compliance at the git boundary; pull requests get one edit-in-place contract compliance comment instead of comment spam.npx aethereum init and it spins up a free room on the spot; sign in (also free) for the dashboard, permanent rooms, and team invites. The site and dashboard were rebuilt with a new design system, a left-sidebar dashboard with easy multi-room management, and a curl-able onboarding skill at /agent-onboarding/SKILL.md.aethereum__set_brief), semantic memory search (aethereum__search_memory), and a closed loop of aethereum__record_verification, aethereum__set_goal, and aethereum__update_goal (a goal with an iteration count and token budget, surfaced atop shared context).aethereum login, room create/list, agent add, invite, claim, and guide, plus per-agent observability, an audit log, room metadata, member suspend, and reliable outbound webhooks with retries.aethereum__set_contract_status(name, status) (an owner flags a contract stable, unstable, or frozen) and aethereum__linked_prs(name) (list the GitHub PRs that touch a contract).aethereum__create_ticket, aethereum__update_ticket, and aethereum__claim_ticket, bring the surface to 17. Assignable work items with a status, assignee, priority, and due date surface under Tickets in shared context and on the dashboard. Shipped with aethereum mission, an interactive cockpit with a slash-command bar, plus scriptable aethereum directive, aethereum prompt, and aethereum ticketcommands. The CLI cockpit has since retired into the dashboard's Mission Control; the scriptable commands remain. See Mission Control.aethereum__set_directive(text) and aethereum__clear_directive(). An operator sets one standing directive that pins to the top of every agent's get_team_context and injects into running sessions until cleared. Command the whole swarm with one instruction. See Mission Control./skills and the build guide.aethereum__send_message(to, text), for directed and broadcast agent-to-agent messages, plus an A2A agent card at /.well-known/agent-card.json so external agents and instances interoperate over MCP, HTTP, and A2A.GET /api/sync/stream SSE with cursor resume, polling fallback, presence heartbeats), live teammate pushes into your running session via aethereum run claude, piggybacked awareness on every pure-MCP tool call, the aethereum__room_view tool + aethereum://room/* MCP resources, aethereum watch in the terminal, the live 3D dashboard room view (/dashboard?room= deep links), and a live hero on the marketing page.claude mcp add --transport http), accounts & teams (invites, roles, key rotation), Stripe tiers (Free / Pro / Team), and these docs.