AI coding agents like Claude Code and Codex are powerful, but they have no built-in cost controls—one runaway session can silently burn $20–$50 with no visibility into what’s happening or when to stop. Agents Fleet gives you a local web UI to launch and monitor agent sessions and automatically stop them when they hit a token or USD budget.
Local-first “mission control” for AI coding agent CLIs (and any shell commands): launch sessions in a repo, stream live output to a web UI, stop them, and keep a persisted history.
- Real-time usage tracking (PR #2): Parse Claude Code status lines for accurate token/cost counting instead of estimates
- Budget enforcement that actually works
This repository contains a working MVP:
- pnpm workspace monorepo
- React + Vite + TypeScript “Mission Control” web app
- Node + Express + TypeScript server:
- SQLite persistence (
data/agents_fleet.sqlite) - session + terminal history HTTP APIs
- WebSocket streaming (
/ws):- live PTY output for shell/CLI sessions
- live Claude SDK chat streaming + tool events
- SQLite persistence (
- shared TypeScript types (
packages/shared)
New session form
Live terminal (interactive agents)
- Claude Code (interactive TUI rendered via xterm.js)
- OpenAI Codex (interactive)
Per-session artifacts (git diff snapshots)
- Artifacts tab (changed files + diff)
- Artifacts view (larger change set)
Live output vs persisted terminal history
- Terminal (live)
- Terminal (persisted)
Budget enforcement (auto-stop)
- Token budget cutoff
- USD budget cutoff
Cost estimate vs actual (CLI-reported)
SQLite persistence (debug views)
The MVP persists several tables in data/agents_fleet.sqlite:
sessions: session metadata + budgets + estimated token/cost + stop reasonpty_chunks: raw PTY stream (ANSI included) used for Terminal (persisted) replaystdin_events: input audit trail (stored separately; not injected into replay)session_markers: lifecycle markers likestop_requested,budget_exceeded,process_exitsession_artifacts: per-session artifacts (currently: git snapshot withchangedFiles[]+ combined staged/unstageddiffcaptured on stop/exit)
Earlier iterations used a line-based
logstable. The current design persists terminal history as raw PTY chunks (pty_chunks) for xterm.js replay, which is much closer to real scrollback (especially for TUIs like Claude/Codex).
Tip: GitHub renders MP4 previews nicely in README.
.movfiles are ignored by default in.gitignoreto avoid bloating git history.
screenshots/Agents_Fleet__Mission_Control_for_Your_Local_AI_Workers.mp4
See ARCHITECTURE.md.
- Node.js 20.x
- pnpm (Corepack is fine)
COREPACK_HOME="$PWD/.corepack" pnpm installpnpm dev:oneOn first run, this may optionally prompt you for ANTHROPIC_API_KEY and save it to .env.local (gitignored). Press Enter to skip.
This will:
- install dependencies (if needed)
- start
apps/server+apps/webin parallel
Open: http://localhost:5173
COREPACK_HOME="$PWD/.corepack" pnpm -C apps/server dev
COREPACK_HOME="$PWD/.corepack" pnpm -C apps/web dev- Open the web app (Vite prints the URL, typically
http://localhost:5173). - Enter:
- Repo path: absolute path to a local repository (must be a directory)
- Command: any shell command to run in that repo
Example commands:
node -e "console.log('hello')"
git status
node -e "setinterval(()=>console.log('tick',Date.now()),200)"
node -e "setInterval(()=>console.log(Date.now()),200)"
claude
codex- Start a session with command
claude(orcodexif installed).
Claude Code can run a custom status line command that receives structured JSON about the current session (context window usage, estimated cost, etc.).
For the most reliable budget tracking in Agents Fleet, configure a single-line status line that prints parse-friendly key/value pairs.
- Create the script:
#!/bin/bash
input=$(cat)
CTX_IN=$(echo "$input" | jq -r '.context_window.total_input_tokens // 0')
CTX_OUT=$(echo "$input" | jq -r '.context_window.total_output_tokens // 0')
CTX_SIZE=$(echo "$input" | jq -r '.context_window.context_window_size // 0')
CTX_PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
COST_FMT=$(printf '$%.6f' "$COST")
# Single-line, parse-friendly output:
# Use a unique prefix + delimiter to make parsing reliable even with TUI redraws.
echo "AF|ctx=${CTX_IN}/${CTX_SIZE}(${CTX_PCT}%)|in=${CTX_IN}|out=${CTX_OUT}|cost=${COST_FMT}"Save it as ~/.claude/agents_fleet_statusline.sh and make it executable:
chmod +x ~/.claude/agents_fleet_statusline.sh- Update
~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "~/.claude/agents_fleet_statusline.sh",
"padding": 1,
"refreshInterval": 1
}
}Notes:
- Requires
jqto be installed (brew install jqon macOS). cost.total_cost_usdis an estimate computed client-side by Claude Code and may differ from your actual bill.- Type directly into the Terminal (live) pane (xterm.js).
- Use Terminal (persisted) to replay and scroll through the recorded PTY output (xterm.js replay).
Codex can also show session usage in a single-line status line. For Agents Fleet, the simplest reliable setup is to keep Codex’s built-in status line enabled and ensure it includes the usage fields below.
- Update
~/.codex/config.toml:
[tui]
status_line = ["model-with-reasoning","current-dir","context-remaining","context-used","total-input-token","total-output-tokens","weekly-limit","five-hour-limit","run-state","task-progress"]
status_line_use_color = true- Make sure the output stays on one line in the Codex TUI.
Notes:
- The config above matches the usage fields Agents Fleet can parse for budget tracking.
- If you change the field list, keep it single-line so PTY replay remains parse-friendly.
- Type directly into the Terminal (live) pane (xterm.js).
- Use Terminal (persisted) to replay and scroll through the recorded PTY output (xterm.js replay).
Prerequisite: set ANTHROPIC_API_KEY (required). The server will reject Claude SDK requests if it’s missing.
- Switch to Claude (SDK) in the UI.
- Provide a repo path and chat normally.
- The assistant can propose
run_commandtool calls; you must Approve or Reject each command. - Tool output is capped (100KB) and stored as session artifacts.
Screenshots:
- Claude SDK session stopped by budget
- Claude SDK tool call + output
- Claude SDK tool permission gate (Approve/Reject)
- Optional
Budget USDand/orBudget tokensapply to the entire session lifetime. - Token estimation:
ceil(text.length / 4). - Cost estimation:
- shell/PTY sessions use the default rates in
apps/server/src/budget.ts - Claude SDK sessions use a model-based pricing table (
computeModelCostUsd) and SDK-reported usage when available.
- shell/PTY sessions use the default rates in
- If a budget is exceeded, the session is stopped automatically and
stop_reasonbecomesbudget_exceeded.
Note: USD cost is still an estimate unless you configure model pricing to match your account/contract.
Configure pricing via a remote API (
PRICING_API_URL, must be https) or via local overrides (PRICING_JSONinline JSON /PRICING_JSON_PATHfile path). Seeapps/server/src/pricing.tsfor schema + env vars.
- Select a running session and click Stop.
- The server will attempt graceful termination first, then force-kill if needed (best-effort, cross-platform).
On session stop and/or exit, Agents Fleet can capture a git snapshot for the session repo and store it in SQLite.
- UI: open the Artifacts tab (next to Terminal tabs) to view changed files + diff.
- Storage:
session_artifactstable. - Toggle: set
AGENTS_FLEET_CAPTURE_GIT_ON_END=0to disable capture.
pnpm dev:oneinstalls deps if needed and runs dev for all workspaces (web + server).pnpm devruns dev for all workspaces (web + server) in parallel.pnpm checkrunslint+typecheck+test+build.pnpm buildbuilds all workspaces.pnpm typecheckruns TypeScript checks across workspaces.
COREPACK_HOME="$PWD/.corepack" pnpm -C apps/server test- If you see Corepack cache permission errors, the
COREPACK_HOME="$PWD/.corepack"prefix keeps Corepack’s cache inside the repo.
- SQLite DB:
data/agents_fleet.sqlite(local only; do not commit).
- PTY sessions do not preserve stdout/stderr separation.
- Token/cost is an estimate unless the CLI provides actual usage.
- Some TUIs (notably Claude) may clear/restore the alternate screen on exit. The persisted replay is a faithful stream replay, so end-of-session scrollback may differ from what you remember seeing just before exit.













