Discord Fleet

Discord Fleet

A system that runs one Claude Code session per Discord channel inside tmux, fed by a Discord “broker”. Each channel = a worker directory + a tmux session running claude in bypass-permissions mode.

Deployments

Deployment Host Form Notes
viveks-fleet bot-fleet (192.168.70.99) Docker container docker exec viveks-fleet tmux ls
native fleet fleet-22143 (192.168.68.39) systemd (fleet.service) /fleet/tools/fleet-tmux
fleet-container-abe 192.168.39.20 native fleet container host (was bbd-vm02)

How it works

  1. Broker (core/discord-broker.py) connects to Discord (one bot token) and listens on a unix socket (DISCORD_FLEET_SOCKET).
  2. fleet-tmux launch-all starts one tmux session per channel from /fleet/workers/<channel-id>-<slug>/, each running claude --dangerously-load-development-channels server:discord-fleet.
  3. Each worker’s .mcp.json binds a discord-fleet MCP shim (mcp_shim.py) to its channel id(s), which the broker delivers messages through.

Gotchas learned

Warning
  • Bypass permissions: newer Claude Code (2.1.x) added an “Auto mode” that shifted the shift-tab cycle, and a one-time “accept bypass mode” prompt. Fleet workers must reach ⏵⏵ bypass permissions on — set bypassPermissionsModeAccepted and use --dangerously-skip-permissions, or accept once interactively.
  • MCP shim needs enableAllProjectMcpServers + enabledMcpjsonServers in the worker’s .claude/settings.local.json, and the venv needs mcp==1.27.2 (latest breaks Server.list_tools).
  • Per-UID egress firewall on fleet-22143 jails the fleet user (uid 1500) to specific LAN ranges via iptables owner-match (fleet-lan-block.service).

Fleet infra repo

vkirub/fleet-container — the container/tooling for fleet hosts: bin/ commands (flc install-required, flc update --name <fleet>, flc status, flc connect), a shared base/ image, and per-fleet compose under fleets/<name>/.

See also