1
0
Fork
You've already forked hermes-deployment
0
No description
  • Makefile 62.8%
  • Shell 25%
  • Dockerfile 9.1%
  • HTML 3.1%
Daniel Snider eeb495d83c feat(hermes): run our own fork image; retire boot patches; add hermes-update
Switch the daemon image from upstream nousresearch/hermes-agent:latest to our own ghcr.io/dephekt/hermes-agent:latest, built from the dephekt/hermes-agent fork (public GHCR, amd64). All three deploy-local boot patches (opencode-go Kimi reasoning, MCP refresh-token retention, camofox VNC URL) are now baked into that image, so delete them; the patches/ dir keeps a README documenting the mechanism for future experiments.
Add a hermes-update target: sync-secrets then `up -d --pull always --force-recreate --no-deps hermes` — the steady-state path after the fork publishes a new image. The cont-init patch loop is retained and no-ops on the now-empty patches/.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026年06月11日 01:34:44 -05:00
hermes feat(hermes): run our own fork image; retire boot patches; add hermes-update 2026年06月11日 01:34:44 -05:00
openwebui feat(openwebui): add upsun-pc and personal-pc agents to the model list 2026年06月08日 18:42:14 -05:00
.gitignore chore(hermes): track deployment-local code patches in git 2026年06月07日 18:22:42 -05:00
config.env feat: initial hermes + openwebui deployment 2026年05月13日 01:10:30 -05:00
Makefile feat(hermes): run our own fork image; retire boot patches; add hermes-update 2026年06月11日 01:34:44 -05:00
Makefile.include feat: initial hermes + openwebui deployment 2026年05月13日 01:10:30 -05:00
README.md chore(hermes): add hermes-recreate make target for config/patch/env changes 2026年06月11日 00:53:37 -05:00

hermes-deployment

Home-server deployment of Hermes Agent + OpenWebUI. Two Docker Compose stacks on containers.home.arpa, sharing the proxy external network alongside the media stack at ~/docker/.

Why a separate repo from ~/docker/

The agent stack has its own lifecycle, secret set, change cadence, and reviewer pool. Putting it next to media/, immich/, etc. would conflate two unrelated infrastructures. Cost of separation is near-zero because both repos share the same Makefile pattern and the same Docker host.

Topology

containers.home.arpa (Docker host)
 │
 ├── ~/docker/ ← media stack (Jellyfin, Keycloak, Newt, etc.)
 │ core/newt ← scans Docker labels on this host, registers with Pangolin
 │
 └── ~/hermes-deployment/ ← this repo (synced here by `make sync-secrets`)
 hermes/ ← Hermes Agent daemon + runner containers
 openwebui/ ← OpenWebUI, public at ai.dephekt.net
Pangolin edge VPS (~/docker/pangolin/ on a separate VPS)
 ← Newt registers labels from ALL containers on containers.home.arpa
 ← TLS termination for ai.dephekt.net → openwebui:8080
Discord cloud ←─ outbound WebSockets ─── hermes container
 (two bots: upsun + personal profiles, s6-supervised)
Browser ─HTTPS─→ ai.dephekt.net (Pangolin) ─WireGuard→ openwebui:8080
openwebui ─────→ http://hermes:8642/v1 (upsun profile's API server)
hermes ─────────→ docker.sock → ONE hermes-runner container per profile
 (shared by that profile's sessions; isolated sandboxes)

Newt in ~/docker/core/ picks up Pangolin labels from any container on the host regardless of which compose project owns it. The openwebui service has labels for ai.dephekt.net; the hermes service has none (API stays internal).

Stacks

Stack Service(s) Exposed
hermes hermes daemon Internal only (proxy network)
openwebui openwebui ai.dephekt.net via Pangolin

Quick bring-up

# 1. Populate secrets from 1Password (writes per-profile .env files)
make inject-secrets
# 2. Rsync everything to containers.home.arpa
make sync-secrets
# 3. Start stacks
make hermes-up
make openwebui-up
# 4. Install the agent as the 'upsun' profile from the distribution repo
# (in-container; uses /opt/data/.netrc for lab.plat.farm auth)
docker exec -it hermes hermes profile install \
 https://lab.plat.farm/dephekt/hermes-upsun.git --name upsun --yes
# 5. One-time OAuth for the profile (Anthropic + Linear + Guru) — paste the
# redirect URL back at the prompt; see hermes/README.md
docker exec -it hermes hermes -p upsun setup
docker exec -it hermes hermes -p upsun mcp add linear --url https://mcp.linear.app/mcp --auth oauth
docker exec -it hermes hermes -p upsun mcp add guru --url https://mcp.api.getguru.com/mcp --auth oauth
# 6. Start the profile gateway (s6-supervised; survives docker restart)
docker exec hermes hermes -p upsun gateway start
# 7. OpenWebUI first login: visit https://ai.dephekt.net → Sign in with Keycloak

See hermes/README.md for the full step-by-step including Discord bot setup, secret rotation cadence, backup notes, and the Docker socket risk callout.

Shipping agent updates (bundle → distribution → profiles)

SOUL.md, skills, and config defaults live in the hermes-upsun profile distribution (lab.plat.farm/dephekt/hermes-upsun), rendered from the upsun-development-agent bundle. To ship a change:

# In ~/upsun/dephekt/hermes-upsun/ after a bundle git pull:
make render # re-render SOUL.md + skills/ from the bundle
git commit -am "..." && git tag vX.Y.Z && git push --tags
# On any machine running the agent (incl. this deployment):
docker exec hermes hermes profile update upsun --yes
docker exec hermes hermes -p upsun gateway restart

Secrets/env changes still flow through this repo:

make inject-secrets && make sync-secrets && make hermes-recreate
  • Profile distribution (SOUL, skills, config): lab.plat.farm/dephekt/hermes-upsun
  • Bundle / conventions / skills source: gitlab.com/dephekt/upsun-development-agent
  • Runner image (terminal backend): codeberg.org/stackdrift-images/hermes-runner
  • Pangolin config (edge VPS): ~/docker/ in this machine's sibling checkout

Directory layout

.
├── Makefile STACKS, inject-secrets, hermes-render-profiles, sync-secrets
├── Makefile.include Copied verbatim from ~/docker/; provides up/down/restart/logs targets
├── config.env Shared DOMAIN, TZ
├── .gitignore **/secrets/, hermes/config/, openwebui/openwebui-data/
├── hermes/
│ ├── docker-compose.yml
│ ├── config.env Non-secret daemon env (author, PyPI groups, etc.)
│ ├── cont-init-secrets.sh s6 cont-init hook: signing key + GITLAB_TOKEN
│ │ into /run/s6/container_environment
│ ├── secrets/ gitignored; hermes.env + profile-*.env from inject-secrets
│ ├── config/ gitignored; bind-mounted to /opt/data in the container
│ │ (profiles/<name>/.env placed by hermes-render-profiles;
│ │ SOUL.md/skills/config.yaml come from the distribution)
│ └── README.md
└── openwebui/
 ├── docker-compose.yml
 ├── config.env
 ├── secrets/ gitignored; OPENAI_API_KEY.env, OAUTH_CLIENT_SECRET.env
 ├── openwebui-data/ gitignored; runtime bind mount
 └── README.md