Built and maintained by Thomas Rice, Co-founder of Minotaur Capital.
Arcane Agents is a local-first visual control room for terminal-backed AI agents. Each agent appears as a character on a 2D map, and selecting one opens its live terminal in the right panel. Common setups use Claude Code or OpenCode runtimes, but any terminal-accessible runtime can work.
aa-demo.mp4
- Manages agents as tmux windows.
- Streams live terminal output into the browser via
node-pty+ WebSockets. - Tracks agent status (
idle,working,attention,error) from pane output. - Lets you spawn agents from shortcuts or direct project+runtime combinations.
- Stores state locally in SQLite.
- Linux: fully supported and recommended.
- macOS: core app works, but opening an agent in an external terminal (
↗) is currently Linux-oriented (xdg-terminal-exec). - Windows: use WSL2 (Ubuntu or similar) and run Arcane Agents inside WSL.
- Node.js 20+ and npm
- tmux (hard dependency)
- At least one configured runtime command (for example
opencode,claude, orbash) - Optional but useful:
git(for worktree/discovery workflows)xdg-terminal-exec(Linux external terminal button)
- Install system dependencies.
Linux (Debian/Ubuntu):
sudo apt update
sudo apt install -y tmux gitmacOS (Homebrew):
brew install tmux gitWindows:
- Install WSL2 and Ubuntu.
- Run the Linux setup steps inside WSL.
- Install Arcane Agents globally.
npm install -g arcane-agents- Create your user config.
arcane-agents initarcane-agents start also auto-creates a starter config if it is missing.
- Edit your config.
arcane-agents config editThis opens ~/.config/arcane-agents/config.yaml in $VISUAL or $EDITOR.
- Run setup checks.
arcane-agents doctor- Start Arcane Agents.
arcane-agents- Open
http://127.0.0.1:7600.
Optional maintenance commands:
npm install -g arcane-agents@latest # upgrade
npm uninstall -g arcane-agents # uninstall- Install system dependencies.
Linux (Debian/Ubuntu):
sudo apt update
sudo apt install -y tmux gitmacOS (Homebrew):
brew install tmux gitWindows:
- Install WSL2 and Ubuntu.
- Run the Linux setup steps inside WSL.
- Clone and install dependencies.
git clone https://github.com/thomasrice/arcane-agents.git
cd arcane-agents
npm install- Create your user config.
npm run cli -- init- Edit your config.
npm run cli -- config editOr edit ~/.config/arcane-agents/config.yaml directly.
- Start dev mode (client + server).
npm run devDefault URLs:
- App (Vite):
http://127.0.0.1:7600 - API (Express):
http://127.0.0.1:7601
- Use shortcut buttons in the bottom bar to quickly spawn agents.
- Use the
+button for custom spawn (project + runtime selection). - Click an agent to focus it and attach the terminal panel.
- Drag agents on the map to organize them visually.
- Use contextual controls to stop/restart selected agents.
Selectionfocus: map/roster shortcuts are active.Terminalfocus: keys go directly to the attached terminal.Enteron a selected agent focuses its terminal.- With no selection,
Enteractivates the highlighted roster item; pressEnteragain to focus terminal input. Ctrl+DorCtrl+]exits terminal focus back to selection focus.- Press
Ctrl+DorCtrl+]again in selection focus to clear selection.
/: open command palette.?: show the full shortcut list in-app.Tab/Shift+Tab: cycle agents (or cycle selected-group focus)../,/Shift+.: cycle idle agents.1-0: select control group.Ctrl+1-0: assign selected agents to a control group.K: open kill confirmation for selected agents.Shift+K: kill highlighted roster agent (thenEnterto confirm).R: rename selected agent.M: toggle movement mode for selected agent(s).W/A/S/Dor arrow keys: move selected agents.Shift+W/A/S/DorShift+Arrow keys: pan the map viewport.-/+: zoom map out or in (outside terminal focus).[/]: resize split;Shift+[/Shift+]: jump split to edge;=: reset split.- Left-drag the divider between map and terminal panes to resize.
Esc: close overlays/dialogs, then deselect.
- Primary config:
~/.config/arcane-agents/config.yaml - Optional override config:
~/.config/arcane-agents/config.local.yaml - State directory:
~/.local/state/arcane-agents/ - SQLite DB:
~/.local/state/arcane-agents/arcane-agents.db
Config is loaded at server startup and merged in this order:
- Built-in defaults
config.yamlconfig.local.yaml
Changes require a server restart.
arcane-agents config path # print config and local override paths
arcane-agents config show # print config.yaml
arcane-agents config edit # open config.yaml in $VISUAL/$EDITORprojects: named working directories (cwd) agents can launch into.runtimes: command presets to run in a project directory.shortcuts: savedproject + runtimecombinations; can also include hotkeys.discovery: optional auto-discovery rules for additional projects.avatars: avatar selection settings (for example disabling specific avatar types from random allocation).status: status detection settings (for example interactive command filtering).audio: client sound settings.backend.tmux: tmux session and status poll settings.server: API bind host/port.
If you want to launch Claude Code in ~/minotaur/taurient and OpenCode in
~/code/personal-assistant, a minimal config looks like this:
projects:
home:
path: "~"
shortName: home
taurient:
path: ~/minotaur/taurient
shortName: taur
personal-assistant:
path: ~/code/personal-assistant
shortName: pa
runtimes:
claude:
command: ["claude"]
label: Claude Code
opencode:
command: ["opencode"]
label: OpenCode
shell:
command: ["bash"]
label: Shell
shortcuts:
- label: Taurient Claude
project: taurient
runtime: claude
hotkeys: ["Ctrl-U"]
- label: PA OpenCode
project: personal-assistant
runtime: opencode
hotkeys: ["Ctrl-A"]
- label: Home Shell
project: home
runtime: shell
hotkeys: ["Ctrl-S"]projects is a map keyed by project id. Each entry defines the working
directory used when launching an agent.
Required fields per project:
path: filesystem path (supports~expansion)shortName: short display slug
Optional fields per project:
label: UI-friendly label
Example:
projects:
app:
path: ~/code/my-app
shortName: app
label: My Appruntimes is a map keyed by runtime id. Each runtime defines the command Arcane
Agents runs inside a selected project directory.
Required fields per runtime:
command: command to execute (string array)label: UI label
Example:
runtimes:
claude:
command: ["claude"]
label: Claude Code
shell:
command: ["bash"]
label: Shellshortcuts is an array of saved launch recipes. Each shortcut combines a
project with a runtime, and can optionally include one or more keyboard
hotkeys.
Required fields per shortcut:
label: button textproject: project id (or uniqueshortName)runtime: runtime id
Optional fields per shortcut:
command: command override for this shortcut onlyhotkeys: array of key chords (for example"Ctrl+1")avatar: pinned avatar type
Example:
shortcuts:
- label: APP
project: app
runtime: claude
hotkeys: ["Ctrl+1"]
- label: Tests
project: app
runtime: shell
command: ["npm", "test", "--", "--watch"]
avatar: elder-wizarddiscovery is an array of rules with:
name(required)type(required):worktrees,directories, orglobpath(required)match(optional)exclude(optional)maxDepth(optional)
Rule behavior:
worktrees: runsgit worktree listfrompath.directories: recursively scans directories frompath.matchchecks for a marker path (for example.git).excludeskips matching directory names.maxDepthcontrols recursion depth.
glob: treatspathas a glob pattern and includes matching directories.
Example:
discovery:
- name: code-projects
type: directories
path: ~/code
match: ".git"
exclude: ["node_modules", ".cache", "dist"]
maxDepth: 2
- name: app-worktrees
type: worktrees
path: ~/code/my-app
- name: playground-glob
type: glob
path: ~/code/playground/*sessionName: tmux session used for managed windows.pollIntervalMs: status poll interval in milliseconds (minimum250).
Example:
backend:
tmux:
sessionName: arcane-agents
pollIntervalMs: 2500Controls how Arcane Agents detects agent activity.
interactiveCommands: programs where terminal output changes are user-driven (scrolling, status bar updates, etc.) and should not triggerworking/idletransitions. Setting this replaces the defaults entirely.extraInteractiveCommands: additional commands to add to the default list without replacing it.
Default interactive commands: nvim, vim, vi, nano, helix, hx,
emacs, emacsclient, less, more, man, htop, btop, top, watch,
lazygit, lazydocker, ranger, nnn, lf, yazi, tmux.
Example — replace defaults entirely:
status:
interactiveCommands:
- nvim
- vim
- my-custom-editorExample — extend defaults with extra commands:
status:
extraInteractiveCommands:
- my-custom-editor
- my-other-toolenableSound: enable or disable in-app voice/sound playback (defaulttrue).
Example:
audio:
enableSound: truedisabled: avatar folder names to exclude from random avatar allocation.- Disabled avatars can still be used when explicitly pinned via
shortcuts[].avatar.
Example:
avatars:
disabled:
- minotaur-strategist
- gothic-witchhost: bind address for the API server.port: bind port for the API server.
Example:
server:
host: 127.0.0.1
port: 7600npm run dev # client + server
npm run dev:server # backend only
npm run dev:client # frontend only
npm run lint
npm run typecheck
npm run test:cinpm run build
npm startDefault runtime URL: http://127.0.0.1:7600
Health checks:
# dev mode (npm run dev)
curl http://127.0.0.1:7601/api/health
# built app (npm start, default config)
curl http://127.0.0.1:7600/api/healthTo log status transitions (for example working -> idle) in the server terminal, set
ARCANE_AGENTS_STATUS_TRACE when launching the backend:
ARCANE_AGENTS_STATUS_TRACE=transitions npm run dev:serverUseful modes:
ARCANE_AGENTS_STATUS_TRACE=off(default)ARCANE_AGENTS_STATUS_TRACE=transitions(only status changes; no output when status stays the same)ARCANE_AGENTS_STATUS_TRACE=verbose(every status evaluation)
If you run full dev mode:
ARCANE_AGENTS_STATUS_TRACE=transitions npm run devStatus debugging APIs:
GET /api/status-debugGET /api/workers/:workerId/status-debugGET /api/workers/:workerId/status-history
- TypeScript (client + server)
- Vite + React (client)
- Express + ws (server)
- xterm.js (embedded terminal)
- node-pty (PTY bridge)
- tmux (session/window process management)
- better-sqlite3 (local persistence)
src/
client/ UI, map renderer, xterm terminal panel
server/ API, orchestration, tmux adapter, status monitor
shared/ Shared types/config models
assets/ Maps, character art
Avatar packs are directory-driven under assets/characters/<avatar-type>/.
- Required sprite files are documented in
assets/characters/README.md. - Optional voice clips are loaded from
assets/characters/<avatar-type>/voice-lines/. - Voice file names: fixed events use
arrive.mp3,attention.mp3,complete.mp3,death.mp3; random events match anymove*.mp3andselected*.mp3clips in the folder. - In app runtime, clips are served from
/api/assets/characters/<avatar-type>/voice-lines/<file>.mp3. - Add a new avatar by dropping in a compliant folder; it becomes available automatically.
- Licensed under MIT.