Every agent at a glance.
Argus is a terminal-native orchestrator for LLM coding agents. Run a swarm of Claude Code and Codex sessions side by side, each in its own git worktree, all under a single keyboard-driven UI — and reach the same swarm from your phone, from another agent, or from your own notes.
Coding agents are cheap to start and expensive to babysit. Five claude tabs become five forgotten branches. A codex you fire off at lunch is a black box until you cmd-tab back. Argus replaces that pile of terminals with a persistent orchestrator that knows what every agent is doing, where its worktree lives, when it goes idle, and who needs your attention next.
- One keystroke spins up an isolated worktree, a fresh branch, and a fresh agent, all wired into a live dashboard.
- A persistent daemon keeps PTYs alive across TUI restarts and laptop reboots. Your sessions outlive your terminal.
- An idle detector quietly promotes any agent waiting for input to "in review" — so a glance at the list tells you who needs you.
- A built-in HTTP API + PWA mirrors every keystroke from your phone, so the dashboard travels with you.
- A built-in MCP server lets agents talk to Argus directly — search your notes, spawn other agents, or hand off work between models.
Argus ships a real, installable Progressive Web App. Tap Add to Home Screen in Safari and you have a phone-shaped operations console for your agents — running locally on your machine, reachable over your Tailscale mesh, never exposed to the public internet.
- Real terminals in the browser — xterm.js fed by an SSE byte stream, with PTY auto-resize on rotation. Not a polling log viewer.
- A native compose bar that catches everything iOS sends — dictation, third-party keyboards, Wispr Flow — and forwards it cleanly into the agent's stdin. Slash-key autocomplete pulls from your
~/.claude/skills/, per-project skills, and installed plugins. - A virtual key bar with the keys iOS won't give you: Esc, Tab, Shift+Tab (cycle Claude Code modes), arrows. Tap them between dictations without losing the soft keyboard.
- Web Push notifications when an agent goes idle. Throttled, VAPID-signed, per-device subscriptions, no third-party push services.
- Share-sheet target — Argus shows up natively in the Android share sheet. iOS gets a one-paste Shortcut that does the same. Either way, sharing a URL or a chunk of text into Argus lands you on the New Task tab with the prompt pre-filled.
- GitHub-style stacked diff view — every changed file in the worktree as a collapsible panel, expand-all, wrap toggle, optimistic for thumbs.
- Per-device API tokens — your iPhone, your iPad, and your laptop each get their own labeled token. Revoke any of them from the dashboard. Master token mints; SHA-256 hashes are all that's stored.
- Offline-aware — when the daemon is unreachable (laptop closed, Tailscale off) the PWA flips to a branded offline screen and reconnects automatically.
- Pure-local — runs on
localhostand your Tailscale IP only, never0.0.0.0. Hotel/cafe LANs cannot reach the API even with the token.
Argus exposes itself as a Model Context Protocol server, so any agent can drive Argus the same way you do.
- Spawn other agents. An orchestrator agent can call
task_createto fan work out across worktrees, then watch progress withtask_listandtask_get. - Hand off cleanly. When a session is done, the agent calls
task_complete(status flip) ortask_archive(out of sight) using its ownpwdto identify itself — no IDs to track. - Schedule itself.
schedule_createaccepts cron,@every 30m, or a one-shotrun_once_attimestamp. An agent can plant a tomorrow-morning follow-up before signing off. - Stage clipboard text with
argus_clipboard_set— solves the iOS Safari rule thatclipboard.writeTextrequires a synchronous user gesture. The agent stages, you tap Copy (PWA) or hitctrl+y(TUI). One tap, no escape-character mangling. - Rename, fork, stop, resume — every TUI verb has an MCP equivalent.
The same MCP server is auto-injected into every worktree Argus creates, so newly-spawned agents inherit the toolset without any per-project config.
Argus indexes your Obsidian vault as a SQLite FTS5 store and serves it over MCP. Every agent it spawns sees your notes — your design docs, your meeting captures, your durable preferences — as a first-class lookup, not a copy-paste afterthought.
kb_search— ranked full-text search across the entire vault, with snippets.kb_read— full markdown by vault-relative path. Wiki-link friendly.kb_list— directory listing with prefix filtering for path-aware browsing.kb_ingest— agents write their own learnings back. Your KB grows from sessions instead of decaying between them.- Live re-indexing — files dropped into the vault are searchable in seconds.
- Schema-aware — YAML frontmatter (title + tags) drives retrieval and clustering.
Pair this with the MCP task tools and an agent can read a meeting note, decide what to build, spawn its own worker tasks, and archive itself when done — all in a single conversation.
- Multi-backend — Claude Code, Codex, or any LLM CLI as a templated command. Per-backend prompt flags and plan-mode defaults.
- Worktree isolation — every task gets
~/.argus/worktrees/<project>/<task>and anargus/<task>branch, all transactionally created and cleaned up. - Session resume —
--resumeon Claude Code,codex resume <id>on Codex. Your conversation survives a daemon restart. - Consistent scrollback across viewers — switch between the TUI and the PWA at very different widths and the agent re-emits the conversation at the new size. Idle-gated so it never fires mid-tool-call; the SPA reattaches transparently.
- Agent forking — duplicate a running task with full context (source info, recent output, git diff) injected into the new worktree.
- Smart auto-naming — a Claude Haiku call quietly turns a free-form prompt into a kebab-case task name. Falls open to a regex slug if
claudeis unavailable. - Scheduled tasks — cron, descriptors, intervals, or one-shot runs. Each fire spawns a fresh task. Manage from TUI, PWA, or MCP.
- PR review dashboard — open PRs across configured repos, syntax-highlighted diffs, approve / request changes / line-comment from the TUI.
- macOS sandbox-exec — per-session SBPL profiles.
~/.gnupg,~/.aws,~/.kube,~/.config/gcloudblocked by default. - Self-update —
git pull+go install+ daemon restart from a single Settings row. Active sessions reattach across the swap. - Auto-start at login — install the daemon as a launchd LaunchAgent so your agents survive reboots without launching the TUI.
- Full PTY emulation —
charmbracelet/x/vtpainting cells directly totcell. Colors, attributes, OSC 8 hyperlinks, infinite scrollback, bracket paste.
go install github.com/drn/argus/cmd/argus@latest
argusPure Go, no CGO. SQLite via modernc.org/sqlite. Built with tcell and tview.
argus daemon install # macOS — auto-start at login via launchdTo open the PWA, enable Remote API in Settings, then point your phone at http://<your-machine>:7743/ and paste the master token from ~/.argus/api-token. Tailscale recommended.
The sections below are the dense usage docs — keybindings, REST endpoints, configuration tables. Skim if you're getting started; bookmark if you're already running.
| Key | Action |
|---|---|
n |
New task (with skill autocomplete in prompt field) |
Enter |
Open agent view |
ctrl+f |
Fork task (duplicate with context) |
s / S |
Advance / revert status |
a |
Toggle archive |
w |
Toggle "Waiting for Review" (own section above Archive) |
P |
Toggle pin (★ section pinned to the top of the task list) |
p |
Open PR in browser |
c |
Copy task prompt to clipboard |
ctrl+d |
Destroy task (kill agent + remove worktree + delete branch) |
ctrl+r |
Prune completed tasks |
j / k |
Navigate up/down |
1 / 2 / 3 |
Switch tabs (Tasks / Reviews / Settings) |
ctrl+l |
Refresh screen (wipe ghost cells; works in every non-agent tab) |
q |
Quit |
| Key | Action |
|---|---|
ctrl+q / Esc |
Back (3-level: diff → files → task list) |
Cmd+← / Cmd+→ |
Switch panels |
Cmd+↑ / Cmd+↓ |
Navigate between tasks |
ctrl+p |
Open PR in browser |
ctrl+l |
Open link picker (fuzzy search all session URLs) |
ctrl+y |
Copy agent-staged text (only when payload pending; otherwise sent to PTY) |
o |
Open PR in browser (when session is finished) |
Shift+↑ / Shift+↓ |
Scroll terminal (with acceleration) |
| Key | Action |
|---|---|
Enter |
Open diff |
s |
Toggle split/unified diff |
o |
Reveal in Finder |
e |
Open in editor |
t |
Open terminal in worktree |
| Key | Action |
|---|---|
Esc / ctrl+q |
Close / cancel |
Enter |
Confirm / submit |
Tab / Shift+Tab |
Navigate fields |
| Key | Action |
|---|---|
j / k |
Navigate PRs |
R |
Refresh PR list |
a |
Approve PR |
r |
Request changes |
c |
Line comment |
| Key | Action |
|---|---|
j / k |
Navigate rows |
n |
New project / backend / schedule |
e |
Edit project / backend / schedule |
d |
Delete project / set default backend / delete schedule |
t |
Toggle schedule enabled (on the Scheduled Tasks section) |
r |
Run schedule now (on the Scheduled Tasks section) |
i |
Quick add projects |
Enter / ◀ / ▶ |
Toggle / cycle settings |
From the Settings tab (Status section, when the daemon is connected) the Source path row holds the path to your local Argus checkout, and the Update Argus row runs git pull --ff-only followed by go install ./... and then restarts the daemon so the new binary takes over. Active sessions reattach across the restart. The same controls are exposed in the web UI under Settings → Argus update (master token only).
Toggle from Settings → Status → Auto-start at login (Enter), or use the CLI:
argus daemon install # write ~/Library/LaunchAgents/com.drn.argus.daemon.plist and bootstrap into launchd
argus daemon uninstall # bootout and remove the plist
argus daemon status # show plist path + installed/loaded stateThe plist is configured with RunAtLoad and KeepAlive { SuccessfulExit = false }, which means launchd starts the daemon at login and restarts it if it crashes (non-zero exit) — but a clean argus daemon stop is honored and won't trigger a respawn. Stdout/stderr are written to ~/.argus/launchd.log. The plist points at ~/.argus/argusd, a symlink to the resolved argus binary; reinstalling rewrites the symlink so launchd picks up the new binary on next start. macOS only — Linux/Windows show no toggle.
Argus can run agent processes inside macOS sandbox-exec for filesystem and credential isolation. Each agent session gets an SBPL profile that restricts reads and writes.
Global sandbox settings are managed in the Settings tab (4 key):
| Setting | Description |
|---|---|
| Enabled | Master toggle — applies to all projects by default |
| Deny Read | Extra paths to block reads from (comma-separated) |
| Extra Write | Extra paths to allow writes to (comma-separated) |
Per-project overrides are set in the project form (e on a project in Settings) — Inherit, Enabled, or Disabled. Per-project deny-read and extra-write paths are appended to the global lists.
Always denied read: ~/.gnupg, ~/.aws, ~/.kube, ~/.config/gcloud
Always allowed write: the task's worktree directory, /tmp, /var/folders, ~/.claude.json, ~/.claude/, the main repo's .git dir.
Cycle through styles in the Settings tab using Enter or ◀/▶ on the Spinner row:
| Style | Frames | Speed |
|---|---|---|
| Progress (default) | Nerd Font progress icons | 100ms |
| Dots | Braille dots ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ |
100ms |
| Braille | Braille pattern ⣷⣯⣟⡿⢿⣻⣽⣾ |
100ms |
| Classic | ASCII |/-\\ |
150ms |
Argus runs an MCP server on port 7742 and auto-injects it into every agent worktree.
Knowledge Base:
| Tool | Description |
|---|---|
kb_search |
Full-text search with ranked results and snippets |
kb_read |
Read full document content by vault-relative path |
kb_list |
List documents with optional path prefix filtering |
kb_ingest |
Add or update a document in the knowledge base |
kb_delete |
Remove a document by vault-relative path |
Task Management (lets agents orchestrate other agents):
| Tool | Description |
|---|---|
task_create |
Create a task with worktree and start an agent. Params: name, prompt, project |
task_list |
List tasks, filtered by status and/or project |
task_get |
Get task details by id |
task_stop |
Stop a running agent (moves task to "in review") |
task_archive |
Archive or unarchive a task. Pass cwd (from the agent's pwd) to resolve by worktree, or id. Omit archived to toggle. |
task_rename |
Rename a task. Updates only the display name (branch and worktree paths stay locked to the original slug). Pass cwd or id plus name. |
task_complete |
Mark a task as complete (sets status, stamps EndedAt). Pass cwd or id. Does NOT stop a running agent — call task_stop first if needed. |
Sample skills at .claude/skills/archive/SKILL.md and .claude/skills/argus-complete/SKILL.md let an agent finalize its own task at the end of a session via cwd resolution. Completing and archiving are independent axes.
Schedule Management:
| Tool | Description |
|---|---|
schedule_list |
List all schedules with name, project, cron expression, enabled state, next/last fire timestamps |
schedule_create |
Create. Params: name, project, prompt, plus exactly one of schedule (cron or @every <duration>) or run_once_at (RFC3339 UTC); optional backend, enabled |
schedule_update |
Partial update — pass id plus any fields to change. Toggling enabled, rotating prompts, or converting between cron and one-shot (set the new field; the other clears automatically). |
schedule_delete |
Remove a schedule by id. Tasks already created by previous fires are unaffected. |
schedule_run_now |
Fire a schedule immediately, out of cycle. Bookkeeping is updated so the next regular tick will not double-fire. One-shot rows auto-disable. Does NOT send a push notification — only cron-tick fires do. |
Agent-Staged Clipboard:
| Tool | Description |
|---|---|
argus_clipboard_set |
Stage text for the user to copy with one tap (PWA Copy button) or one keypress (TUI ctrl+y). Params: text (required), id or cwd. Last-write-wins, 5-min TTL, 1 MiB max. |
All endpoints require auth — Authorization: Bearer <token> header or ?token=<token> query param (the latter is required for EventSource/SSE because browsers cannot set headers on it). The token can be the master token from ~/.argus/api-token or any non-revoked device token.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/status |
Running/idle session counts, task counts by status |
GET |
/api/tasks |
List tasks. Filters: ?status=, ?project=, ?archived=1 (or =all). Each task carries idle: true when in_progress but the session is missing or waiting for input. |
POST |
/api/tasks |
Create and start a task. JSON {"name", "prompt", "project", "backend?"}, OR multipart/form-data with name/prompt/project/backend plus files parts (uploaded into <worktree>/.context/, paths appended to the prompt). Per-file 10MB / total 50MB / 20 files cap. |
GET |
/api/tasks/{id} |
Get single task detail (includes archived, worktree_path, prompt, idle) |
POST |
/api/tasks/{id}/stop |
Stop a running agent (moves to in_review) |
POST |
/api/tasks/{id}/resume |
Resume a stopped agent |
DELETE |
/api/tasks/{id} |
Delete a task |
POST |
/api/tasks/{id}/archive |
Archive (hidden from default list) |
POST |
/api/tasks/{id}/unarchive |
Restore from archive |
POST |
/api/tasks/{id}/rename |
{"name":"..."} |
POST |
/api/tasks/{id}/fork |
Clone to a new task. Body: {"name?", "prompt?", "project?"} |
POST |
/api/tasks/{id}/status |
Set status. Body: {"status":"in_review"|"complete"|"pending"|"in_progress"} |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/tasks/{id}/output |
Recent output (text). Optional ?bytes=, ?clean=1 |
GET |
/api/tasks/{id}/links |
Extract http/https URLs from terminal output. Returns {"links":[{"label","url"}]}. Powers the PWA's "Open link" overflow item. |
POST |
/api/tasks/{id}/input |
Send raw bytes to PTY stdin |
POST |
/api/tasks/{id}/upload |
Upload files mid-session. multipart/form-data with files parts; saved to <worktree>/.context/<name> (auto-suffixed on collision) and returns {paths:[]}. Same 10MB/50MB/20-file caps as create. |
GET |
/api/tasks/{id}/stream |
SSE stream of live output (base64-encoded chunks) |
GET |
/api/tasks/{id}/size |
Current PTY dimensions: {cols, rows} |
POST |
/api/tasks/{id}/resize |
Resize PTY: {"cols":N,"rows":M}. Returns {cols,rows,rerendered} — rerendered:true means the resize crossed the rerender margin (≥30 col delta from session-start width) and the daemon queued a kill+resume so the agent re-emits scrollback at the new width. The SPA's exit-event handler reattaches automatically. |
POST |
/api/sessions/stop-all |
Stop every running session |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/tasks/{id}/git/status |
git status output + branch diff for the task's worktree |
GET |
/api/tasks/{id}/git/diff?path=<file> |
Unified diff for a single file |
GET |
/api/tasks/{id}/files?dir=<rel> |
Worktree file listing |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/projects |
List project names |
GET |
/api/projects/full |
List with path, branch, default_backend |
POST |
/api/projects |
Create. Body: {"name", "path", "branch?", "backend?", "sandbox?"} where sandbox is {"enabled": true|false|null, "deny_read":[], "extra_write":[]} (null = inherit global) |
PUT |
/api/projects/{name} |
Update |
DELETE |
/api/projects/{name} |
Delete |
GET |
/api/backends |
List with command + prompt_flag |
POST |
/api/backends |
Create |
PUT |
/api/backends/{name} |
Update |
DELETE |
/api/backends/{name} |
Delete |
GET |
/api/skills |
Skill autocomplete. Filter: ?project=, ?filter= (case-insensitive substring) |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/push/vapid-public-key |
VAPID public key (urlsafe base64) for pushManager.subscribe() |
POST |
/api/push/subscribe |
Register a subscription. Body: {"label","endpoint","keys":{"p256dh","auth"}} |
GET |
/api/push/subscriptions |
List with masked endpoints |
DELETE |
/api/push/subscribe/{id} |
Unsubscribe |
POST |
/api/push/test |
Fan out a test notification to every device |
The daemon polls running sessions every 5s; when a session transitions to idle, every subscription receives a notification (throttled to 1 per task per 5 min). Subscriptions returning 410 Gone are auto-pruned.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/tokens |
List tokens with last-4 + label |
POST |
/api/tokens |
Mint a new device token. Master token required. Body: {"label":"My iPhone"} → {"id","label","token"} (plaintext shown once) |
DELETE |
/api/tokens/{id} |
Revoke. Master token required. |
Tokens are stored as SHA-256 hashes; plaintext is never persisted on the server.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/schedules |
List schedules with next_run_at, last_run_at, last_task_id, last_error. Master token required (prompts can carry sensitive instructions). |
POST |
/api/schedules |
Create. Body: {"name","project","prompt","schedule","backend?","enabled"}. Master token required. Returns the created row. |
PUT |
/api/schedules/{id} |
Partial update — every field optional. Useful for toggling enabled. Master token required. |
DELETE |
/api/schedules/{id} |
Remove. Tasks already created by the schedule are not affected. Master token required. |
POST |
/api/schedules/{id}/run |
Fire the schedule now, regardless of cron timing. Returns {"task_id"}. Master token required. |
Schedule expressions accept the standard 5-field cron syntax (e.g. 0 9 * * 1-5), descriptors (@hourly, @daily, @weekly, @monthly, @yearly), and intervals (@every 30m).
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/settings |
Returns sandbox / KB / API / defaults config plus sandbox.available (whether sandbox-exec is on this host). Device tokens may read. |
PUT |
/api/settings |
Partial update — every section is optional. Body: {"sandbox":{...}, "kb":{...}, "api":{...}, "defaults":{...}}. Master token required. |
GET |
/api/logs/{ux|daemon}?bytes=N |
Tail the last N bytes of the log (default 64K, max 1M). Missing files return 200 with empty body. |
The daemon runs as a normal process on the host machine. When the host sleeps, HTTP responses stall, SSE streams disconnect, and push notifications stop firing. PTY sessions pause where they were and resume when the host wakes.
For a clamshell-mode laptop driving an external display:
- Use
caffeinate -is(no-d) or KeepingYouAwake with Allow display sleep enabled — keeps system + idle awake while letting the display sleep. - For a permanent setup on AC power:
sudo pmset -c sleep 0 disablesleep 1 displaysleep 1. - Sleeping the external display via
pmset displaysleepnow(or a hot corner) is fine; physically disconnecting it will sleep the Mac because the lid is closed.
For secure remote access without exposing ports to the internet:
- Install Tailscale on your machine and phone
- Enable the API in Argus Settings
- Access the dashboard at
http://<tailscale-ip>:7743/from your phone
When the PWA cannot reach the API — daemon stopped, host asleep, or Tailscale off — it flips to an offline screen with the Argus banner and a Tailscale reminder, then auto-reconnects once the daemon is reachable again.
All state (tasks, projects, backends, keybindings, UI settings, KB index) is persisted in SQLite at ~/.argus/data.sql.


