A self-hosted site-agent: an AI agent that keeps your notes and builds web pages for you, running on your own server in two Docker containers. You tell it "make a page X that looks like this design" and it writes the HTML, publishes it, and hands you back a public URL.
Two containers, no orchestration:
- trip2g — your notes, published as a public HTML site. Open source: github.com/trip2g/trip2g
- hermes — the LLM agent (NousResearch). Its brain is your OpenAI Codex subscription.
On a fresh Ubuntu 22.04/24.04 server (2+ vCPU, 4 GB RAM, root or sudo):
curl -fsSL https://raw.githubusercontent.com/trip2g/hermes_wiki/main/install.sh | shRead the script first — it's meant to be read before you pipe it to sh. It
installs Docker if missing, generates local secrets, loads your codex auth,
brings up both containers, seeds the note vault, and runs three checks.
It will ask for two things (or take them from the environment):
- Your email — your login for the trip2g site.
- Your codex
auth.json— this is the agent's brain. Runcodex loginon your laptop, then copy~/.codex/auth.jsonto the server. Without it hermes runs but cannot think.
Everything else (public IP, port, secrets) is auto-detected or generated.
All inputs can come from env vars:
SERVER_IP=203.0.113.10 \
OWNER_EMAIL=you@example.com \
AUTH_JSON=/root/codex-auth.json \
PORT=8081 \
ASSUME_YES=1 \
sh install.sh| Variable | Default | Meaning |
|---|---|---|
SITE_AGENT_DIR |
/opt/site-agent |
Install directory |
PORT |
8081 |
Public HTTP port |
SERVER_IP |
auto-detected | Public IP |
OWNER_EMAIL |
(prompt) | Your trip2g login |
AUTH_JSON |
~/.codex/auth.json |
Path to your codex auth.json |
MODEL_SLUG |
gpt-5.5 |
Codex model slug |
TELEGRAM_BOT_TOKEN |
(none) | Optional chat interface |
ASSUME_YES |
(off) | Never prompt; fail if a required value is missing |
The script is idempotent — run it again to reuse secrets and fix anything missing.
After install, one-off from the shell:
docker compose -f /opt/site-agent/docker-compose.yml exec hermes \
hermes chat -q "Make a page portfolio: dark background, big gradient heading,
three project cards. Match this vibe: calm, editorial, lots of whitespace."The agent writes _layouts/portfolio.html, publishes it, and replies with
http://<your-ip>:8081/portfolio.
Design-brief demo. Give it a brief (or an image and a description) and a slug:
"Make a page hello_world: dark background #0b0f1a, a large cyan→violet
gradient heading, and one line saying an AI agent runs this site." A few seconds
later http://<your-ip>:8081/hello_world serves exactly that.
For an always-on chat interface, set TELEGRAM_BOT_TOKEN (from @BotFather) and
re-run the installer — then just message your bot ("write this down…",
"make a page…"). Lock it to your own Telegram id with TELEGRAM_ALLOWED_USERS.
Set VOICE=1 and the installer adds a third container — a self-hosted
speech-to-text engine (Speaches,
faster-whisper large-v3, CPU, no GPU, OpenAI-compatible). After that you can
send the bot a Telegram voice message — "сделай страницу про космическое
кафе в тёмном дизайне" — and it transcribes the clip locally, builds the page,
and replies with the link. Nothing leaves the box for transcription.
VOICE=1 \
TELEGRAM_BOT_TOKEN=... \
TELEGRAM_ALLOWED_USERS=<your-telegram-id> \
OWNER_EMAIL=you@example.com \
sh install.shCost of the voice option: about 3 GB (the Speaches image plus the whisper
model, pulled once on first use) and a couple of GB of RAM while it transcribes.
Leave VOICE unset for the lean two-container setup. Pick a lighter/faster model
with STT_MODEL (e.g. deepdml/faster-whisper-large-v3-turbo-ct2).
Owner login to the site (no SMTP needed):
docker compose -f /opt/site-agent/docker-compose.yml exec trip2g /trip2g login-link- A server — a cheap Ubuntu VPS is enough.
- Your codex subscription — the
auth.jsonfromcodex login. This repo ships no keys; you bring your own.
This is the small, personal version. Be clear-eyed about the trade-offs:
- No secret isolation. Your
auth.jsonsits in a Docker volume on the box, and the agent runs on the same box — so the agent can, in principle, read your codex credentials. This is fine for a personal server you own and trust. It is not the sandboxed "the agent never sees the token" model. - Bare HTTP by default. The site serves over plain HTTP until you put TLS in
front of it. For anything public-facing, add a reverse proxy (Caddy is one line
of config) and remove
USER_TOKEN_INSECUREfrom the compose file. - Shared credential. The brain is your own codex subscription. Refreshing/
rotating it on your laptop can invalidate the copy on the server;
codex loginagain fixes it. - The openai SDK patch lives in the container, not the image. Updating the
hermes image reverts it — re-run
install.shafterwards to reapply. hermes chat -qis one-shot. For a persistent interface, use Telegram.- The Codex backend can be flaky. Longer page builds sometimes hit
Broken pipe/ "model provider failed after retries" fromchatgpt.com/backend-api/codex— an intermittent, backend-side issue. If it persists, setMODEL_SLUG=gpt-5.4(orgpt-5.3-codex) and re-run; a shorter model often streams more reliably on the same subscription. - Voice needs headroom. Transcription and the LLM both use the CPU; on a
small box a long clip can bump hermes' 30s transcription timeout. large-v3 is
the most accurate on Russian but the slowest —
STT_MODEL=deepdml/faster-whisper-large-v3-turbo-ct2trades a little accuracy for latency.
If you need the agent to not have access to your real credentials — proxied tokens, egress locks, per-agent scoping, a full control plane — that's a different product (the "box"), not this. hermes_wiki is deliberately the minimal, trust-your-own-server version.
| File | Purpose |
|---|---|
install.sh |
The curl | sh entrypoint. Reads top-to-bottom. Set VOICE=1 for speech-to-text. |
docker-compose.yml |
Reference compose (install.sh generates a filled-in copy). |
skills/create-html-page.md |
The page-building skill seeded into the agent's vault. |
LICENSE |
MIT. |
No secrets are committed here, and none ever should be — see .gitignore.
MIT.