Files
paperclip/Dockerfile
T
Chris Farhood 002c470ee7 fix(docker): install gh via direct binary instead of keyring/apt
The GitHub CLI keyring approach requires a hardcoded SHA256 checksum
that drifts as the keyring file is updated upstream, causing build
failures. Replace with direct binary tarball download which is simpler
and has no checksum drift issue.

Also removed wget (only needed for keyring download).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 17:17:55 -04:00

91 lines
3.7 KiB
Docker

FROM node:lts-trixie-slim AS base
ARG USER_UID=1000
ARG USER_GID=1000
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl git jq nano procps python3 python3-pip vim \
&& rm -rf /var/lib/apt/lists/* \
&& curl -fsSL https://github.com/cli/cli/releases/download/v2.89.0/gh_2.89.0_linux_amd64.tar.gz | tar -xzf - -C /tmp \
&& mv /tmp/gh_2.89.0_linux_amd64/bin/gh /usr/local/bin/ \
&& rm -rf /tmp/gh_* \
&& curl -fsSL "https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/$(dpkg --print-architecture)/kubectl" \
-o /usr/local/bin/kubectl \
&& chmod +x /usr/local/bin/kubectl \
&& curl -LsSf https://astral.sh/uv/install.sh | sh \
&& mv /root/.local/bin/uv /usr/local/bin/uv \
&& mv /root/.local/bin/uvx /usr/local/bin/uvx \
&& curl -fsSL "https://github.com/bitnami-labs/sealed-secrets/releases/latest/download/kubeseal-$(uname -s | tr '[:upper:]' '[:lower:]')-$(dpkg --print-architecture)" \
-o /usr/local/bin/kubeseal \
&& chmod +x /usr/local/bin/kubeseal
# Modify the existing node user/group to have the specified UID/GID to match host user
RUN usermod -u $USER_UID --non-unique node \
&& groupmod -g $USER_GID --non-unique node \
&& usermod -g $USER_GID -d /paperclip node
RUN corepack enable
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml* .npmrc ./
COPY cli/package.json cli/
COPY server/package.json server/
COPY ui/package.json ui/
COPY packages/shared/package.json packages/shared/
COPY packages/db/package.json packages/db/
COPY packages/adapter-utils/package.json packages/adapter-utils/
COPY packages/mcp-server/package.json packages/mcp-server/
COPY packages/adapters/claude-local/package.json packages/adapters/claude-local/
COPY packages/adapters/codex-local/package.json packages/adapters/codex-local/
COPY packages/adapters/cursor-local/package.json packages/adapters/cursor-local/
COPY packages/adapters/gemini-local/package.json packages/adapters/gemini-local/
COPY packages/adapters/openclaw-gateway/package.json packages/adapters/openclaw-gateway/
COPY packages/adapters/opencode-local/package.json packages/adapters/opencode-local/
COPY packages/adapters/pi-local/package.json packages/adapters/pi-local/
COPY packages/plugins/sdk/package.json packages/plugins/sdk/
COPY patches/ patches/
RUN pnpm install --no-frozen-lockfile
FROM base AS build
WORKDIR /app
COPY --from=deps /app /app
COPY . .
RUN pnpm --filter @paperclipai/ui build
RUN pnpm --filter @paperclipai/plugin-sdk build
RUN pnpm --filter @paperclipai/server build
RUN test -f server/dist/index.js || (echo "ERROR: server build output missing" && exit 1)
FROM base AS production
ARG USER_UID=1000
ARG USER_GID=1000
WORKDIR /app
COPY --chown=node:node --from=build /app /app
RUN npm install --global --omit=dev @anthropic-ai/claude-code@latest @openai/codex@latest opencode-ai @google/gemini-cli \
&& mkdir -p /paperclip/.config/opencode \
&& cd /paperclip/.config/opencode \
&& npm install @ai-sdk/anthropic \
&& chown -R node:node /paperclip
COPY scripts/docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENV NODE_ENV=production \
HOME=/paperclip \
HOST=0.0.0.0 \
PORT=3100 \
SERVE_UI=true \
PAPERCLIP_HOME=/paperclip \
PAPERCLIP_INSTANCE_ID=default \
USER_UID=${USER_UID} \
USER_GID=${USER_GID} \
PAPERCLIP_CONFIG=/paperclip/instances/default/config.json \
PAPERCLIP_DEPLOYMENT_MODE=authenticated \
PAPERCLIP_DEPLOYMENT_EXPOSURE=private \
OPENCODE_ALLOW_ALL_MODELS=true
VOLUME ["/paperclip"]
EXPOSE 3100
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node", "--import", "./server/node_modules/tsx/dist/loader.mjs", "server/dist/index.js"]