v0.1.2-alpha.25 is outsee the release →
[ HOW IT WORKS ]

From a bare box to a branch

Every command on this page is one the CLI ships. Set the server up once, register an agent, and from then on the loop is run, watch, pull.


[ THE SERVER ]

Set it up once

What you need

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.

How the pieces connect

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.

my-server:2222 / the path a run takes
YOUR MACHINEaether CLIsync daemonyour clone
BACK IN YOUR CLONEaether/run-014-flaky-authfetched, and left unmerged
THE SERVER BOX
AETHER-SERVERssh :2222 · host key · membersno HTTP listener: SSH only
aether workspace init
aether workspace init
WORKSPACEyour repo, its members, its feed, its budgetand the base branch new runs fork from
aether run "fix the flaky auth test"
aether run
RUN 014claudecontainergit worktreebranch
RUN 015codexcontainergit worktreebranch
RUN 016claudecontainergit worktreebranch

Install

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.

my-server:2222 / shell
$
$

Start the server

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.

my-server:2222 / shell
$
$
$

Link from your machine

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.

my-server:2222 / shell
$
$

Create a workspace and push the repo

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.

my-server:2222 / shell
$
$
$
[ AGENTS ]

Register an agent

Once per agent, per person

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.

my-server:2222 / shell
$
$
$

What ships

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.

AGENTCLILOGIN AND PROFILEAPI KEY ENVMCPRESUME
claudeClaude Code~/.claudeANTHROPIC_API_KEYyesyes
codexOpenAI Codex CLI~/.codexOPENAI_API_KEYnono
pipi coding agent~/.piANTHROPIC_API_KEY, OPENAI_API_KEYnoyes
ampAmp~/.config/ampAMP_API_KEYnono
opencodeopencode~/.local/share/opencodeANTHROPIC_API_KEY, OPENAI_API_KEYnono

Your settings follow you

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.

my-server:2222 / shell
$
$
$

Secrets never sync

Pick a file and watch where it goes.

my-server:2222 / one way, and two guards
YOUR MACHINEthe daemon pushes on changesettings.json
CREDENTIAL DENYLISTper harness, on by defaultsettings.json
CONTENT SCANclient side, on by defaultsettings.json
PROFILE SNAPSHOTon the server, pinned by the next runsettings.json
Through both guards and into the snapshot. The next run to be provisioned pins it.
one way only. Nothing ever syncs back down.
[ A RUN ]

Put it to work

Launch a run

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.

my-server:2222 / shell
$
$
$
$

Run states

Five states, and only one of them waits on you. Pick one to see what it means.

my-server:2222 / where a run can be
Accepted and waiting its turn. The dashboard folds this into Working with the two states after it.
pauseda badge on the card, not a bucket of its ownkilledthe worktree and the transcript both survive it

Watch it, and steer it

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.

my-server:2222 / shell
$
$
$
$

The dashboard

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.

127.0.0.1:41823 / aether gui
workspace switcher
WORKSPACESflaky-auth-fix3 runsdeps-audit1 rundashboard-a11y2 runsdocs-sweep1 run4 workspaces · 7 runsgrouped by member
[ THE RESULT ]

Take the work back

Pull the branch

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.

my-server:2222 / shell
$
$
$

One branch per run

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.

my-server:2222 / one branch per run
mainrun …mgcpedunmergedrun …tx0pggrun …a8jqf1
aether pull 01m04mhf114eap4k85n2mgcpedgit diff main...aether/aether/run-fix-the-flaky-auth-test-mgcpedfetched into your clone as a remote-tracking ref, and left there. Reviewing and merging are yours.

The sync daemon

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.

my-server:2222 / shell
$
$
$

Try it without a vendor account

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.


[ NEXT ]

Several people, one machine

Joining, roles, attribution and budgets.

$ curl -fsSL https://raw.githubusercontent.com/3xDevOps/Aether/main/scripts/install.sh | sh
back to the landing page