Agent Console:统一管理多个 Claude Code 智能体的浏览器控制台
ms2sato/agent-console
Agent Console 是一个基于浏览器的 Web 应用,用于统一管理运行在不同 git worktree 中的多个 AI 编码智能体实例,目前默认支持 Claude Code,未来计划支持 Gemini CLI、Codex 等。
Note: Currently only tested on macOS & Claude Code.
Security Note: This tool is designed for local personal use only. It provides terminal access to your system and should not be deployed as a shared server or exposed to untrusted networks. The server binds to
localhostby default.
A web application for managing multiple AI coding agent instances running in different git worktrees. Control all your agents through a unified browser interface instead of scattered terminal windows.
Currently supports Claude Code as the default agent, with plans to support additional agents (Gemini CLI, Codex, etc.) in the future.
Features
- Unified Dashboard: View and manage all repositories, worktrees, and agent sessions in one place
- Browser-based Terminal: Full terminal access via xterm.js - no need for separate terminal windows
- Session Persistence: Sessions continue running even when you close the browser tab (tmux-like behavior)
- Multiple Workers per Session: Run agent and terminal workers side-by-side within a single session
- Inter-worker Messaging: Send messages between workers in the same session via an embedded message panel
- Git Worktree Integration: Create and delete git worktrees directly from the UI
- Real-time Updates: WebSocket-based notifications for session and worker lifecycle changes
- Orchestration via MCP: Agents can delegate tasks, coordinate workflows, and manage other agents programmatically via MCP tools
Key Concepts
- Session: A working context tied to a git worktree or arbitrary directory. Each session can have multiple workers.
- Worker: A PTY process running within a session. Two types:
- Agent Worker: Runs an AI agent (e.g., Claude Code)
- Terminal Worker: A plain terminal shell
Architecture
Backend (Bun + Hono) Frontend (React + Vite)
┌──────────────────────────┐ ┌──────────────────────────┐
│ SessionManager │ │ Dashboard │
│ ├── Session1 │ │ ├── SessionList │
│ │ ├── AgentWorker │◄──────►│ │ └── WorkerTabs │
│ │ └── TerminalWorker │ WS │ └── Terminal (xterm.js) │
│ └── Session2 │ │ │
│ └── AgentWorker │ │ │
└──────────────────────────┘ └──────────────────────────┘
Requirements
-
Bun >= 1.3.5
scripts/check-bun-version.mjsis wired as apreinstallhook and hard-fails on older Bun, so the requirement is enforced rather than advisory. The floor is set by two features:Bun.Terminal(used by the server, 1.3.5+) andminimumReleaseAge(the supply-chain age gate, 1.3.0+); the higher of the two wins. See Supply Chain Security for the age gate details.
Development
Setup
# Install dependencies bun install # Start development servers (frontend + backend) bun dev
The development server runs at:
- Frontend: http://localhost:5173
- Backend: http://localhost:3457
Environment Configuration
When running multiple development instances (e.g., in different git worktrees), you can use a .env file to avoid port and data conflicts.
# Copy the example file cp .env.example .env # Edit .env with your settings
Available variables:
| Variable | Default | Description |
|---|---|---|
PORT |
3457 |
Backend server port |
CLIENT_PORT |
5173 |
Frontend dev server port |
AGENT_CONSOLE_HOME |
~/.agent-console-dev |
Data directory (DB, outputs) |
Bun automatically loads .env files - no additional packages required.
For a claude-sdk embedded worker's project .mcp.json ${VAR} placeholders: in single-user mode the placeholders resolve from the server's cleaned environment (see docs/multi-user-setup-guide.md for the multi-user equivalent).
Build
bun run build
This creates a production bundle in the dist/ directory:
dist/
├── package.json # Standalone package manifest
├── index.js # Bundled server
└── public/ # Built frontend assets
Production
# From the project root (after build)
bun startOr run directly:
NODE_ENV=production bun dist/index.js
The server runs at http://localhost:3457
macOS Launch Agent
A deployment script is provided to install Agent Console as a macOS Launch Agent (auto-start on login):
# Deploy with defaults (port 6340) ./scripts/update-and-deploy-for-mac.sh # Deploy with custom port PORT=8080 APP_URL=http://localhost:8080 ./scripts/update-and-deploy-for-mac.sh
The script builds the project, copies files to ~/.agent-console/server/, installs a launchd plist, and starts the service.
Environment Configuration via ~/.agent-console/.env
The Launch Agent loads ~/.agent-console/.env on every startup. This is the recommended way to configure the server in production — especially for secrets that should not be embedded in the plist file.
# Example: ~/.agent-console/.env
GITHUB_WEBHOOK_SECRET=your-secret-here
LOG_LEVEL=infoAfter editing .env, restart the service to apply changes (no redeployment required):
launchctl kickstart -k "gui/$(id -u)/com.agent-console"Available server environment variables are defined in packages/server/src/lib/server-config.ts.
Note: Variables set in
.envoverride values from the launchd plist.PORT,APP_URL,NODE_ENV, andPATHare set in the plist at deploy time; all other variables should be configured via.env.
Supply Chain Security
This repo uses Bun's minimumReleaseAge install setting to refuse npm package versions younger than 7 days. Compromised packages are usually detected or unpublished within a few days of release, so a short cool-off window catches the common case while letting routine updates through.
Configuration lives in bunfig.toml at the repo root. A preinstall hook (scripts/check-bun-version.mjs) enforces the repo's minimum Bun version, which is at or above the 1.3.0 floor required by minimumReleaseAge, so the age gate is never silently ignored.
Emergency override
When you genuinely need a just-published version (e.g., a CVE patch), bypass the gate for that single command rather than editing bunfig.toml:
# CLI flag, scoped to one invocation: bun add <pkg> --minimum-release-age 0 # Or via environment variable: BUN_CONFIG_MINIMUM_RELEASE_AGE=0 bun install
Record the reason (CVE number, advisory link, etc.) in the commit message or PR description so the override is auditable. Do not lower minimumReleaseAge in bunfig.toml — keep the gate intact and override per-command.
Standalone Distribution
The dist/ directory can be distributed independently. Users only need to:
cd dist bun install # Installs only bun-pty (~few seconds) bun start # Starts the server
Template Configuration
When creating a new worktree, Agent Console can automatically copy template files into it. This is useful for setting up consistent configurations (e.g., .claude/settings.local.json for MCP servers) across all worktrees.
Template Locations
Templates are searched in the following order (first found wins):
- Repository-local:
.agent-console/directory in the repository root - Global:
$AGENT_CONSOLE_HOME/repositories/<owner>/<repo>/templates/
The default $AGENT_CONSOLE_HOME is ~/.agent-console.
Directory Structure
Place files in the templates directory with the same structure you want in the worktree:
~/.agent-console/repositories/<owner>/<repo>/templates/
├── .claude/
│ └── settings.local.json # → copied to <worktree>/.claude/settings.local.json
├── .env.local # → copied to <worktree>/.env.local
└── any/
└── nested/
└── file.txt # → copied to <worktree>/any/nested/file.txt
Placeholders
Template files support variable substitution using {{VARIABLE}} syntax:
| Placeholder | Description | Example |
|---|---|---|
{{WORKTREE_NUM}} |
Worktree index number (0, 1, 2, ...) | 1 |
{{BRANCH}} |
Branch name | feature/add-login |
{{REPO}} |
Repository name (without owner) | agent-console |
{{WORKTREE_PATH}} |
Full path to the worktree | /Users/me/.agent-console/.../wt-001-abc |
Arithmetic Expressions
{{WORKTREE_NUM}} supports arithmetic operations:
| Expression | Description | Example (WORKTREE_NUM=2) |
|---|---|---|
{{WORKTREE_NUM + 3000}} |
Addition | 3002 |
{{WORKTREE_NUM - 1}} |
Subtraction | 1 |
{{WORKTREE_NUM * 10}} |
Multiplication | 20 |
{{WORKTREE_NUM / 2}} |
Division (floor) | 1 |
Example: Environment Variables
To configure different ports for each worktree's development server (.env.local):
# Worktree: {{BRANCH}}
DEV_PORT={{WORKTREE_NUM + 3000}}
API_PORT={{WORKTREE_NUM + 4000}}With this template, worktree 0 uses DEV_PORT=3000, worktree 1 uses DEV_PORT=3001, and so on.
Orchestration via MCP
Agent Console exposes MCP (Model Context Protocol) tools that turn any AI agent into an orchestrator. A single agent can delegate tasks to new worktrees, monitor their progress, coordinate inter-agent communication, run review workflows, and manage timers — all programmatically through a unified tool interface.
Setup
Register the Agent Console MCP server in Claude Code (one-time):
# For production (default port 6340) for user scope claude mcp add --scope user --transport http agent-console http://localhost:6340/mcp # For production (default port 6340) for local scope claude mcp add --transport http agent-console http://localhost:6340/mcp # For development (if using a different port, match your .env PORT) for local scope claude mcp add --transport http agent-console-dev http://localhost:3457/mcp
This adds the MCP server to ~/.claude.json. All Claude Code instances (including those spawned by Agent Console) will automatically discover the tools.
Tip: If you change the server port, update the URL accordingly. Multiple Agent Console instances can coexist with different names (e.g.,
agent-console,agent-console-2).
Available MCP Tools
Session Management
| Tool | Description |
|---|---|
list_sessions |
List all active sessions with worker activity states |
get_session_status |
Get a specific session's status, workers, and parent info |
close_session |
Close a session and clean up its workers |
Worktree Delegation
| Tool | Description |
|---|---|
delegate_to_worktree |
Create a worktree + session + agent and send a prompt — the primary orchestration tool |
remove_worktree |
Remove a git worktree and its associated session |
Communication
| Tool | Description |
|---|---|
send_session_message |
Send a message to a worker in another session (file-based with PTY notification) |
write_memo |
Write a Markdown memo for a session, visible in the UI |
Timer
| Tool | Description |
|---|---|
create_timer |
Create a periodic timer that sends notifications to a worker at specified intervals |
delete_timer |
Delete a periodic timer |
list_timers |
List active timers, optionally filtered by session |
Interactive Process
| Tool | Description |
|---|---|
run_process |
Start an interactive script that communicates via STDOUT/STDIN |
write_process_response |
Send a response to a waiting interactive process |
kill_process |
Terminate a running interactive process |
list_processes |
List all interactive processes (useful after agent restart) |
Review
| Tool | Description |
|---|---|
write_review_annotations |
Write review annotations for a git-diff worker, pushed to the client in real-time |
clear_review_annotations |
Clear all review annotations for a git-diff worker |
Agent & Repository Registry
| Tool | Description |
|---|---|
list_agents |
Discover available agents (built-in + custom) with capabilities |
list_repositories |
Discover available repositories with IDs and remote URLs |
Patterns in Practice
Parallel Delegation
An orchestrator splits work across multiple worktrees and monitors progress:
Orchestrator (wt-000)
├── delegate_to_worktree → Agent A (wt-001): "implement feature X"
├── delegate_to_worktree → Agent B (wt-002): "write tests for module Y"
└── delegate_to_worktree → Agent C (wt-003): "fix bug Z"
... later ...
├── get_session_status(wt-001) → "active, working"
├── get_session_status(wt-002) → "idle, waiting for input"
└── get_session_status(wt-003) → "idle, task complete"
With parentSessionId and parentWorkerId, delegated agents automatically report results back via send_session_message.
Timer-Based Monitoring
Set up periodic check-ins to monitor long-running tasks:
create_timer(sessionId, workerId, intervalSeconds: 300, action: "check CI status and report")
→ Timer fires every 5 minutes with [internal:timer] PTY notification
→ Agent wakes up, checks status, takes action
delete_timer(timerId) # Clean up when done
Interactive Process Workflow
Drive scripts that require back-and-forth communication:
run_process(command: "node acceptance-check.js 526", sessionId, workerId)
→ Process starts, sends STDOUT as [internal:process] PTY notifications
→ Agent reads output, decides next action
write_process_response(processId, content: "approve")
→ Process receives response, continues execution
kill_process(processId) # Terminate if needed
Review and Memo
Annotate diffs for human review and leave persistent notes:
write_review_annotations(workerId, sessionId, annotations: [...], summary: {...})
→ Annotations appear in the git-diff viewer in real-time
write_memo(sessionId, content: "## Status\n- Feature complete\n- Tests passing\n- Ready for review")
→ Memo visible in the session UI panel
See docs/design/self-worktree-delegation.md for the full design document.
GitHub Webhook Integration (Inbound Events)
Agent Console can receive GitHub webhooks and route them to active sessions. When a webhook arrives (e.g., CI failure, PR merged), Agent Console:
- Matches the event to sessions working on the same repository
- Notifies agent workers by writing a structured message to the agent's PTY input
- Sends UI notifications via WebSocket to connected browsers
Setup
-
Set the webhook secret environment variable:
GITHUB_WEBHOOK_SECRET=your-secret-here
For the macOS Launch Agent, add it to
~/.agent-console/.env. -
Expose the webhook endpoint to the internet:
GitHub sends webhooks from its servers, so your local Agent Console must be reachable via a public URL. Use a tunnel service such as ngrok, Cloudflare Tunnel, or similar:
# Example with ngrok (forward to the Agent Console server port) ngrok http 3457 # → https://xxxx-xxxx.ngrok-free.app
-
Configure the webhook in GitHub:
- Go to Settings > Webhooks > Add webhook in your repository (or organization)
- Payload URL:
https://<your-tunnel-domain>/webhooks/github - Content type:
application/json - Secret: Same value as
GITHUB_WEBHOOK_SECRET - Events: Select individual events:
Workflow runs,Issues,Pull requests
Multi-user mode (Ubuntu / systemd) recipe
Place the secret in a file outside the deploy target so that the rsync --delete in scripts/update-and-deploy-for-multiuser-ubuntu.sh does not wipe it on the next redeploy. The recommended path is /home/<service-user>/.config/agent-console/secrets.env, owned by the service user with mode 0600. Then point the systemd unit at it via EnvironmentFile=-.
# 1. Secret file outside the deploy target sudo mkdir -p /home/agentconsole/.config/agent-console echo "GITHUB_WEBHOOK_SECRET=$(openssl rand -hex 32)" | \ sudo tee /home/agentconsole/.config/agent-console/secrets.env sudo chown -R agentconsole:agentconsole /home/agentconsole/.config/agent-console sudo chmod 600 /home/agentconsole/.config/agent-console/secrets.env # 2. Reference from the systemd unit sudo systemctl edit --full agent-console.service # In [Service], add: # EnvironmentFile=-/home/agentconsole/.config/agent-console/secrets.env # The leading `-` makes the unit start even if the file is absent. # 3. Reload + restart sudo systemctl daemon-reload sudo systemctl restart agent-console.service # 4. Verify (see "Verifying webhook configuration" below for the auth-cookie variant) # From a logged-in browser DevTools console: # fetch('/api/system/health').then(r => r.json()).then(console.log) # → { webhookSecretConfigured: true, ... }
Why outside the deploy target. scripts/update-and-deploy-for-multiuser-ubuntu.sh syncs the source-repo into the deploy target with rsync -a --delete, excluding only node_modules and .git. A secret file placed at <deploy-target>/.env would work on the first deploy (Bun auto-loads env files at WorkingDirectory) but would be deleted on the next update-and-deploy-for-multiuser-ubuntu.sh invocation, because env files are excluded from the source-repo by .gitignore. Placing the secret under /home/<service-user>/.config/agent-console/ and referencing it via EnvironmentFile=- keeps deploys and secret management on independent lifecycles.
Tunneling for inbound webhooks (Cloudflare Tunnel, ngrok, etc.) works the same as in the single-user instructions above — point the public URL at the server's HOST:PORT (e.g. 127.0.0.1:8080 for the bootstrap default).
Supported Events
| GitHub Event | Condition | Inbound Event | Actions |
|---|---|---|---|
| Workflow runs | Completed successfully | ci:completed |
Notify agent, refresh diff view |
| Workflow runs | Completed with failure | ci:failed |
Notify agent, show UI alert |
| Issues | Closed | issue:closed |
Show UI alert |
| Pull requests | Merged | pr:merged |
Refresh diff view, show UI alert |
How Events Are Routed
- Events are matched to sessions by comparing the webhook's repository name with each session's git remote URL
- If the event includes a branch name, only sessions working on that branch are notified
- Events without a branch (e.g., issue closed) are delivered to all sessions for that repository
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
GITHUB_WEBHOOK_SECRET |
Yes | (empty) | Shared secret for HMAC-SHA256 signature verification. If unset, incoming webhooks are accepted but not processed (the endpoint still returns 200 OK). Check server logs or GET /api/system/health to verify configuration. |
Verifying webhook configuration via /api/system/health
GET /api/system/health returns { webhookSecretConfigured: boolean, appUrl: string | null } for the running server. This endpoint requires authentication — unauthenticated requests return 401 Unauthorized. Two reliable ways to call it:
- From a logged-in browser DevTools console:
fetch('/api/system/health').then(r => r.json()).then(console.log)
- With curl, providing the auth cookie: Copy the
auth_token=...cookie value from your browser's DevTools (Application → Cookies) and pass it via--cookie. The cookie name isauth_token(defined inpackages/server/src/lib/auth-constants.ts):curl -s --cookie "auth_token=<your-auth-cookie-value>" http://localhost:8080/api/system/health | jq
A simple unauthenticated curl -sf http://localhost:8080/api/system/health returns an empty body (silent failure on 401), which is easy to misread as "the webhook is unconfigured." Use one of the authenticated paths above.
Project Structure
agent-console/
├── packages/
│ ├── client/ # React frontend
│ ├── server/ # Hono backend
│ └── shared/ # Shared TypeScript types
├── docs/ # Documentation
├── scripts/ # Deployment scripts
└── dist/ # Production build output (generated)
Contributing
See AGENTS.md for repository guidelines, commands, and testing expectations.
Tech Stack
- Backend: Bun, TypeScript, Hono, bun-pty
- Frontend: React, TypeScript, Vite, TanStack Router, TanStack Query, xterm.js, Tailwind CSS
- Build: Bun bundler (server), Vite (frontend)
- Package Manager: Bun workspaces
AI-Driven Development
This project serves as a testbed for exploring the boundaries of AI-assisted software development. The goal is to minimize human involvement throughout the entire development lifecycle:
- Code generation: All code is written by Claude Code, not by humans
- Code review: Reviews are performed by Claude subagents (code-quality-reviewer, test-reviewer, ux-architecture-reviewer)
- Testing: Test code is also generated and reviewed by AI
The human role is limited to:
- Providing high-level requirements and direction
- Final approval of pull requests
- Resolving issues that AI cannot handle autonomously
This approach allows us to dogfood Agent Console while simultaneously validating how far AI can go in autonomous software development. The codebase you see here is the result of this experiment.
Special Thanks
This project is built on the shoulders of amazing open-source projects:
- Claude Code - The AI coding agent that wrote most of this codebase with remarkable speed and quality. This project literally couldn't exist without it.
- Bun - Blazing fast runtime that makes development a joy
- Hono - Ultrafast web framework with excellent DX
- TypeScript - Type safety that saves countless debugging hours
- xterm.js - The terminal emulator that makes browser-based CLI possible
Inspiration
- Vibe Kanban - A fantastic project for managing AI coding agents. Exploring this project sparked the idea for Agent Console. Highly recommended!
Thank you to all the maintainers and contributors!
License
MIT
来源:GitHub · github.com