-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add Hermes Agent on Fly.io guide to blueprints #2388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
582374b
Add Hermes Agent on Fly.io guide to blueprints
a357477
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson f623fce
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson db41e46
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson 963960a
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson e7f16eb
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson 506d443
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson c0b2c64
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson a358d1d
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson 65aa637
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson e4447ec
Update blueprints/hermes-agent-on-fly-io.html.md
theoctopusperson 57c5528
Shorten --app to -a; add header image
theoctopusperson 3f15b05
Apply suggestion from @kcmartin
kcmartin 05f6df8
Apply suggestion from @kcmartin
kcmartin 99fa7a7
Apply suggestion from @kcmartin
kcmartin d68754e
Change we to you for consistency
kcmartin fc8579f
change we to you to match the rest of the guide
kcmartin 9d67eb9
fix image filename and change docs links to relative
kcmartin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,209 @@ | ||
| --- | ||
| title: Run Hermes Agent on Fly.io | ||
| layout: docs | ||
| nav: guides | ||
| date: 2026-05-04 | ||
| --- | ||
|
|
||
| <figure> | ||
| <img src="/static/images/Hermes_Agent.png" alt="Illustration by Annie Ruygt of the Greek god Hermes mid-flight, depicted on a black-figure pottery bowl framed by olive branches" class="w-full max-w-lg mx-auto"> | ||
| </figure> | ||
|
|
||
| [Hermes](https://github.com/NousResearch/hermes-agent) is an AI agent from Nous Research with a built-in learning loop: it watches its own output, notices when it had to improvise to finish a task, and writes that experience back as a reusable skill it can call next time. The skill library grows with use, so Hermes works best when it runs continuously on a persistent host rather than a short-lived sandbox, which is exactly what a Fly Machine with an attached volume gives you. | ||
|
|
||
| This guide walks you through running Hermes on a Fly Machine, configuring it, and reaching its web dashboard from your laptop. | ||
|
|
||
| You'll need **[flyctl](/docs/flyctl/install/)** installed, a **Fly.io account** ([free trial](/docs/about/free-trial/) works), and an **LLM API key** (Anthropic, OpenAI, Google Gemini, or [OpenRouter](https://openrouter.ai/) for access to 200+ models). | ||
|
|
||
| You'll use Nous Research's **official prebuilt image** (`nousresearch/hermes-agent:latest`) so there's no Dockerfile to maintain and no remote builder to wait on. Fly pulls the image straight from Docker Hub. | ||
|
|
||
| ## Create the app and volume | ||
|
|
||
| Hermes keeps all its state in `/opt/data` inside the container. That includes config, API keys, sessions, skills, and memories. You'll back that with a Fly volume so it persists across deploys and restarts. | ||
|
|
||
| Pick an app name (must be globally unique on Fly) and a [region](/docs/reference/regions/) close to you, then: | ||
|
|
||
| ```bash | ||
| fly apps create <your-hermes-app> | ||
| fly volumes create data -a <your-hermes-app> --region <region> --size 3 | ||
| ``` | ||
|
|
||
| 3 GB is comfortable headroom for sessions and the bundled skills directory. | ||
|
|
||
| ## Write fly.toml | ||
|
|
||
| Create a directory for the deployment config and drop a `fly.toml` in it: | ||
|
|
||
| ```toml | ||
| app = "<your-hermes-app>" | ||
| primary_region = "<region>" | ||
|
|
||
| [build] | ||
| image = "nousresearch/hermes-agent:latest" | ||
|
|
||
| [processes] | ||
| app = "gateway run" | ||
|
|
||
| [[mounts]] | ||
| source = "data" | ||
| destination = "/opt/data" | ||
|
|
||
| [[vm]] | ||
| memory = "4gb" | ||
| cpus = 2 | ||
| ``` | ||
|
|
||
| A few notes: | ||
|
|
||
| - **No `[build.dockerfile]`.** Fly pulls the image directly. Deploys take seconds, not minutes. | ||
| - **`[processes] app = "gateway run"`** defines the single process group for this app, and its command is passed to the image's entrypoint, so the Machine boots into `hermes gateway run` (the messaging gateway for Telegram, Discord, Slack, WhatsApp, etc.). | ||
| - **No `[[services]]` block.** The gateway talks *outbound* to chat platforms, so you don't need a public port. The dashboard exposes API keys and shouldn't be public; you'll reach it through a Fly proxy tunnel below. | ||
| - **4 GB / 2 CPU** is the recommended size when browser tools (Playwright/Chromium) are active. If you don't use browser tools you can drop to `shared-cpu-1x` and 1–2 GB. | ||
|
|
||
| ## Deploy | ||
|
|
||
| ```bash | ||
| fly deploy -a <your-hermes-app> --ha=false | ||
| ``` | ||
|
|
||
| `--ha=false` keeps it to a single machine; Hermes is stateful and you don't want two gateway processes writing to the same volume. | ||
|
|
||
| When the deploy finishes, the machine boots, the entrypoint bootstraps `/opt/data` (creating `.env`, `config.yaml`, `SOUL.md`, `sessions/`, `skills/`, etc.), and `hermes gateway run` starts. It'll keep running but it has no API key yet, so it can't talk to a model. | ||
|
|
||
| Confirm it's alive: | ||
|
|
||
| ```bash | ||
| fly logs -a <your-hermes-app> | ||
| ``` | ||
|
|
||
| You should see the bundled skills sync, then the gateway starting up. | ||
|
|
||
| ## Configure Hermes | ||
|
|
||
| SSH into the machine. The `hermes` binary lives at `/opt/hermes/.venv/bin/hermes` inside the image, but `fly ssh console` opens a login shell that resets PATH and won't find it there. Add a symlink into `/usr/local/bin` (which is always on PATH) so `hermes` works as a bare command: | ||
|
|
||
| ```bash | ||
| fly ssh console -a <your-hermes-app> -C \ | ||
| "ln -sf /opt/hermes/.venv/bin/hermes /usr/local/bin/hermes" | ||
| ``` | ||
|
|
||
| Then open a shell on the machine and run the setup wizard: | ||
|
|
||
| ```bash | ||
| fly ssh console -a <your-hermes-app> | ||
| hermes setup | ||
| ``` | ||
|
|
||
| The wizard walks you through model selection, tool configuration, and connecting your messaging platforms. When it's done, exit the SSH session. | ||
|
|
||
| Restart the machine so the gateway picks up the new config: | ||
|
|
||
| ```bash | ||
| fly machine restart <machine-id> -a <your-hermes-app> | ||
| ``` | ||
|
|
||
| Get `<machine-id>` from `fly machine list -a <your-hermes-app>`. | ||
|
|
||
| ## Web dashboard | ||
|
|
||
| Hermes has a web dashboard on port 9119 for managing sessions, skills, and config. The dashboard reads your API keys, so the upstream guidance is to never expose it on a public port. Tunnel to it instead: | ||
|
|
||
| In one terminal, start the dashboard inside the machine: | ||
|
|
||
| ```bash | ||
| fly ssh console -a <your-hermes-app> -C \ | ||
| "hermes dashboard --host 0.0.0.0 --no-open" | ||
| ``` | ||
|
|
||
| In a second terminal, open a Fly proxy from your laptop: | ||
|
|
||
| ```bash | ||
| fly proxy 9119:9119 -a <your-hermes-app> | ||
| ``` | ||
|
|
||
| Now visit `http://localhost:9119` in your browser. Traffic goes over your authenticated WireGuard tunnel; the dashboard isn't published to the public internet, though it is reachable from other Machines on your organization's [private network](/docs/networking/private-networking/) | ||
|
|
||
| When you're done, `Ctrl+C` both commands. The gateway keeps running on the machine. | ||
|
|
||
| ## Upgrading | ||
|
|
||
| The image is stateless; your data lives on the volume. To pull the latest Hermes: | ||
|
|
||
| ```bash | ||
| fly deploy -a <your-hermes-app> | ||
| fly ssh console -a <your-hermes-app> -C \ | ||
| "ln -sf /opt/hermes/.venv/bin/hermes /usr/local/bin/hermes" | ||
| ``` | ||
|
|
||
| The deploy pulls `nousresearch/hermes-agent:latest` again. The second command re-creates the `/usr/local/bin/hermes` symlink; it lives on the container's filesystem, not the data volume, so each new container starts without it. | ||
|
|
||
| ## VM sizing | ||
|
|
||
| If you're running heavy tool use or multiple concurrent sessions, scale up: | ||
|
|
||
| ```bash | ||
| fly scale memory 8192 -a <your-hermes-app> | ||
| fly scale vm shared-cpu-4x -a <your-hermes-app> | ||
| ``` | ||
|
|
||
| ## Useful commands | ||
|
|
||
| | Command | Description | | ||
| |---------|-------------| | ||
| | `fly logs -a <your-hermes-app>` | Stream live logs | | ||
| | `fly ssh console -a <your-hermes-app>` | SSH into the machine | | ||
| | `fly ssh console -a <your-hermes-app> -C "hermes doctor"` | Health check | | ||
| | `fly machine restart <id> -a <your-hermes-app>` | Restart after config changes | | ||
| | `fly status -a <your-hermes-app>` | Check machine status | | ||
| | `fly volumes list -a <your-hermes-app>` | List attached volumes | | ||
| | `fly ssh console -a <your-hermes-app> -C "hermes skills list"` | List learned skills | | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| **Gateway won't start** | ||
|
|
||
| Check `hermes doctor` for missing API keys or other diagnostics: | ||
|
|
||
| ```bash | ||
| fly ssh console -a <your-hermes-app> -C "hermes doctor" | ||
| ``` | ||
|
|
||
| **Out of memory** | ||
|
|
||
| Increase RAM: | ||
|
|
||
| ```bash | ||
| fly scale memory 8192 -a <your-hermes-app> | ||
| ``` | ||
|
|
||
| **Need to start fresh** | ||
|
|
||
| Wipe the config files (skills, sessions, and memories survive): | ||
|
|
||
| ```bash | ||
| fly ssh console -a <your-hermes-app> -C \ | ||
| "sh -c 'rm -f /opt/data/config.yaml /opt/data/.env'" | ||
| fly machine restart <machine-id> -a <your-hermes-app> | ||
| fly ssh console -a <your-hermes-app> | ||
| hermes setup | ||
| ``` | ||
|
|
||
| To wipe everything including conversations, destroy and recreate the volume: | ||
|
|
||
| ```bash | ||
| fly machine stop <machine-id> -a <your-hermes-app> | ||
| fly volumes destroy <volume-id> -a <your-hermes-app> | ||
| fly volumes create data -a <your-hermes-app> --region <region> --size 3 | ||
| fly machine start <machine-id> -a <your-hermes-app> | ||
| ``` | ||
|
|
||
| **Skills behaving unexpectedly** | ||
|
|
||
| List, view, and delete: | ||
|
|
||
| ```bash | ||
| fly ssh console -a <your-hermes-app> | ||
| hermes skills list | ||
| hermes skills view <skill-name> | ||
| hermes skills delete <skill-name> | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.