Skip to content

utensils/aethon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

272 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Aethon — pi with a face

An agent-driven desktop shell where the agent decides what you see.

License: MIT Status: early development Tauri 2 React 19 Rust 1.92 Bun Nix flake Platforms: macOS | Linux

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. Skills 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.


What it can do

Workspace

  • Multi-tab agent sessions — each tab owns its own pi conversation, model, draft, and terminal buffer (⌘T new, ⌘] / ⌘[ next/prev, ⌘W close).
  • Native macOS menu + system tray — built-ins (Quit, Hide, Cut/Copy/Paste, Minimize) for free, plus app-specific items (New Tab, Toggle Terminal, Stop Prompt, Check for Updates) that route through the same dispatcher as the keyboard shortcuts.
  • Live terminal panel (`⌘``) — xterm.js with the WebGL renderer. Streams the agent's bash output per tab.
  • Persistent state — chat history, tabs, and themes survive relaunch under ~/.aethon/. Pi LLM context persists per tab via pi's session manager.

Agent-controlled UI

  • Themes registered live via aethon.registerTheme({ id, vars }) or dropped as ~/.aethon/themes/*.json.
  • Custom A2UI components shipped from extensions — visible alongside the built-ins inside the same renderer.
  • Layout slot contract — alternative layouts host the standard composites by adhering to canonical area names (canvas, composer, sidebar, tabs, terminal, status, header, empty-state) or by declaring a slotMap remap.
  • Four built-in layouts (workstation, editorial, command-deck, live-layout) on the Æther signature palette — swap with /layout <id>. Extensions register additional palettes via aethon.registerTheme.

Extensibility

  • Drop a .ts into ~/.aethon/extensions/ — the bridge hot-reloads. Or npm install --prefix ~/.aethon/skills <pkg> to install an npm-distributed skill (manifest via package.json#aethon).
  • Slash commands, keybindings, menu items, and event interceptors — all registerable from extensions, all reported back in the runtime snapshot so the agent knows what's wired.
  • Generic extension_lifecycle event channel — extensions get visible chat-side feedback when they load / fail / reload, and other layouts can intercept the window event to substitute a toast / sidebar pulse / status pill.

Slash commands/clear, /help, /theme, /model, /reset, /terminal, /skills, /sidebar, /layout. Unknown commands fall through to pi.

See SPEC.md for the full status checklist and CHANGELOG.md for release notes.


Getting started

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 reload

Bring 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.

Nix package

The flake also exposes a distribution package and overlay:

nix build .#aethon
nix run .#aethon

Downstream 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.

Devshell commands

Command What it does
dev Launch the app with hot reload (auto-increments Vite + debug ports if 1420/19433 are busy)
build-app Release bundle (.app / .dmg / .deb / .AppImage)
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 with treefmt

Architecture

┌────────────────────────────────────────────────────────────┐
│                     Aethon (.app / .deb)                    │
│                                                            │
│  ┌────────────────┐    stdio (JSON lines)   ┌────────────┐ │
│  │  Tauri Shell    │◄─────────────────────►│  Pi Agent  │ │
│  │  (Rust)         │                        │  (bun bin) │ │
│  │                 │                        │            │ │
│  │  • windows      │   A2UI components      │  • pi-ai   │ │
│  │  • tray + menu  │◄───────────────────────│  • tools   │ │
│  │  • file watch   │                        │  • skills  │ │
│  │  • spawn agent  │   user / UI events     │  • exts    │ │
│  └────────┬────────┘──────────────────────► └────────────┘ │
│           │ Tauri IPC                                       │
│           ▼                                                 │
│  ┌──────────────────────────────────────────────────────┐  │
│  │             React Frontend (Vite)                    │  │
│  │  ┌─────────────────────┐  ┌──────────────────────┐  │  │
│  │  │  A2UI Renderer       │  │  default-layout     │  │  │
│  │  │  (20 primitives +    │  │  (sidebar, canvas,  │  │  │
│  │  │  scoped templates)   │  │  terminal, ...)     │  │  │
│  │  └─────────────────────┘  └──────────────────────┘  │  │
│  └──────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────┘
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 a skill (src/skills/default-layout/). Replacing it requires no React changes — just register a different layout payload via aethon.setLayout(...).


Project layout

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 + skill packages (reference)
├── flake.nix            # Nix dev environment, package, and overlay
├── package-lock.json    # npm dependency snapshot for reproducible Nix builds
└── package.json         # 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

RELEASING.md walks through generating an updater signing keypair, configuring GitHub Actions secrets, and cutting a release that the in-app updater can consume.


License

MIT © James Brink

Aethon is independent of and not affiliated with Anthropic. Pi is © its respective authors.

About

Pi with a face — agent-driven desktop shell with A2UI

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors