Skip to content

Docker image

The image is built from a two-stage Dockerfile.

Stage Base Purpose
bun oven/bun:1.2 Only used to copy the bun binary out.
bridge node:22-bookworm-slim Builds bridge/ (TypeScript → dist/) and drops dev and optional dependencies. Copied to /opt/bridge.
final node:22-bookworm-slim Runtime: Node 22 for Claude Code and the bridge, Bun for the Discord plugin.

Bun is needed because the Discord channel plugin’s MCP server runs on Bun. It is copied to /usr/local/bin/bun.

Argument Default Meaning
CLAUDE_CODE_VERSION 2.1.322 Version of @anthropic-ai/claude-code installed globally with npm.

The version is pinned so rebuilding the image is reproducible. Keep it in step with @anthropic-ai/claude-agent-sdk in bridge/package.json (SDK 0.3.N goes with Claude Code 2.1.N): the bridge runs the globally installed claude, and the SDK’s own bundled binaries are left out of the image to save about 650 MB. Auto-update is turned off at runtime (DISABLE_AUTOUPDATER=1); to upgrade, rebuild with a new value:

Terminal window
docker build --build-arg CLAUDE_CODE_VERSION=<new version> -t claude-discord:latest .

Installed with apt-get (no recommends), then the apt lists are deleted to keep the image small.

Group Packages
Core git, ca-certificates, curl, tini, jq, ripgrep
Admin sudo, procps, less, nano, file
Media ffmpeg
Python python3, python3-pip, python3-venv
Build build-essential
Archives / download wget, unzip, zip, xz-utils
Remote openssh-client
GitHub gh (GitHub CLI, from the official cli.github.com apt repository, verified with its keyring)

tini is PID 1 so signals are forwarded and zombie processes are reaped. jq is used by the entrypoint to edit JSON config. ripgrep is used by Claude Code for code search.

  • The container runs as the non-root user node (UID 1000 in the Node base image). Claude Code refuses bypassPermissions mode when running as root, so a non-root user is required.
  • node has passwordless sudo (/etc/sudoers.d/node, mode 0440) so the bot can install extra packages with sudo apt-get install. See Security before relying on this.
  • /workspace and /home/node/.claude are created and owned by node.
Setting Value
WORKDIR /workspace
DISABLE_AUTOUPDATER 1
CLAUDE_CONFIG_DIR /home/node/.claude
ENTRYPOINT /usr/bin/tini -- /usr/local/bin/entrypoint.sh

The entrypoint script is described in Entrypoint.

With Docker:

Terminal window
docker build -t claude-discord:latest .

For Portainer, the build context is shipped as claude-discord-build.tar (it contains Dockerfile, entrypoint.sh and the bridge sources). To recreate it after editing any of them:

Terminal window
tar cf claude-discord-build.tar --exclude=node_modules --exclude=dist Dockerfile entrypoint.sh bridge

Then upload it as described in Deployment.