The server is a Linux machine with Docker and git, and every agent runs there. Your machine can be Linux, macOS or Windows. It needs git and an SSH key, unless both machines sit on the same tailnet and Tailscale identifies you instead. A passphrase-protected key works through your ssh-agent.
A Linux box with Docker, and the machine you already work on.
The CLI on your machine talks to the server over SSH. The server owns the workspace and the container each agent runs in. What comes back to you is a branch.
The script covers Linux and macOS. On Linux it installs the client and the server; on macOS only the client, since the server is Linux only. Windows downloads the release binary, checks it against the published checksums and puts it on PATH.
One command on the server box writes the systemd unit and the config. It asks for the listen address, the data directory and the tailnet policy, and Enter accepts each default. The SSH host key is generated on first start. SSH on port 2222 is the only thing the server exposes; there is no HTTP listener.
The first identity to link a fresh server becomes its admin, and that is the whole account setup. On a tailnet the server asks Tailscale who is connecting and no key changes hands. Anywhere else your SSH public key is registered. The server's host key lands in known_hosts, with its fingerprint printed for you to compare.
A workspace is a repo plus the server-owned environment its agents run in. The standard image carries git, go, node, python, rust and common build tools, so most projects need no setup; pass --image for one of your own. Linking with a repo path adds an aether git remote over the same SSH port, with no separate credentials.
One command installs the agent, opens a shell inside a server-created container for the vendor's own login flow, and registers it under your membership when you exit. The container has no browser, so pick the device-code option. Logins are per member, are never shared, and never pass through Aether.
The first column is what you pass to --agent, and the paths are inside the run container. A fake harness runs a script from your repo for testing, and an admin can pin any other CLI with a harness definitions file.
| AGENT | CLI | LOGIN AND PROFILE | API KEY ENV | MCP | RESUME |
|---|---|---|---|---|---|
| claude | Claude Code | ~/.claude | ANTHROPIC_API_KEY | yes | yes |
| codex | OpenAI Codex CLI | ~/.codex | OPENAI_API_KEY | no | no |
| pi | pi coding agent | ~/.pi | ANTHROPIC_API_KEY, OPENAI_API_KEY | no | yes |
| amp | Amp | ~/.config/amp | AMP_API_KEY | no | no |
| opencode | opencode | ~/.local/share/opencode | ANTHROPIC_API_KEY, OPENAI_API_KEY | no | no |
Skills, plugins, custom commands and settings mirror one way from your machine to the server, per agent, so the agent there is configured the way yours is. A credential denylist and a content scan hold secrets back, and nothing ever syncs down. The sync daemon pushes on change.
Pick a file and watch where it goes.
A run is one agent execution with its own container, git worktree and branch. It pins the environment and tool snapshot it starts with, so later changes affect later runs and not this one. Scoped commands take --workspace and default to it when there is only one.
Five states, and only one of them waits on you. Pick one to see what it means.
aether gui serves the dashboard from your own machine over your SSH connection and opens a browser tab. attach is the raw PTY of the agent's own TUI. inject drops a message into the transcript as a banner in your member color. Detaching leaves the run alone, because the terminal lives on the server.
Every pane reads one store, kept current by a single socket. The desktop app is the same page in its own window, with notifications and a badge when a run needs you, and it drives the CLI underneath.
When the agent exits its work is already committed and the run parks in needs-attention. Pulling fetches the branch into your clone as a remote-tracking ref and stops there. Closing the run clears it off the board with the outcome recorded.
Each run branches off main as it stood at launch and is named for its task and the tail of its id. Nothing merges without you.
It fetches run branches as they update and pushes your base branch back up, so the next run starts from current reality. It also pushes your agent profile when you change it. install prints the activation line for systemd, launchd or schtasks.
The fake harness runs a script from your repo in place of an agent. Start the server with AETHER_FAKE_AGENT set, launch a run with --agent fake, and a branch carrying the script's commit comes back within seconds. The container, the worktree, the PTY, the commit and the fetch are all real.
Everything happens for real except the agent.
Joining, roles, attribution and budgets.