Operations
Logs (bridge mode)
Section titled “Logs (bridge mode)”The bridge logs to the container output: login, one line per finished turn (thread ID, steps, cost) and errors. Use docker compose logs -f or Portainer’s Logs. Permission prompts appear as buttons in the Discord thread, so there is nothing to attach to. !stop in a thread interrupts its running turn.
Attaching to the Claude session (plugin mode)
Section titled “Attaching to the Claude session (plugin mode)”The container keeps a TTY open so you can see Claude’s terminal and answer permission prompts.
- Docker:
docker attach claude-discord. Detach with Ctrl-P Ctrl-Q (Ctrl-C would stop Claude and the container). - Portainer: Containers → claude-discord → Console → Attach.
From the terminal you can also run slash commands such as /discord:access to manage pairing when DISCORD_ALLOWED_USERS is empty.
Restarting
Section titled “Restarting”docker compose restartBridge mode: running turns are interrupted; each thread resumes its session on the next message. Plugin mode: with CLAUDE_CONTINUE=true the new session continues the previous conversation. Set it to false to start fresh. Changes to DISCORD_* variables take effect on restart because access.json is rebuilt from env.
Updating Claude Code
Section titled “Updating Claude Code”The version is pinned and the auto-updater is off. To update:
- Change
CLAUDE_CODE_VERSIONin theDockerfile(or pass--build-arg), and the matching@anthropic-ai/claude-agent-sdkversion inbridge/package.json(cd bridge && npm install @anthropic-ai/claude-agent-sdk@<version>). - Rebuild:
docker compose up -d --build, or, for Portainer, recreateclaude-discord-build.tarand build the image again, then Recreate the container (pull disabled).
Installing extra tools
Section titled “Installing extra tools”The node user has passwordless sudo, so the bot (or you, in the console) can run sudo apt-get install <package>. Packages installed this way are lost when the container is recreated. Anything needed permanently belongs in the Dockerfile.
Where data lives
Section titled “Where data lives”| Path | Volume | Survives recreate |
|---|---|---|
/home/node/.claude |
claude-home |
yes |
/workspace |
./workspace or claude-workspace |
yes |
everything else (apt packages, /tmp) |
none | no |
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause |
|---|---|
Container exits with DISCORD_BOT_TOKEN is required |
The variable is missing from .env / stack.env. |
Exits with Set CLAUDE_CODE_OAUTH_TOKEN (recommended) or ANTHROPIC_API_KEY |
No Claude credentials provided. |
| Bot is online but ignores messages | Not @mentioned while DISCORD_REQUIRE_MENTION=true; user not in the allow list; channel ID missing from DISCORD_CHANNELS; Message Content Intent disabled. |
git push fails with authentication errors |
GH_TOKEN unset, expired, or not granted the repository. |
Permission denied writing /workspace (Compose) |
The host folder is not owned by UID 1000. |
| Claude seems stuck | Bridge: look for Allow/Deny buttons in the thread, or send !stop. Plugin: it may be waiting on a permission prompt; attach and answer it. |
Bridge exits with DISCORD_CHANNELS must list at least one channel ID |
Bridge mode needs DISCORD_CHANNELS and DISCORD_ALLOWED_USERS. |
| A thread stays on ⏳ | All BRIDGE_MAX_CONCURRENT slots are busy; it starts when another turn finishes. |
Not logged in in a thread |
The Claude token is missing or expired; check CLAUDE_CODE_OAUTH_TOKEN / ANTHROPIC_API_KEY. |