From 37bf43c3ea1fddfa4db93591eba8050eea25333f Mon Sep 17 00:00:00 2001 From: Hermes Date: Mon, 18 May 2026 18:37:31 -0400 Subject: [PATCH] feat: add custom Dockerfile with Hermes adapter baked in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Creates ai/paperclip/ with: - Dockerfile: extends upstream paperclip image, pre-installs hermes-paperclip-adapter@0.3.0 npm package as seed data - docker-entrypoint.sh: seeds the adapter plugin on first boot if the persistent volume is empty, then runs original startup This ensures the Hermes adapter is available on first boot without requiring network access — no npm install needed at runtime. The adapter persists on the Docker volume across restarts. --- ai/compose.yml | 3 +- ai/paperclip/Dockerfile | 47 +++++++++++++++++++++++++++++++ ai/paperclip/docker-entrypoint.sh | 35 +++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 ai/paperclip/Dockerfile create mode 100644 ai/paperclip/docker-entrypoint.sh diff --git a/ai/compose.yml b/ai/compose.yml index 004a5c9..003b3d4 100644 --- a/ai/compose.yml +++ b/ai/compose.yml @@ -115,7 +115,8 @@ services: - ai_backend paperclip: - image: ghcr.io/paperclipai/paperclip:v2026.517.0 + build: + context: ./paperclip container_name: paperclip restart: always ports: diff --git a/ai/paperclip/Dockerfile b/ai/paperclip/Dockerfile new file mode 100644 index 0000000..a40c91a --- /dev/null +++ b/ai/paperclip/Dockerfile @@ -0,0 +1,47 @@ +# syntax=docker/dockerfile:1.20 +FROM ghcr.io/paperclipai/paperclip:v2026.517.0 + +# ── Install Hermes adapter npm package into seed directory ────────── +# This seed data gets copied to the persistent volume on first boot +# so the adapter is available without network access. +USER root + +RUN npm install --no-save --prefix /opt/paperclip-seed/adapter-plugins \ + hermes-paperclip-adapter@0.3.0 + +# Create adapter-plugins.json metadata (Paperclip reads this on startup +# to discover which external adapters to load) +RUN mkdir -p /opt/paperclip-seed && python3 -c " +import json +record = { + 'packageName': 'hermes-paperclip-adapter', + 'version': '0.3.0', + 'type': 'hermes', + 'installedAt': '2026-05-18T00:00:00.000Z', +} +with open('/opt/paperclip-seed/adapter-plugins.json', 'w') as f: + json.dump([record], f, indent=2) +" + +# Ensure the adapter-plugins dir has a package.json (Paperclip expects one) +RUN python3 -c " +import json +pkg = { + 'name': 'paperclip-adapter-plugins', + 'version': '0.0.0', + 'private': True, + 'description': 'Managed directory for Paperclip external adapter plugins.', +} +with open('/opt/paperclip-seed/adapter-plugins/package.json', 'w') as f: + json.dump(pkg, f, indent=2) +" + +# ── Custom entrypoint ────────────────────────────────────────────── +# Seeds the Hermes adapter on fresh volumes, then runs original logic. +COPY docker-entrypoint.sh /usr/local/bin/paperclip-entrypoint.sh +RUN chmod +x /usr/local/bin/paperclip-entrypoint.sh + +USER node + +ENTRYPOINT ["/usr/local/bin/paperclip-entrypoint.sh"] +CMD ["node", "--import", "./server/node_modules/tsx/dist/loader.mjs", "server/dist/index.js"] diff --git a/ai/paperclip/docker-entrypoint.sh b/ai/paperclip/docker-entrypoint.sh new file mode 100644 index 0000000..28f561a --- /dev/null +++ b/ai/paperclip/docker-entrypoint.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -e + +# ── Seed Hermes adapter if volume is fresh ────────────────────────── +PAPERCLIP_HOME="${PAPERCLIP_HOME:-/paperclip}" +if [ ! -f "${PAPERCLIP_HOME}/adapter-plugins.json" ]; then + echo "[paperclip] Seeding Hermes adapter plugin..." + cp -r /opt/paperclip-seed/* "${PAPERCLIP_HOME}/" + chown -R "${USER_UID:-1000}:${USER_GID:-1000}" \ + "${PAPERCLIP_HOME}/adapter-plugins" \ + "${PAPERCLIP_HOME}/adapter-plugins.json" + echo "[paperclip] Hermes adapter seeded. Ready to create Hermes agents." +fi + +# ── Original entrypoint logic (UID/GID adjustment) ────────────────── +PUID="${USER_UID:-1000}" +PGID="${USER_GID:-1000}" +changed=0 + +if [ "$(id -u node)" -ne "$PUID" ]; then + usermod -o -u "$PUID" node + changed=1 +fi + +if [ "$(id -g node)" -ne "$PGID" ]; then + groupmod -o -g "$PGID" node + usermod -g "$PGID" node + changed=1 +fi + +if [ "$changed" = "1" ]; then + chown -R node:node "${PAPERCLIP_HOME}" +fi + +exec gosu node "$@"