ACPP is a multi-channel proxy for AI coding agents. It bridges agent protocols (ACP subprocess, OpenCode HTTP) to communication channels (Discord, Console, Web UI), providing session management, usage tracking, and persistent logging.
- The discord server is used as a daily driver
- Web is used for checking stats, but the session management part is WIP
- Android app is highly experimental and WIP
- Desktop app is highly experimental and WIP
go install github.com/elek/acpp@latestOr build from source:
go build -o acpp .Start the web UI, scheduler, and — when a Discord token is configured — the Discord bot, all on a shared router:
acpp serveDiscord is enabled automatically when a token is available (--token flag or
discord_token in config); without one, serve runs the web UI alone.
These commands work across all channels (Discord, Console, Web):
| Command | Description |
|---|---|
/start |
Create a new session |
/stop |
Stop the active session |
/status |
Show session info and usage |
/cancel |
Cancel the current operation |
/clear |
Restart session with same config |
/exit |
Shutdown the application |
/modes |
List available agent modes |
/mode <id> |
Switch agent mode |
/pwd |
Show working directory |
/cd <dir> |
Change directory (restarts session) |
/ls [dir] |
List directory contents |
!<cmd> |
Execute a shell command |
- Session: one client may use more sessions.
- Client an ACP client connection. Tight to an ACP session.
- Conversation: a conversation from an agentic loop (ACPSession + usage metadata)
- Project: collection of one or more sessions (usually tight to a single GitHub repo)
- Process: a running ACP agent instance (stdin, stdout)
Config file: ~/.config/acpp/config.yaml (or $XDG_CONFIG_HOME/acpp/config.yaml)
# PostgreSQL connection for session persistence
database:
dsn: "postgres://localhost/acpp?sslmode=disable"
# Discord bot token (alternative to DISCORD_TOKEN env var)
discord_token: "..."
# Web UI listen address
web_addr: ":8080"
# Default session parameters
defaults:
agent: "claude-code-acp"
sandbox: "bwrap.sh"
env_whitelist:
- PATH
- HOME
- ANTHROPIC_API_KEY
# Resolve project directories from channel name
search_path:
- /home/user/projects
# Directory containing sandbox scripts
sandbox_dir: /opt/sandboxes
# Tool permission rules
tool_permissions:
- kind: "execute"
action: "ask" # "ask" or "deny"
contains: ["rm", "sudo"]
# OpenTelemetry OTLP exporter
otlp:
endpoint: "localhost:4317"
tls:
insecure: trueWhen search_path is configured, ACPP maps Discord channel names to project directories automatically. A channel named myproject will use /home/user/projects/myproject if it exists.
A project can run its agent on another machine. On the server, set a shared
secret (this enables the /remote/ws endpoint):
remote:
secret: "..." # or secret_file: ~/.config/acpp/remote.secretOn the other machine, run acpp remote with its own config:
remote:
server: https://acpp.example.com
secret: "..."
location: gpu-box # defaults to the hostnameThen set the project's location to gpu-box on /project/<name> (empty or
localhost runs on the server). The project's dir must be set explicitly, as a
path on that machine. The remote machine resolves the agent command
(agent_path) and builds the sandbox from its own profiles; hooks (worktree,
commit) and !sh commands run there too.
A dropped connection is survived for 5 minutes on both sides without losing
output. Restarting the server does not stop remote agents: the new server adopts
their conversations when the remote agent reconnects (a turn in flight during the
restart is lost). The secret travels in the clear unless the server is behind TLS
(use https://), and the remote agent runs whatever the server asks, so only
connect it to a server you trust over TLS or a private network.
ACPP uses PostgreSQL for session persistence and event logging. Migrations run automatically on startup via goose.
The database is optional — without it, sessions are ephemeral.
- session — tracks agent, directory, status, token usage, cost, and timing
- log — stores all session events (prompts, responses, tool calls) as JSONB
- Prometheus metrics exposed on
:9090by default - OpenTelemetry OTLP export via the
otlpconfig section - Web UI with live WebSocket streaming of session events
See LICENSE for details.
