-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
107 lines (89 loc) · 4.31 KB
/
Dockerfile
File metadata and controls
107 lines (89 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
############################################################
# GranClaw — single-image, single-port test container.
#
# Ships the whole app on ONE port (3001). The backend:
# - serves the built frontend (static files)
# - exposes the REST API
# - proxies /ws/agents/:id WebSocket to internal agent
# processes (which listen on 127.0.0.1 inside the container,
# never exposed to the host).
#
# Build deps (tsc, vite) are used only during the build stage,
# so the runtime image stays small.
############################################################
# ── Stage 1: build frontend + compile backend ─────────────────────────────
FROM node:20-slim AS builder
# Skip Playwright browser downloads — we use system Chromium at runtime.
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
WORKDIR /app
COPY package.json package-lock.json* ./
COPY packages/backend/package.json ./packages/backend/
COPY packages/frontend/package.json ./packages/frontend/
COPY packages/cli/package.json ./packages/cli/
# Full install including dev deps (tsc, vite) for the build.
RUN npm install --no-audit --no-fund
# Copy source and build.
COPY packages ./packages
RUN npm run build
# ── Stage 2: runtime ──────────────────────────────────────────────────────
FROM node:20-slim AS runtime
# OS deps — Chromium powers the agent-browser skill; ffmpeg is required
# by agent-browser's `record` command to encode WebM session recordings.
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
chromium \
fonts-liberation \
libnss3 \
libxss1 \
libasound2 \
libgbm1 \
libxshmfence1 \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*
# agent-browser is the default browser automation binary used by the browser
# tool. Extensions (loaded via GRANCLAW_EXTENSIONS_DIR in downstream images
# like the enterprise edition) can register alternative browser providers
# that swap to a different binary per-turn.
RUN npm install -g --no-audit --no-fund agent-browser \
&& agent-browser --version
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \
CHROME_BIN=/usr/bin/chromium \
AGENT_BROWSER_CHROME_PATH=/usr/bin/chromium
# The `claude` CLI refuses to run with --dangerously-skip-permissions under
# uid 0 for security reasons, so the whole stack runs as the non-root `node`
# user that ships with the official node image.
WORKDIR /app
RUN chown -R node:node /app
# Bring in workspace manifests and install production deps only.
COPY --chown=node:node package.json package-lock.json* ./
COPY --chown=node:node packages/backend/package.json ./packages/backend/
COPY --chown=node:node packages/frontend/package.json ./packages/frontend/
COPY --chown=node:node packages/cli/package.json ./packages/cli/
USER node
RUN npm install --omit=dev --no-audit --no-fund \
&& printf '{}' > /home/node/.claude.json \
&& chmod 600 /home/node/.claude.json
# Copy compiled backend + built frontend + templates from the builder stage.
COPY --chown=node:node --from=builder /app/packages/backend/dist ./packages/backend/dist
COPY --chown=node:node --from=builder /app/packages/frontend/dist ./packages/frontend/dist
COPY --chown=node:node packages/cli/templates ./packages/cli/templates
# Assets (stealth extension) — not emitted by tsc, must be copied explicitly
COPY --chown=node:node packages/backend/assets ./packages/backend/dist/assets
# Runtime config. CONFIG_PATH is pinned so REPO_ROOT resolves to /app
# regardless of where the node process was started from. HOME points to
# the node user's home so claude CLI finds /home/node/.claude/.credentials.json.
# GRANCLAW_STATIC_DIR is pinned to the bundled frontend dist so the static-
# file handler keeps working when GRANCLAW_HOME is mounted somewhere else
# (e.g. /data in enterprise provisioning, where the frontend isn't).
ENV NODE_ENV=production \
PORT=3001 \
HOME=/home/node \
CONFIG_PATH=/app/agents.config.json \
GRANCLAW_STATIC_DIR=/app/packages/frontend/dist
# The only port the container exposes. Agents run internally on 3100+.
EXPOSE 3001
# Graceful shutdown: the backend forwards SIGTERM to agent children.
STOPSIGNAL SIGTERM
CMD ["node", "packages/backend/dist/index.js"]