An agent-driven desktop shell where the agent decides what you see.
Early development — not ready for production use. The API and protocol surface are still settling; expect breaking changes between commits.
Aethon embeds the pi coding agent inside a Tauri 2 desktop shell and renders its output as live, interactive UI via the A2UI protocol. The interface is not a fixed IDE layout — it's a canvas the agent populates dynamically. Extensions bring their own components, themes control the look, the agent decides the layout.
The name comes from Greek mythology: Αἴθων, one of the horses that pulled Helios's sun chariot. The blazing one that shapes what you see.
- Multi-tab workspace — top-strip agent tabs (one pi conversation each) plus a bottom-panel terminal with sub-tabs: a read-only "Agent bash" stream and zero-or-more interactive PTY shells (xterm.js + WebGL, full TUI / 256-color / true-color). Focus-aware
⌘T,⌘1–⌘9jump,⌘Wclose,⌘⌥Treopen. - Projects & workspaces — the sidebar nests host → project → workspace. A project contains one or more workspaces: the main checkout plus zero or more git worktrees ("worktree" is now just the underlying git mechanism). New workspaces fork from
origin/mainby default, configurable per project, and GitHub issue "Send to agent" can target a new workspace or the current one — re-linking to an existing session for an already-handed-off issue — using per-repo.aethon/issues.tomlhandoff templates plus branch names inferred from the issue title/labels. - Native shell integration — system tray + macOS menu, auto-updater (
tauri-plugin-updateragainst GitHub Releases), persistent chat history / tabs / themes / projects /~/.aethon/config.toml, per-tab pi session continuity. - Agent-controlled UI — themes (
aethon.registerThemeor~/.aethon/themes/*.json) drive the whole palette including terminal ANSI; any A2UI built-in (composites or app-root overlays likecommand-palette,notification-stack,settings-panel,search-panel) is overridable viaaethon.registerComponent. One built-in layout (workstation); extensions register more viaaethon.registerLayout. - Native A2UI canvas windows — agents and extensions can open separate native OS windows that render bare A2UI canvas content, with window-local state, extension templates/React components, themes, event handlers, and restore-on-launch persistence. Exploratory dashboards can live there without replacing the main workspace chrome.
- Agent ↔ shell sharing — four-value
shareMode(private/read/read-write/read-write-trusted) per shell, clickable badge to cycle. Bridge surfaceaethon.shells.{list, read, write}exposes scrollback (forward-only, privacy floor enforced Rust-side) and keystroke injection (Allow/Deny prompt per write unless trusted). - First-class Nix devshell support — projects with
flake.nix,.envrc(use_flake+direnv), orshell.nixget their devshell env auto-applied to every PTY shell tab AND the agent's pibashtool, no manualnix developwrap needed. One in-memory + on-disk cache keyed onflake.lockhash feeds both spawn paths; status-bar⬡ direnv/⬡ flakebadge shows current state. Configurable via[devshell]inconfig.tomland per-project.aethon/devshell.toml. - Voice input — push-to-talk dictation straight into the composer (
Cmd+Shift+M, plus an optional hold-to-record key). Transcription provider is selectable per host: a bundled local Whisper model (downloaded on demand), the native OS recognizer (macOS Speech, Windows SAPI 5.4), or LFM2-Audio — an end-to-end ASR+TTS mode for hands-free conversation with speak-aloud replies. Hotkeys configurable via[voice]inconfig.toml. - Multiple provider accounts — sign in to more than one account per provider and switch which one a tab uses with
/login [list | use <account> | default <account>]. Each profile keeps its own credentials and model registry; the active profile is per-tab with a per-provider default. - MCP servers — connect Model Context Protocol servers via guided
/mcpsetup, with per-project config (.aethon/mcp.toml,.mcp.jsonimport) gated by a host approval policy. - Subagents & tasks — delegate to multi-model subagents that run in parallel in the background, then fold their results back into the conversation.
- Scheduled tasks & loops — a native scheduler for recurring work, driven by
/tasks(list/run/pause/resume/cancel) and/loop(fixed-interval or self-paced loops bound to a session). - Memory — per-user and per-project memory the agent can read and write, surfaced with
/memory. - Extensibility — drop a
.tsinto~/.aethon/extensions/for hot-reload, ornpm install --prefix ~/.aethon/extensions <pkg>for npm-distributed extensions (manifest viapackage.json#aethon); project-local extensions discovered from cwd up to its git root. Extensions register slash commands, keybindings, menu items, event routes, layouts, A2UI components, and themes — all reported back in the runtime snapshot. - Built-in slash commands —
/clear,/help,/theme,/model,/plan,/init,/config,/mcp,/mcp-auth,/login,/reset,/reload,/rename,/memory,/context,/session,/compact,/name,/export,/loop,/tasks,/terminal,/extensions,/sidebar,/files,/layout,/project. Unknown commands fall through to pi.
See SPEC.md for the full status checklist, docs/project-config.md for project-local .aethon config, and CHANGELOG.md for release notes.
Requires Nix with flakes enabled. With direnv, the dev shell activates automatically when you cd into the directory.
nix develop # enter the dev shell (rust toolchain + bun + tauri CLI)
bun install # install JS deps
dev # launch the app with hot reloadBring your own LLM key — pi reads ANTHROPIC_API_KEY / OPENAI_API_KEY / equivalents from the environment. See pi's docs for the full multi-provider setup.
The flake also exposes a distribution package and overlay:
nix build .#aethon
nix run .#aethonDownstream flakes can consume overlays.default, which provides pkgs.aethon.
The package follows nixpkgs' Tauri pattern (cargo-tauri.hook +
fetchNpmDeps) and uses package-lock.json as the reproducible npm dependency
input for Nix builds.
| Command | What it does |
|---|---|
dev |
Launch the app with hot reload (auto-increments Vite + debug ports if 1420/19433 are busy) |
docs |
Run the VitePress docs site on 0.0.0.0:5173 with hot reload |
understand-dashboard |
Vite dashboard for the understand-anything knowledge graph (.understand-anything/knowledge-graph.json); open the printed ?token= URL |
build-app |
Release bundle (.app / .dmg on macOS, .deb / .rpm on Linux, NSIS .exe on Windows) |
check |
Full CI gate: clippy + tsc + ESLint + cargo test + vitest |
lint |
ESLint frontend + agent (no auto-fix) |
test |
Run Rust + TS tests (cargo test --lib + vitest run) |
coverage |
TS coverage report under coverage/ (vitest v8) |
fmt |
Format Rust + Nix + JSON/MD/YAML/CSS + TOML with treefmt |
clean |
Remove Rust build artifacts under src-tauri/target/ |
package.json is the app-version source of truth. The sidebar version
chip imports it directly, while scripts/sync-version.mjs mirrors it into
Tauri and Cargo metadata.
bun run version:sync # update package-lock, tauri.conf, Cargo.toml, Cargo.lock
bun run version:check # fail if any copy drifted from package.jsongraph TD
subgraph aethon["Aethon"]
TS["Tauri Shell (Rust)\nwindows · tray + menu · file watch · spawn agent"]
PA["Pi Agent (bun bin)\npi-ai · tools · skills · exts"]
subgraph react["React Frontend (Vite)"]
R["A2UI Renderer\n19 primitives + scoped templates"]
L["default-layout\nsidebar · canvas · terminal · …"]
end
TS -- "stdin JSON lines\nuser / UI events" --> PA
PA -- "stdout JSON lines\nA2UI components + responses" --> TS
TS <-- "Tauri IPC" --> react
end
| Layer | Owns | Doesn't own |
|---|---|---|
| Tauri shell (Rust) | OS surface — windows, tray, native menus, file watcher, spawning the agent subprocess | Any business logic, agent awareness, A2UI knowledge |
| Pi agent (Bun) | LLM interaction, tool execution, session management, extension loading, A2UI emission | OS resources |
| React frontend | Rendering A2UI payloads, dispatching events, persisting local state, hosting the chrome | The chrome is data — default-layout is itself an A2UI payload |
The default layout is an extension (src/extensions/default-layout/). Replacing it requires no React changes — just register a different layout payload via aethon.setLayout(...).
aethon/
├── src/ # React frontend (entry: src/main.tsx)
├── src-tauri/ # Rust Tauri shell (lib + helpers + watcher)
├── agent/ # Pi agent bridge (run as a bun subprocess)
├── docs/aethon-agent/ # Bundled reference docs the agent reads
├── examples/ # Pi extensions + extension packages (reference)
├── flake.nix # Nix dev environment, package, and overlay
├── bun.lock # Bun lockfile (used by `bun install` in the devshell)
├── package-lock.json # npm dependency snapshot for reproducible Nix builds
└── package.json # App version source + frontend deps + tauri CLI
For agent-side authoring docs (the API surface, A2UI components, extension recipes), see docs/aethon-agent/. The same files ship inside the binary as bundled resources so the agent can read them at runtime.
For repository conventions and architecture deep-dives, see CLAUDE.md.
RELEASING.md walks through generating an updater signing keypair, configuring GitHub Actions secrets, and cutting a release that the in-app updater can consume.
MIT © James Brink
Aethon is independent of and not affiliated with Anthropic. Pi is © its respective authors.
