An agent-first IDE built entirely in the terminal.
"It never gets old that your operating system is this malleable." — DHH
tmux is the window manager. Neovim is the editor. AI agents are first-class panes — not plugins bolted on, but peers sitting next to your code with their own space to think. You compose layouts that give you and your agents exactly the arrangement you need, then tear them down and reshape them when the work changes.
This is a research environment. The kind of setup where you spawn four Claude instances across four git worktrees and let them all run in parallel. Where you open a swarm of agents tiled across your screen and watch them collaborate. Where your dev layout is nvim on the left, an AI agent on the right, and a terminal at the bottom — and that's just the default.
Everything is a shell function. Everything is composable. Everything is yours to change.
brew install aadarwal/tap/anu
anu initgit clone https://github.com/aadarwal/anu.git ~/anu
~/anu/bin/anu initanu init installs dependencies, then walks you through each config file — merge with your existing setup, replace (with backup), or skip. For a fresh machine, use anu init --replace-all.
Open a new Ghostty window, then:
t # start tmux
tdl cx # dev layout: nvim + claude + terminal| Layer | Tool |
|---|---|
| Terminal | Ghostty |
| Multiplexer | tmux |
| Editor | Neovim + LazyVim |
| Prompt | Starship |
| Shell | Bash 5 + eza + fzf + zoxide + bat + mise |
| AI | Claude Code, opencode, Codex, or anything that runs in a terminal |
All layout commands run inside tmux. This is the core of anu — arranging agents and editors in space.
The daily driver. Editor left, agent right, terminal bottom.
┌──────────────────────┬─────────────┐
│ │ AI (30%) │
│ nvim (70%) │ e.g. cx │
│ │ │
├──────────────────────┴─────────────┤
│ terminal (15%) │
└────────────────────────────────────┘
tdl cx # nvim + claude + terminal
tdl cx c # nvim + claude + opencode (stacked)N tiled panes all running the same command. Parallel AI at scale.
tsl 4 cx # 4 claude instances, tiled
tsl 4 cxx # same, full permissions skipOne agent per git worktree, stacked on the right. Editor on the left browses all of them.
┌──────────────────────┬─────────────────────┐
│ │ cx @ master │
│ nvim (70%) ├─────────────────────┤
│ (browses all wts) │ cx @ feat/auth │
├──────────────────────┴─────────────────────┤
│ terminal (15%) │
└────────────────────────────────────────────┘
twdl cx # auto-detect all worktrees
twdl cx master feat # specific branches onlyFull-width vertical stack, one AI per worktree.
twsl cxx # full-width swarm across all worktrees| Command | What it does |
|---|---|
tdlm <ai> |
One tdl per subdirectory — built for monorepos |
tpl |
Two editors side by side + terminal |
tml <cmds...> |
Main pane left, stacked command panes right |
twl <branch> <ai> |
New tab with tdl in a specific worktree |
twlm <ai> |
One tab per worktree, each with full tdl |
Add or remove agents mid-session without destroying your layout.
| Command | Description |
|---|---|
taa [cmd] |
Add an agent pane (default: claude). Re-tiles layout. |
tra [pane] |
Remove an agent pane (fzf picker if no arg) |
tscale <n> [cmd] |
Scale to exactly N agent panes |
tap |
List tracked agent panes with status |
# Start with 2 agents, scale up when you need more
tdl cx
taa cx # add another claude
taa cdx # add a codex
tscale 6 cx # scale to 6 agentsThe swarm system lets you orchestrate multiple AI agents across different topologies. Each topology defines how agents communicate.
| Command | Topology | Description |
|---|---|---|
swarm start <n> <cmd> |
Flat | N equal workers, you orchestrate |
swarm star <n> <cmd> |
Star | 1 conductor + N-1 workers. Conductor delegates. |
swarm pipe <n> <cmd> |
Pipeline | Sequential stages. Each reads predecessor output. |
swarm pair <cmd> |
Pair | Coder + reviewer feedback loop |
swarm wt <n> <cmd> |
Worktree | One agent per auto-created git worktree |
swarm mesh <n> <cmd> |
Distributed | Across Tailscale devices |
| Command | Description |
|---|---|
swarm send <agent> "<msg>" |
Message a specific agent |
swarm broadcast "<msg>" |
Message all agents |
swarm capture <agent> |
Capture agent's pane output |
swarm collect |
Aggregate all agent outputs |
| Command | Description |
|---|---|
swarm status |
Agent status table |
swarm dashboard |
Live-refreshing popup (5s refresh) |
swarm ls |
List all active swarms |
swarm kill |
Tear down current swarm |
swarm merge [--all] |
Merge worktree agent branches back |
| Command | Description |
|---|---|
swarmx plan <topo> <n> <cmd> |
Dry-run: preview what a swarm would create |
swarmx status |
Enhanced status with git diff stats per agent |
swarmx merge |
Interactive fzf merge with conflict detection |
| Command | Description |
|---|---|
al [cmd] |
Launch agent in a new split pane (fzf picker) |
alw [cmd] |
Launch agent in a new window |
Available agent aliases: cx (Claude), cxx (Claude full-auto), c (OpenCode), cdx (Codex), cdxx (Codex full-auto), pi (Pi minimal harness — no permission popups by design).
When a swarm finishes, you don't want to read 200 raw diffs. The review system sends diffs to a model and shows you AI-comprehended summaries — cached per commit SHA so it's instant on re-review.
| Command | Description |
|---|---|
review |
Overview of all divergent branches with AI summaries |
review <swarm_id> |
Scope review to a specific swarm |
review <agent> |
Deep dive: one agent's work with per-file annotations |
review <agent> <file> |
AI-explained diff for a single file |
review conflicts |
Cross-agent conflict analysis |
reviewd |
Dashboard mode: persistent pane, auto-refreshing |
See your entire project state at a glance.
| Command | Description |
|---|---|
pd |
Full-screen fzf popup: branches, worktrees, active swarms |
pds |
Persistent sidebar (toggle on/off) |
Actions inside pd: checkout branch (enter), create worktree (ctrl-w), spawn agent (ctrl-a).
| Command | Description |
|---|---|
t |
Attach last session / create "Work", or fzf picker inside tmux |
t <name> |
Attach or create named session |
t <name> <dir> |
Named session rooted at directory |
t . |
Session named after current git repo |
tj [query] |
Jump to project dir (zoxide + fzf), create/attach session |
tp |
fzf session picker with preview and inline kill (ctrl-x) |
tk [name] |
Kill session |
tl |
List sessions |
Drop a .tmux-workspace file in any project directory. When t creates a session there, it sources the file automatically.
# .tmux-workspace
tdl cx
tw server "rails server"
tw logs "tail -f log/development.log"
tmux select-window -t :1tss # save tmux state
tsr # restore it| Command | Description |
|---|---|
tw <name> [cmd] |
Create named window, optionally run a command |
twp |
fzf window picker |
to [cmd] |
Popup overlay / scratchpad |
tws |
Stash current window |
twg |
Grab window back from stash |
| Command | Description |
|---|---|
gwa <branch> [base] |
Create worktree as sibling directory |
gwr [branch] |
Remove worktree (fzf picker if no arg) |
gwl |
List worktrees |
gws [branch] |
cd into worktree (fzf picker if no arg) |
twf [path] |
Refocus all AI panes to a specific worktree |
In nvim, <leader>gw opens a telescope worktree picker that switches cwd and auto-focuses the corresponding agent pane.
| Alias | Description |
|---|---|
g |
git |
gcm <msg> |
Commit with message |
gcam <msg> |
Stage all + commit |
gwip |
Quick WIP commit (stage all) |
gunwip |
Undo last WIP commit |
gp |
Push + print PR URL |
gpf |
Force push with lease |
gsync |
Fetch + rebase on default branch |
gpr [-d] |
Push + create PR (add -d for draft) |
gclean |
Delete merged branches (fzf multi-select) |
| Command | Description |
|---|---|
gb [filter] |
Branch checkout with preview, delete (ctrl-d) |
gl |
Git log browser, copy SHA (enter), show diff (ctrl-d) |
ga |
Interactive staging: multi-select, stage/unstage |
gd [ref] |
Diff viewer, open in editor |
gst |
Stash manager: apply, drop, pop |
| Command | Description |
|---|---|
cfgmap |
fzf browser of all editable configs (categorized by level) |
cfgedit <name> |
Quick-edit config by short name |
cfgedit tmux # opens tmux.conf
cfgedit aliases # opens aliases file
cfgedit ghostty # opens terminal config| Command | Description |
|---|---|
rgi [query] |
Interactive ripgrep — search, preview, open match in editor |
fdi [query] |
Interactive fd — find files, open in editor |
fp |
Process picker: SIGTERM (enter), SIGKILL (ctrl-k) |
fenv |
Environment variable browser |
mkd <name> |
mkdir + cd |
json [file] [query] |
Pretty-print JSON or run jq query |
serve [port] |
Quick HTTP server (Python) |
extract <file> |
Universal archive extraction |
Connect to remote devices for distributed agent swarms.
| Command | Description |
|---|---|
mesh |
fzf device picker (online + SSH-capable) |
mesh ssh |
Filter for SSH-capable devices |
mesh all |
Show all devices |
| Key | Action |
|---|---|
Ctrl+Option+Arrows |
Navigate panes |
Ctrl+Option+Shift+Arrows |
Resize panes |
Option+1-9 |
Switch to window |
Option+Left/Right |
Prev/next window |
Option+Up/Down |
Prev/next session |
F12 |
Toggle nested tmux pass-through |
| Key | Action |
|---|---|
h / v |
Split below / right |
x |
Kill pane |
c / k / r |
New / kill / rename window |
C / K / R |
New / kill / rename session |
q |
Reload config |
s / w / j |
Session / window / project picker (fzf) |
` |
Scratchpad popup |
a |
AI popup (claude) |
A |
Agent launcher (fzf picker) |
+ / - |
Add / remove agent pane |
f |
Review popup |
d |
Project dashboard popup |
g / G / b |
Git log / worktree / branch picker |
m |
Mesh (Tailscale) popup |
S |
Swarm hub popup |
U |
Grab window from stash |
| Alias | What it runs |
|---|---|
cx |
Claude Code (permissions skip) |
cxx |
Claude Code (full permissions skip) |
c |
OpenCode |
cdx |
Codex |
cdxx |
Codex (full auto) |
pi |
Pi coding harness (minimal, no permission popups) |
n |
Neovim |
g |
git |
d |
docker |
r |
rails |
ls |
eza with icons |
lt |
eza tree view |
ff |
fzf with bat preview |
eff |
fzf + open in editor |
cd |
zoxide (smart directory jumping) |
| Command | Description |
|---|---|
anu init |
Interactive setup — deps, config linking, git identity |
anu init --replace-all |
Non-interactive: replace all configs (fresh machine) |
anu init --merge-all |
Non-interactive: merge shell files, replace the rest |
anu init --skip-existing |
Non-interactive: skip any existing config file |
anu unlink |
Remove all anu configs, restore backups |
anu status |
Show current state of all config links |
anu upgrade |
Pull latest + sync deps + update links |
anu doctor |
Check installation health |
When anu init finds an existing config file, it offers three strategies:
- Merge (shell files like
~/.bashrc): appends asource anuline to your existing file. Your config stays intact. - Replace: backs up your file (e.g.,
~/.bashrc.anu-bak.20260408_143022), then symlinks ours.anu unlinkrestores the backup. - Skip: leaves the file untouched.
./install.sh, ./upgrade.sh, and ./uninstall.sh still work — they delegate to anu init/upgrade/unlink.
Tools (via Homebrew): tmux, bash 5, neovim, starship, eza, fzf, zoxide, bat, ripgrep, fd, mise, gh, jq, tree
Font (install separately): brew install --cask font-jetbrains-mono-nerd-font
All config files are linked from the repo to their standard locations (~/.config/tmux/, ~/.config/nvim/, ~/.config/ghostty/, ~/.bashrc, etc.). Run anu status to see the full list and current state.
anu exposes the repo at ~/.local/share/anu/ and stores runtime feature state under that path:
| Directory | Contents |
|---|---|
swarms/ |
Swarm metadata, agent state, mailboxes |
reviews/ |
Cached AI summaries per commit SHA |
mesh/ |
Tailscale device cache, host definitions |
The installer link manifest lives separately at ~/.local/state/anu/manifest so anu unlink can restore configs without writing installer bookkeeping into the repo.
- Bash 5+ required for
tsl. The installer offers to set Homebrew bash as default. - macOS only — uses Ghostty,
pbcopy(clipboard), andosascript(notifications). - Mission Control —
Ctrl+Option+Shift+Arrowsmay conflict. Disable in System Settings > Keyboard > Keyboard Shortcuts > Mission Control. - First nvim launch auto-installs 46 plugins via lazy.nvim (~30-60s).
The DHH quote is from his work on omakub / omarchy, which inspired the original direction. anu has since diverged into something different — an agent-first research environment rather than a general-purpose dev setup.