Skip to content

Latest commit

 

History

History
307 lines (242 loc) · 13.4 KB

File metadata and controls

307 lines (242 loc) · 13.4 KB

unified-agent-manager (uam)

Security SonarCloud Quality Gate Release Go

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

What it does

  • 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 Running and Stopped sessions in one dashboard, with grounded exit detail
  • 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 gh is available
  • Supports per-session command aliases such as a custom Copilot launcher

Requirements

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

Supported platforms

  • Linux (Ubuntu), on amd64 and arm64
  • macOS, on Intel and Apple silicon
  • Native Windows is not supported. Windows Terminal and PowerShell can be used only as SSH clients connecting to a Linux or macOS host running uam.

Install

Install the uam binary directly:

go install github.com/RandomCodeSpace/unified-agent-manager/cmd/uam@latest

Build locally:

make build

Quick start

Open the dashboard:

uam

Guided dispatch flow, using OpenCode by default when it is available, then opening the created session immediately:

uam new

Headless 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"

CLI

uam                              # open the TUI
uam new                          # guided dispatch wizard, then attach
uam dispatch [--safe] [--alias <name>] <agent> [#session-name] [prompt]
uam ls [--json]
uam peek <id>
uam attach [--allow-latest] <name-or-id>
uam last
uam stop <id>                    # kill the session, keep record
uam restart [--allow-latest] <id>  # stop the agent and resume it in place
uam rm <id>                      # kill the session and remove record
uam kill-all                     # stop every managed session
uam version

TUI keys

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 for Running; resume Stopped in the background
Ctrl+T Pin selected session
Ctrl+R Rename selected session
Ctrl+X Stop and remove the selected record, or restart it, with confirmation
Ctrl+S Toggle group-by-directory
Shift+↑/↓ Reorder rows
/ with an empty command Filter by name, provider, task, workspace, ID, or lifecycle
e Open the guided dispatch wizard
? Open help
Esc Close overlays, clear input, or quit

The dashboard responds to every terminal resize. Operations always use a full-width, bordered session list; the selected row expands in place with its task, Workspace, identity, and pull request. Wide terminals split only when Peek is open. Compact or keyboard-constrained mobile terminals keep ordinary rows to one line and expand the selected row to two. See Responsive TUI design and operations for layout thresholds, filtering, mobile guidance, lifecycle labels, and accessibility.

Attached sessions

uam attach (or Enter in the TUI) bridges your terminal straight to the agent's PTY:

  • Ctrl+B d detaches and returns to the dashboard (Ctrl+B Ctrl+B sends a literal Ctrl+B to the agent; Ctrl+B c sends a literal Ctrl+C)
  • Plain Ctrl+C is swallowed while attached so terminal copy shortcuts do not cancel 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 next Enter/Esc. Set UAM_ATTACH_BACK_DETACH=0 to disable.
  • The session keeps running after you detach or close the terminal
  • Ctrl+Z is 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

UAM_ATTACH_MOUSE controls whether provider mouse reporting is preserved:

  • auto (the default) enables it locally and disables it when SSH_CONNECTION or SSH_TTY indicates an SSH session
  • on preserves provider mouse reporting everywhere
  • off suppresses provider mouse modes so the terminal keeps selection and paste gestures

Bracketed-paste payload is forwarded byte-for-byte. Control bytes inside a paste do not trigger UAM's attach shortcuts. UAM cannot access the client clipboard or turn an unsent mouse gesture into remote input.

For PowerShell SSH, use Windows Terminal and configure a Windows Terminal paste binding such as right-click, Ctrl+Shift+V, or Shift+Insert. Keep UAM_ATTACH_MOUSE=auto (or set it to off) on the remote host if provider mouse tracking captures selection or right-click. Native Windows remains unsupported; Windows is the SSH client in this setup.

In the TUI, Ctrl+X followed by y stops the process and removes its stored record. Use uam stop <id> when you want to stop the process but retain a Stopped row for later resume. For paste diagnosis, follow the SSH troubleshooting steps.

Resuming sessions

Detach/reattach never restarts anything — the provider keeps running under its host and attach is a plain reconnect. Resume applies only when the provider process is Stopped, such as after a reboot, clean exit, or uam stop.

UAM distinguishes an exact resume, which targets known provider state, from a heuristic resume, which asks the provider to continue its latest conversation. If a heuristic provider has multiple retained sessions in the same workspace, UAM fails closed before launching it. The TUI asks for explicit confirmation; CLI users may retry only when latest-conversation behavior is acceptable:

uam attach --allow-latest <name-or-id>
uam restart --allow-latest <id>

Provider behavior:

  • 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 Code) use the guarded --continue heuristic.
  • Copilot: exact resume — the session is named with the uam id at dispatch (--name) and resumed by that exact name (--resume=<id>).
  • OpenCode: UAM learns the current root conversation ID and resumes it exactly with --session. Older records without an identity use guarded -c latest-conversation behavior.
  • Oh My Pi: new sessions receive a UAM-ID-specific provider state directory, making -c exact. Legacy records without that directory retain guarded latest-conversation behavior.
  • Codex: codex resume --last is heuristic because Codex cannot currently be given the UAM ID when the conversation is created.
  • Hermes: no provider resume command is configured. A stopped Hermes record cannot be resumed; dispatch a new Managed Session instead.
  • After a reboot, records survive in the store and resume on attach — a scenario where a tmux session would simply be gone.

Multiple sessions in one workspace

UAM can run several Managed Sessions in one project directory. They have independent UAM IDs, terminal hosts, attach points, and provider conversations, but they share the same files. The grouped TUI warns when more than one Running session shares a Workspace. Use separate Git worktrees or checkouts when agents must not edit the same tree; UAM does not create them automatically.

OpenCode's /new creates a new provider conversation inside the current Managed Session. It intentionally does not create another UAM row or host. UAM tracks the newly selected root conversation for later exact resume. To get two independently attachable sessions, use uam new or uam dispatch again.

The terminology and compatibility decision are documented in Managed Session vs. Provider Conversation.

Session storage

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 uam server 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.

Safety model

uam launches providers in their full-access or auto-approve ("yolo") mode by default when the provider supports it. In that mode, treat the repository, prompt, provider configuration, and any instructions the agent reads as trusted: the provider may execute commands and change files without pausing for approval. Use uam dispatch --safe ... when you want the provider's default approval behavior instead. Safe mode changes provider arguments; it is not an operating- system sandbox and does not reduce the permissions of the uam process itself.

OpenCode is capability-probed before launch. In default yolo mode, UAM adds --auto only when the installed OpenCode advertises that flag; older versions continue without an unsupported argument. This preserves compatibility but does not turn OpenCode or UAM into a sandbox.

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.

Design and operations

Session storage remains schema version 3. Updates do not require a data migration, and unknown JSON fields are preserved when existing records are rewritten.

Development

make test
make build
make lint

Releases

Prebuilt binaries are published on the GitHub Releases page.