uam is a terminal dashboard for managing multiple coding-agent CLIs from one place.
It gives you a single TUI for launching, peeking, replying to, attaching to, and
stopping long-running agent sessions — no tmux (or any other multiplexer)
required.
Supported providers:
- Claude Code
- OpenAI Codex
- GitHub Copilot CLI
- Hermes Agent
- Oh My Pi
- OpenCode
- Runs each managed session under its own lightweight, detached host process (a PTY + terminal emulator + Unix socket) — sessions keep running when the TUI exits, exactly like a tmux server, with no external dependency
- Shows active and closed sessions in one dashboard
- Lets you peek at recent output without attaching (4000 lines of scrollback)
- Sends replies back into running agent sessions
- Persists session metadata across restarts, including each agent's exit code
- Supports pinning, renaming, manual reorder, and group-by-directory
- Detects GitHub PR URLs from agent output and can refresh PR state when
ghis available - Supports per-session command aliases such as a custom Copilot launcher
- Go 1.25+ to build from source (the pinned toolchain downloads automatically)
- Any provider CLI you want to manage already installed and authenticated
That's it — agents are spawned directly under uam's own session hosts, so there is nothing else to install.
Providers are capability-probed at runtime. If a CLI is missing, uam hides it
from the dispatch UI instead of failing the whole app.
Install the uam binary directly:
go install github.com/RandomCodeSpace/unified-agent-manager/cmd/uam@latestBuild locally:
make buildOpen the dashboard:
uamGuided dispatch flow:
uam newHeadless dispatch examples:
uam dispatch claude "fix flaky tests"
uam dispatch --cwd /path/to/repo codex "review this package"
uam dispatch --alias ghcp copilot "review this branch"uam # open the TUI
uam new # guided dispatch wizard
uam dispatch [--safe] [--alias <name>] <agent> [#session-name] [prompt]
uam ls [--json]
uam peek <id>
uam attach <name-or-id>
uam last
uam stop <id> # kill the session, keep record
uam rm <id> # kill the session and remove record
uam kill-all # stop every managed session
uam version| Key | Action |
|---|---|
↑ / ↓ |
Move selection |
Enter / → |
Attach selected session |
Type prompt + Enter |
Dispatch to the default agent |
@agent prompt |
Dispatch to a specific agent |
@agent:alias prompt |
Dispatch with a command alias |
Tab |
Cycle default agent |
Space |
Toggle peek panel |
Ctrl+T |
Pin selected session |
Ctrl+R |
Rename selected session |
Ctrl+X |
Stop or remove the selected session with confirmation |
Ctrl+S |
Toggle group-by-directory |
Shift+↑/↓ |
Reorder rows |
e |
Open the guided dispatch wizard |
? |
Open help |
Esc |
Close overlays, clear input, or quit |
uam attach (or Enter in the TUI) bridges your terminal straight to the
agent's PTY:
Ctrl+B ddetaches and returns to the dashboard (Ctrl+B Ctrl+Bsends a literalCtrl+Bto the agent)←(left arrow) also detaches when you haven't typed anything since the last submit/clear — tap it to hop back to the dashboard. Inside a draft it moves the cursor as usual, and after history/menu navigation it stays passthrough until the nextEnter/Esc. SetUAM_ATTACH_BACK_DETACH=0to disable.- The session keeps running after you detach or close the terminal
Ctrl+Zis swallowed while attached — suspending an agent inside a detached session would leave it impossible to foreground- Several terminals can attach to the same session at once
Detach/reattach never restarts anything — the agent keeps running under its
host and attach is a plain reconnect (this is the tmux property, kept).
Resume only applies to sessions whose process is gone (reboot, uam stop):
- Claude Code: uam seeds claude's session id with the uam id at dispatch
(
--session-id, when the installed claude supports it) and resumes that exact conversation with--resume <id>— several sessions in the same directory each resume their own conversation. Sessions dispatched before this feature (or with an older claude) fall back to--continue. - Copilot: exact resume — the session is named with the uam id at
dispatch (
--name) and resumed by that exact name (--resume=<id>). - Codex / OpenCode: these CLIs cannot preset session ids yet, so resume
uses their "most recent" mode (
codex resume --last,opencode -c). When an opencode record carries aprovider_session_id(ses_...), uam resumes that exact session via--session. omp:-c. - After a reboot, records survive in the store and resume on attach — a scenario where a tmux session would simply be gone.
uam stores session metadata at:
${XDG_CONFIG_HOME:-~/.config}/uam/sessions.json
Writes are atomic and lock-protected. If the file needs migration or recovery,
uam creates backup files next to it.
Per-session runtime state (control sockets and state files) lives in a
per-user directory under the system temp dir — /tmp/uam-<uid> on most
systems (override with UAM_SESSION_DIR) — created owner-only and verified
to be owned by you. The temp dir is used instead of $XDG_RUNTIME_DIR
deliberately: logind wipes the runtime dir when your last login session ends,
which would strand detached sessions that survive logout (the same reason
tmux lives in /tmp/tmux-<uid>). Hosts periodically refresh their files'
timestamps so age-based /tmp cleanup never collects a long-idle session.
Note for distros with KillUserProcesses=yes in logind.conf: any detached
process — uam session hosts and tmux alike — is killed at logout unless you
run loginctl enable-linger.
Upgrading from a tmux-backed release: sessions still running inside the old
tmux -L uamserver are not visible to the native backend. Finish or stop them first (tmux -L uam kill-server); stored session records carry over unchanged and remain resumable.
uam can launch providers in their full-access or auto-approve mode when the
provider supports it. Use uam dispatch --safe ... when you want the provider's
default approval behavior instead.
uam does not make git checkpoints, stash changes, or modify your repository on
its own. It starts and manages agent sessions; the provider remains responsible
for its own execution model.
make test
make build
make lintPrebuilt binaries are published on the GitHub Releases page.