Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,15 @@ suggests `aether auth` and exits `2` instead of spending a turn on "auht".

### `aether code "<task>"` — autonomous coding agent
One host loop drives a pluggable brain: cloud (UVT-metered) by default,
`--local` for the Python/Ollama brain. The host renders every event, executes
`--local` for the built-in Ollama brain. The host renders every event, executes
every tool call locally, and verifies the result itself — the final status is
derived from your test command's exit code, never the brain's self-report.
Every run ends with a verdict line: `✓ ok · 4 files changed · tests green · 3m12s`.

| Flag | Meaning |
|---|---|
| `--local` | Use the local brain (Python/Ollama) instead of the cloud. |
| `--local` | Use the built-in offline Ollama brain instead of the cloud. |
| `--resume <id\|file>` | Continue a prior session id, or a handoff file from another machine. |
| `--pool <gb>` | Context pool size in GB (status-bar reach = pool × 233M tokens). |
| `--effort <t>` | Effort tier: `LOW` \| `MED` \| `HIGH` \| `MAX` \| `ULTRA` \| `CODEPRO` (overrides the saved `/effort` dial). |
| `--test-cmd <c>` | Command the verification gate runs (unverified without it). |
Expand All @@ -90,16 +91,35 @@ aether run kronus "audit this service for race conditions and fix them"
```
> Orchestrators are gated to paid tiers. Neo is available on Solo+; Kronus on Pro+.

### `aether resume [id]` — replay a session
### `aether resume [id | export [id]]` — replay or carry a session
Replays a prior local coding session's transcript from `~/.aether-agent/logs/`.
With no id, resumes the most recent session.
With no id, uses the most recent session in this workspace.
```bash
aether resume # the latest session
aether resume <session-id> # a specific session
aether agent --resume <id> "<task>" # resume, then continue working
aether resume # replay the latest session
aether resume <session-id> # replay a specific one
aether resume export # write ./aether-handoff.json
aether resume export <id> --out h.json # …from a specific session, to a path
```
`export` writes a **handoff**: one portable JSON file carrying the task, the
model that ran it, the verify gate's verdict, the failing-test count, the files
the run changed, the verification command, and the repository identity (origin
remote, branch, HEAD). It carries no file contents, no shell commands, and no
absolute paths, so it can be copied to another checkout, machine, or OS.

Continue from either form:
```bash
aether agent --resume <session-id> "<what to do next>" # same machine
aether agent --resume ./handoff.json # anywhere else
aether agent --resume ./handoff.json --model <other> # …on another model
```
With no new task, the run continues the **original** task. Either way the prior
context is summarized into a continuation brief that the brain reads before its
instruction — you never re-paste the conversation. See
[`docs/demo/handoff.md`](docs/demo/handoff.md) for a runnable end-to-end proof.

> Local-first: sessions are read from disk, so resume works offline. When you stop
> a coding run with Ctrl-C, the exact `aether agent --resume <id>` command is printed.
> A session id is workspace-scoped; a handoff file deliberately is not.

### `aether models [use <id>]` — list / pick a model
- `aether models` — list every model **and** orchestrator visible to your tier.
Expand Down Expand Up @@ -381,6 +401,10 @@ Requires an active orchestrator — switch with `/agent neo` or `/agent kronus`
| `AETHER_LOGIN_URL` | `https://aethersystems.net/platform` | Page `aether auth login` opens. |
| `AETHER_TOKEN` | *(unset)* | Inject a session token (CI / headless / embedding). |
| `AETHER_CONFIG_DIR` | `~/.config/aether` | Config + token + REPL-history directory. |
| `AETHER_LOG_DIR` | `~/.aether-agent/logs` | Where session logs (and therefore `aether resume`) live. |
| `AETHER_BACKEND` | `auto` | `local` \| `cloud` \| `auto` — overrides the config `backend`. |
| `AETHER_LOCAL_BRAIN` | *(unset)* | `python` runs the separately-installed Unlimited-Context brain instead of the built-in Ollama one. |
| `OLLAMA_HOST` | `http://localhost:11434` | Where the offline brain looks for Ollama. |
| `AETHER_STREAM_TIMEOUT_MS` | `120000` | Stream open/idle timeout (ms). `0` disables it. |
| `AETHER_NO_ANIM` | *(unset)* | `1` disables all animated status lines and the thinking pulse. |
| `NO_COLOR` | *(unset)* | Any value disables ANSI colors (https://no-color.org). |
Expand Down
69 changes: 60 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,69 @@

# Aether Agent

**A coding agent for your terminal — runs on hosted frontier models or fully offline on your own machine.**
**Start a task on one model. Finish it on another, on another machine.
Your tests decide when it's done.**

[![CI](https://github.com/AetherAI3/aether-agent/actions/workflows/ci.yml/badge.svg)](https://github.com/AetherAI3/aether-agent/actions/workflows/ci.yml) [![License](https://img.shields.io/badge/license-Apache--2.0-06b6d4)](LICENSE) [![Node](https://img.shields.io/badge/node-%E2%89%A524-14b8a6)](https://nodejs.org) [![TypeScript](https://img.shields.io/badge/TypeScript-7-3178c6)](https://www.typescriptlang.org/) [![Release notes](https://img.shields.io/badge/release-notes-7c3aed)](RELEASE_NOTES.md)

**Aether Agent is in beta.** Updates are shipping quickly.
```bash
npm i -g aether-agents --ignore-scripts # or run once: npx --ignore-scripts aether-agents
npm i -g aether-agents --ignore-scripts # Node ≥ 24 · zero runtime dependencies
aether auth login # …or skip it and run on your own Ollama
aether agent "make the failing tests pass"
```

[Install](#install-in-three-moves) · [Models & pricing](#models--pricing) · [Commands](#commands) · [Security](#security) · [Platform](#part-of-the-aether-platform) · [Release notes](RELEASE_NOTES.md)
[Carry the work](#carry-the-work-across-models-and-machines) · [Install](#install-in-three-moves) · [Models & pricing](#models--pricing) · [Commands](#commands) · [Security](#security) · [Platform](#part-of-the-aether-platform) · [Release notes](RELEASE_NOTES.md)

<a href="https://app.aethersystems.net/">
<img width="760" alt="Aether Agent — terminal coding session" src="https://github.com/user-attachments/assets/f7a71cbb-6be2-41ea-b2a4-35c7c0d889d6" />
</a>

</div>

It scans, plans, edits, and runs your tests — in your repo, on your terms. Verification is ground truth: the agent re-runs your test command and reads the exit code itself, so "done" is never the model's word. And with **QOPC memory** it learns from what you accept, revise, or discard — measurably better the more you use it, no config, no fine-tuning.
Aether Agent scans, plans, edits, and runs your tests — in your repo, on your terms.
Two things make it different from the rest of the terminal-agent shelf:

- **Verification is ground truth.** The agent re-runs *your* test command at the end
and reads the exit code itself. A model that says "done" over a red tree gets
marked `incomplete`, and the process exits non-zero. "Done" is never the model's word.
- **The work outlives the session.** Every run leaves a local record. `aether resume
export` turns that record into a single portable file — copy it to another checkout,
another machine, another OS, and `aether agent --resume <file>` picks the thread up
on whatever model you want, with no chat history to re-paste.

**Aether Agent is in beta.** Updates are shipping quickly.

## Carry the work across models and machines

```bash
# machine A — start it on a hosted frontier model
aether agent --model opus5 "make the slugify tests pass"
aether resume export --out handoff.json # ⇄ one file: task, verdict, files, repo

# machine B (or the same one, offline) — continue on a different brain
aether agent --local --model qwen2.5-coder:7b --resume handoff.json
```

The handoff is a summary, not a transcript: the task, which model ran it, the verify
gate's verdict, how many tests were still failing, the files that changed, and the
repository it belongs to. Nothing is keyed to an absolute path, so the receiving
checkout does not have to live where the work started — and no file contents, shell
commands, or credential-shaped values ride along. The next model reads it as a brief
and continues; you never re-paste the conversation.

Run the whole thing yourself, end to end, in about five seconds:

```bash
npm run demo:handoff # two sessions, two models, two checkouts, one verify gate
```

The demo builds a throwaway git repo with a real failing test, runs the real CLI on
model A, exports the handoff, **deletes machine A's checkout and logs**, and finishes
the job in a second checkout on model B. By default the model is a scripted local stub
so the run is deterministic and needs no download or account; `AETHER_DEMO_REAL=1`
runs the identical script against real Ollama models. Either way the last word belongs
to `node --test`, run independently of the agent. See
[`docs/demo/handoff.md`](docs/demo/handoff.md).

## Install in three moves

Expand All @@ -39,9 +84,12 @@ ollama pull qwen2.5-coder:7b # 03 — or go offline: no account, no network
aether agent --local # …same terminal, nothing leaves the machine
```

`aether agent` opens the REPL — chat with the model, slash-commands at hand, the agent edits files and runs your tests **in the same session**. Both brains run through the same host loop, render, tools, and commands — switching just swaps the transport. On the hosted path your code stays local and only the prompt + context you send leaves; on `--local`, nothing leaves at all. The local brain runs on **[Unlimited Context](https://github.com/AetherAI3/Unlimited-Context-LLM)** — Aether's open-source (Apache-2.0) memory engine that gives any Ollama model a billion-token working memory.

> Prefer the installer UI? Download [`install.sh`](install.sh) or [`install.ps1`](install.ps1), inspect it, then run it locally. Set `AETHER_VERSION=0.1.0` (shell) or `-Version 0.1.0` (PowerShell) to pin an exact release. The canonical npm command above verifies registry integrity and disables lifecycle scripts; there are no native or runtime dependencies and no daemon.
`aether agent` opens the REPL — chat with the model, slash-commands at hand, the agent edits files and runs your tests **in the same session**. Both brains run through the same host loop, render, tools, and commands — switching just swaps the transport. On the hosted path your code stays local and only the prompt + context you send leaves; on `--local`, nothing leaves at all. The offline brain is built into the package: it talks straight to Ollama over its OpenAI-compatible endpoint, with the same eight tools and the same permission gate, so `--local` needs nothing beyond Node and `ollama serve`.

> Running the separate Python brain instead — Aether's open-source (Apache-2.0) **[Unlimited Context](https://github.com/AetherAI3/Unlimited-Context-LLM)** engine, which gives an Ollama model a billion-token working memory — is opt-in with `AETHER_LOCAL_BRAIN=python` once you have installed it. It is not bundled with the npm package.

> Prefer the installer UI? Download [`install.sh`](install.sh) or [`install.ps1`](install.ps1), inspect it, then run it locally. Set `AETHER_VERSION=0.2.0` (shell) or `-Version 0.2.0` (PowerShell) to pin an exact release. The canonical npm command above verifies registry integrity and disables lifecycle scripts; there are no native or runtime dependencies and no daemon.

## Models & pricing

Expand Down Expand Up @@ -98,7 +146,9 @@ Inside the REPL, `/` commands control the whole session — type `/help` to see
aether agent # the main thing — open the REPL and chat
aether agent --local # same REPL on a local Ollama brain (offline)
aether models # list models + orchestrators
aether resume # replay / continue the last session
aether resume # replay the last session in this workspace
aether resume export # write a portable handoff for another machine
aether agent --resume <id|file> # continue it — on any model, with the context
```

Flags you can set when launching the REPL (or pass with an inline task `aether agent "<task>"` for one-shot autonomous mode):
Expand All @@ -108,7 +158,8 @@ Flags you can set when launching the REPL (or pass with an inline task `aether a
| `--local` | Local Ollama brain instead of the hosted API. |
| `--model <id>` | Force a model by key (`--model opus5`, `--model gpt56_terra`, or an Ollama tag with `--local`). |
| `--effort <tier>` | Budget ceiling: `LOW` · `MED` · `MAX` · `ULTRA` · `CODEPRO`. |
| `--test-cmd <cmd>` | Command the verification gate runs (default `pytest -q`). |
| `--test-cmd <cmd>` | Command the verification gate runs. With none, a run ends `unverified` — never `ok`. |
| `--resume <id\|file>` | Continue a prior session, or a handoff file from another machine. |
| `--worktree` | Fresh git worktree on an auto-named branch (isolated). |
| `--repo <owner/name>` | Clone a GitHub repo via your own `gh`/`git` auth, work it in a worktree. |
| `-y`, `--yes` | Auto-confirm prompts (non-interactive). |
Expand Down
35 changes: 35 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,41 @@ history migrates on first read. Full detail in

---

# Aether Agent v0.2.0 — the work outlives the session

**August 19, 2026**

Start a task on one model. Finish it on another, on another machine. Your tests
decide when it's done.

- **Handoffs** — `aether resume export` writes one portable file: the task, the
model that ran it, the verify gate's verdict, how many tests were still
failing, the files that changed, the verification command, and the repository
it belongs to. Copy it anywhere and continue with `aether agent --resume
<file>`, on whatever model you want. Nothing in it is keyed to an absolute
path, so the receiving checkout does not have to live where the work started —
and no file contents, shell commands, or credential-shaped values ride along.
- **`--resume` now reaches the brain** — the prior session is summarized into a
continuation brief the model reads before its own instruction, rather than
being replayed only for the human. With no new task, the run continues the
original one. No re-pasted chat history.
- **`aether agent --local "<task>"` works after a plain npm install** — the
one-shot offline form used to spawn the separately-installed Python brain and
die with `spawn python ENOENT`. It now drives the Ollama brain that ships in
the package. `AETHER_LOCAL_BRAIN=python` opts back in.
- **Session logs stopped redacting your file paths** — the credential filter
matched `pat` inside `path`, so every edited file in every log read
`[REDACTED]`. Real credential keys are still redacted.
- **A run that never reached your tests no longer reports a failing one.**
- **`npm run demo:handoff`** — a five-second deterministic proof of all of it:
two sessions, two models, two checkouts, one verify gate, no account and no
model download. See [`docs/demo/handoff.md`](docs/demo/handoff.md).

Upgrade with `npm i -g aether-agents --ignore-scripts`. No configuration
changes, no migration; 0.1.x session logs are read unchanged.

---

# Aether Agent — the API brain goes bidirectional

**August 12, 2026**
Expand Down
106 changes: 106 additions & 0 deletions docs/demo/handoff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# The handoff demo

> Start a task on one model. Finish it on another, on another machine.
> Your tests decide when it's done.

```bash
npm run demo:handoff
```

This is the reproducible proof behind that sentence, and the script a screen
recording should follow. It runs in about five seconds and needs nothing but a
built checkout — no account, no model download, no network.

## What it does

1. **Machine A.** Builds a throwaway git repo (`slugify`, with an `origin`
remote) containing two genuinely failing tests, and runs the real CLI over it
on model A with `--test-cmd`. The session gets half the job done: lowercasing
and hyphenation land, the whitespace case stays red. The verify gate re-runs
the tests itself and marks the run `incomplete`; the process exits non-zero.
2. **The handoff.** `aether resume export --out handoff.json` distils the
session log into one portable file — the task, the model that ran it, the
verdict, the files that changed, the verification command, and the repository
identity.
3. **Moving machines.** A second checkout is created at a different absolute
path, and machine A's checkout **and its session logs are deleted**. Nothing
the next step does can be quietly reading them, because they no longer exist.
4. **Machine B.** The CLI runs in the second checkout on model B with
`--resume handoff.json` and **no restated task**. The handoff is the only
context it is given. It finishes the job.
5. **Proof.** Three independent checks, all of which must hold:
- the scripted model records session B's first prompt, and it must contain
the continuation brief naming model A and `src/slug.js`;
- `node --test` is run directly by the demo script, outside the agent, and
must be green;
- the CLI's own verify gate must have exited 0.

Any failure prints `FAILED` with the reasons and exits non-zero, so the script
works as a CI gate as well as a demo.

## What is real and what is stubbed

Real: the `aether` CLI, the git repositories, the file edits, the tool
permission gate, the session log, the handoff file, `node --test`, and the
verify gate.

Stubbed by default: **the model, and only the model**. A local HTTP server
speaks Ollama's OpenAI-compatible chat endpoint with scripted tool calls. That
is what makes the run byte-deterministic — a 4B model asked to fix a bug does
something slightly different every time, which is fine for a product and useless
for a gate.

To run the identical script against real models:

```bash
# needs `ollama serve` and both tags pulled
AETHER_DEMO_REAL=1 npm run demo:handoff

AETHER_DEMO_MODEL_A=qwen2.5-coder:7b \
AETHER_DEMO_MODEL_B=qwen3:4b \
AETHER_DEMO_REAL=1 npm run demo:handoff
```

In real mode the models decide what to do, so the transcript varies and the run
can legitimately fail — that is the honest shape of a small local model on a
real task. The verify gate still has the last word either way.

The demo never touches your real configuration: it points `AETHER_CONFIG_DIR`
and `AETHER_LOG_DIR` at a temporary directory, so your token, config, and
session history are untouched, and everything it created is removed on exit.

## Recording it

The sequence below is the 20–45 second version, readable with the sound off.
Nothing here is staged: every frame is the script's own output.

| Beat | Seconds | On screen |
|---|---|---|
| 1. The task | 0–6 | `aether agent --model <A> "make the slugify tests pass"` — the agent reads, edits, runs the tests |
| 2. Not done | 6–12 | the red verdict line: `✗ incomplete · tests failing` |
| 3. The handoff | 12–18 | `aether resume export --out handoff.json` and the `⇄ handoff written` line |
| 4. Moving | 18–24 | `cd` into the second checkout; `rm -rf` the first one |
| 5. Continue | 24–36 | `aether agent --model <B> --resume handoff.json` — no task typed, the agent picks up where A stopped |
| 6. Done | 36–45 | the green verdict line: `✓ ok · tests green` |

Capture:

```bash
# 1. build, so the run is instant on camera
npm ci && npm run build

# 2. set the terminal to 100x30 and record
asciinema rec handoff.cast -c "npm run demo:handoff"

# 3. or, for a GIF
# (agg is asciinema's own renderer: https://github.com/asciinema/agg)
agg --font-size 18 --theme dracula handoff.cast handoff.gif
```

`AETHER_NO_ANIM=1` is set inside the demo for the child processes, so the output
is stable text rather than a repainting status line — which is what you want for
a GIF. For a live-feel recording of the product itself, run the two `aether`
commands by hand instead, with animation on.

Do not re-time or re-cut the verdict lines. The whole point of the last beat is
that a test run, not a model, decided it.
Loading