Start Hermes Agent Stack (macOS)
Bring up local agent infra end-to-end on macOS (tested on Apple Silicon, Darwin 25.x):
- Ollama runtime (port 11434) — model server
- hermes3:8b model loaded + warmed in RAM
- Hermes web dashboard UI (port 9119)
- Optional: Hermes gateway (Telegram/Slack/WhatsApp)
Print final URL at end. All local. No API key. $0 cost.
Prerequisites (must already be installed)
This skill BOOTS the stack — it does not install it. Required:
- Ollama —
/Applications/Ollama.apporbrew install ollama(provides/opt/homebrew/bin/ollamaon Apple Silicon,/usr/local/bin/ollamaon Intel) - Hermes Agent — installed to
~/.hermes/hermes-agent/withhermesCLI on PATH at~/.local/bin/hermes. Official install (does both Python 3.11 viauvAND Node 22 LTS to~/.hermes/node/):
Thencurl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bashpip install hermes-agent[web](oruv pip install -e ".[all,dev]"from source) for the dashboard. - Node 22 — bundled at
~/.hermes/node/by the official installer. Only need standalonefnmif you skipped the installer. - ~5 GB free disk for
hermes3:8b
If any are missing, the skill reports the gap and stops — do NOT attempt to install Ollama or other system tooling unless the user explicitly authorizes.
Current upstream version: v0.15.0 (May 16, 2026) — repo: https://github.com/NousResearch/hermes-agent
Install gotchas learned the hard way (macOS, no Homebrew)
These are the failure modes encountered during a fresh bootstrap on an Apple Silicon Mac WITHOUT Homebrew. The official installer mostly works, but expect:
- Optional brew packages skip gracefully. The installer's
ripgrepandffmpegstep shows⚠ Could not auto-install (brew not found or install failed)— this is fine; Hermes runs without them (you lose fast file search and TTS voice messages). - Git clone may fail with HTTP/2 stream cancel. Symptom:
error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: CANCEL (err 8). Retry with HTTP/1.1 and shallow:rm -rf ~/.hermes/hermes-agent git -c http.version=HTTP/1.1 clone --depth=1 https://github.com/NousResearch/hermes-agent.git ~/.hermes/hermes-agent uv pip install --system -e ".[all]"picks system Python 3.9 and fails. Hermes needs Python>=3.11. The installer normally creates a venv; if you're re-doing this manually:cd ~/.hermes/hermes-agent uv venv .venv --python 3.11 source .venv/bin/activate uv pip install -e ".[all]"hermesCLI symlink is created at~/.local/bin/hermesby the installer, but if the install aborted before that step you must symlink yourself:ln -sf ~/.hermes/hermes-agent/.venv/bin/hermes ~/.local/bin/hermes- Ollama direct-download path (no Homebrew): grab the .zip, extract, and symlink the CLI from inside the .app bundle. The CLI is at
Contents/Resources/ollama, NOTContents/MacOS/Ollama(which is the GUI binary):curl -fL -o /tmp/Ollama-darwin.zip https://ollama.com/download/Ollama-darwin.zip unzip -q /tmp/Ollama-darwin.zip -d /tmp/ollama-extract/ mv /tmp/ollama-extract/Ollama.app ~/Applications/ ln -sf ~/Applications/Ollama.app/Contents/Resources/ollama ~/.local/bin/ollama - PATH bootstrap — after install, add to
~/.zshrc(the installer warns about this but doesn't always patch it):export PATH="$HOME/.local/bin:$HOME/.hermes/node/bin:$PATH"~/.local/binprovideshermes,ollama,uv,python3.11.~/.hermes/node/binprovides bundled Node 22. - Headless Ollama server — instead of
open -a Ollama(which launches the GUI), run the CLI server directly so it survives without a GUI session:nohup ollama serve > /tmp/ollama.log 2>&1 & disown
Steps
1. Ollama service (port 11434)
macOS uses launchd / brew services, not systemctl. Check three install paths:
# Already running? (most common case after first boot)
lsof -nP -iTCP:11434 -sTCP:LISTEN 2>/dev/null | grep -q LISTEN && echo "ollama up" || echo "needs start"
If not running, start by whichever install method exists:
# brew-installed
brew services list 2>/dev/null | grep -q "ollama.*started" || brew services start ollama 2>/dev/null
# .app bundle (Ollama.app's bundled server)
[ -d /Applications/Ollama.app ] && open -a Ollama 2>/dev/null
# direct binary fallback (no brew, no .app)
pgrep -f "ollama serve" >/dev/null || (nohup ollama serve > /tmp/ollama.log 2>&1 & disown)
Verify port reachable:
curl -sf http://localhost:11434/api/tags >/dev/null && echo "ollama API ready"
2. Model present
REQUIRED: hermes3:8b (only model used — no fallback per user spec).
ollama list | grep -q "hermes3:8b" || ollama pull hermes3:8b
Pull takes ~5–8 min on average broadband (4.7 GB). Run in background if missing; wait before warmup. Do NOT swap to llama3.1 or any fallback — user wants hermes3 only.
3. Warmup model into RAM
Reduces first-prompt latency from ~30s → ~1s:
curl -s http://localhost:11434/api/generate -d '{"model":"hermes3:8b","keep_alive":"30m"}' >/dev/null
keep_alive=30m keeps weights resident. Apple Silicon Metal acceleration is used automatically by Ollama — no config needed.
4. Hermes CLI sanity check
hermes --version
hermes status 2>&1 | head -20
If hermes status errors on provider, verify config:
grep -E "^ (provider|default|model|base_url):" ~/.hermes/config.yaml
Expected (verified against Hermes Agent v0.14.0 runtime, May 2026):
model:
provider: custom
base_url: http://localhost:11434/v1
model: hermes3:8b
default: hermes3:8b
Also set in ~/.hermes/.env:
OPENAI_API_KEY=ollama
CRITICAL — provider value must come from hermes doctor's known-providers list. The runtime in v0.14.0 lists exactly these (run hermes doctor to re-fetch — list can change between versions):
ai-gateway, alibaba, alibaba-coding-plan, anthropic, arcee, auto,
azure-foundry, bedrock, copilot, copilot-acp, custom, deepseek,
gemini, gmi, google-gemini-cli, huggingface, kilocode, kimi-coding,
kimi-coding-cn, lmstudio, minimax, minimax-cn, minimax-oauth, nous,
novita, novita-ai, novitaai, nvidia, ollama-cloud, openai-codex,
opencode-go, opencode-zen, openrouter, qwen-oauth, stepfun,
tencent-tokenhub, xai, xai-oauth, xiaomi, zai
For a local Ollama server, use custom (OpenAI-compatible endpoint). Do NOT use:
main— was suggested by some doc pages, but rejected by runtime as "Unknown provider 'main'"ollama— not in the list (onlyollama-cloudfor the hosted service)lmstudio— only valid for actual LM Studio, not Ollama
To verify: hermes doctor should print ✓ model.provider 'custom' is a recognised provider.
Configure via: hermes config set model.provider custom (then hermes config set model.default hermes3:8b, etc.) — writes directly to ~/.hermes/config.yaml.
After changing config, restart the dashboard so it re-reads:
hermes dashboard --stop && nohup hermes dashboard --no-open --tui > /tmp/hermes-dashboard.log 2>&1 & disown
Then refresh the browser tab — the chat tab caches the init result.
5. Web dashboard UI (port 9119)
PREFERRED UI = web dashboard. (The macOS Electron .app may launch silently from a non-GUI exec env — skip it from inside this skill; user can double-click Hermes.app themselves.)
CRITICAL pre-reqs (else "Chat unavailable: 1"):
hermes-agent[web]extra installed (pip install hermes-agent[web]oruv pip install -e ".[all]")- Node 22 MUST be first in PATH when starting dashboard. Prefer the bundled Node at
~/.hermes/node/bin/node(installed automatically byinstall.sh). Fall back tofnm exec --using=22.22.2only if the bundled Node is absent. - Web UI dist built (
hermes_cli/web_dist/assets/) - TUI dist built (
ui-tui/dist/entry.js) — chat tab spawns this subprocess
Skip if already up:
lsof -nP -iTCP:9119 -sTCP:LISTEN 2>/dev/null | grep -q LISTEN && echo "dashboard up" || echo "needs start"
Resolve Node 22 path (bundled preferred, fnm fallback):
if [ -x ~/.hermes/node/bin/node ]; then
NODE22_DIR=~/.hermes/node/bin
elif command -v fnm >/dev/null; then
NODE22_DIR=$(dirname $(fnm exec --using=22.22.2 -- which node))
else
echo "ERROR: No Node 22 available. Run the official installer or 'brew install fnm && fnm install 22.22.2'." && exit 1
fi
echo "Using Node at: $NODE22_DIR"
Build web UI if missing:
[ -f ~/.hermes/hermes-agent/hermes_cli/web_dist/index.html ] || \
(cd ~/.hermes/hermes-agent/web && \
PATH="$NODE22_DIR:$PATH" npm install && \
PATH="$NODE22_DIR:$PATH" npm run build)
Build TUI if missing (REQUIRED for Chat tab):
[ -f ~/.hermes/hermes-agent/ui-tui/dist/entry.js ] || \
(cd ~/.hermes/hermes-agent/ui-tui && \
PATH="$NODE22_DIR:$PATH" npm install --no-fund --no-audit && \
PATH="$NODE22_DIR:$PATH" npm run build)
Start dashboard with Node 22 PATH + TUI tab:
PATH="$NODE22_DIR:$PATH" nohup hermes dashboard --no-open --tui > /tmp/hermes-dashboard.log 2>&1 & disown
Wait + verify:
sleep 6 && hermes dashboard --status && lsof -nP -iTCP:9119 -sTCP:LISTEN 2>/dev/null
Confirm Node 22 inherited (macOS uses ps eww, not /proc/$PID/environ):
PID=$(pgrep -f "hermes dashboard")
ps eww -p $PID 2>/dev/null | tr ' ' '\n' | grep "^PATH=" | head -1
URL: http://127.0.0.1:9119 (token auto-injects on page load — no manual auth)
Debug "Chat unavailable: 1": means _make_tui_argv in hermes_cli/main.py:1075 did sys.exit(1). Causes: node/npm missing in PATH, ui-tui not built, or npm install failed. Check /tmp/hermes-dashboard.log for "npm install failed" or "TUI build failed".
Optional native Hermes.app (only if user explicitly asks — launches the Electron desktop UI):
[ -d /Applications/Hermes.app ] && open -a Hermes
6. Optional — Gateway (only if user asks)
For Telegram/Slack/WhatsApp inbound messaging:
nohup hermes gateway start > /tmp/hermes-gateway.log 2>&1 & disown
Skip unless user explicitly requests messaging integrations.
7. Status report + URL
Print table to user with the UI URL prominently at end:
| Component | Status | Endpoint |
|---|---|---|
| Ollama | active | http://localhost:11434 |
| Model | hermes3:8b loaded + warmed | — |
| Hermes CLI | ready | hermes chat |
| Web Dashboard | UP | http://127.0.0.1:9119 |
| Gateway | (skipped unless asked) | — |
Final line MUST be a clickable URL line:
🌐 Open: http://127.0.0.1:9119
Notes
- Apple Silicon Macs use Metal acceleration via Ollama automatically — no GPU flags. Expect
25–40 tok/s for6–10 tok/s).hermes3:8bon M1/M2/M3 with 16 GB+ RAM. Intel Macs fall back to CPU ( - Ollama
keep_aliveevicts model after timeout — re-warmup if cold-start latency returns. - Hermes config:
~/.hermes/config.yaml. Editprovider/default/base_urlto swap backend. - Logs:
/tmp/ollama.log(only if started via nohup; brew services logs to$(brew --prefix)/var/log/ollama.log),/tmp/hermes-dashboard.log,/tmp/hermes-gateway.log./tmpis wiped on reboot. - If port 11434 is occupied by a stale
ollama serve, identify withlsof -nP -iTCP:11434 -sTCP:LISTEN— don't kill blindly. - Disk: each model ~5 GB. Check free space:
df -h ~ | tail -1. - macOS firewall (System Settings → Network → Firewall) may prompt the first time
ollama servebinds. Allow it. - If
hermes/ollama/fnmare not on PATH inside this skill's shell, source the user's profile first:
Apple Silicon Homebrew installs to[ -f ~/.zprofile ] && source ~/.zprofile [ -f ~/.zshrc ] && source ~/.zshrc/opt/homebrew/bin; Intel to/usr/local/bin.
Alternative backend: Claude via OAuth (no longer free with Pro/Max — May 2026)
Hermes ships an OAuth/PKCE flow that lets the user authenticate against Anthropic via their Claude.ai account (hermes_cli/main.py:_run_anthropic_oauth_flow and agent/anthropic_adapter.run_hermes_oauth_login_pure). Two important facts to surface up front, NOT after the user logs in:
hermes -z PROMPTis silent on backend errors. If Anthropic returns a 4xx,hermes -zexits 0 with empty stdout. Always inspect~/.hermes/sessions/request_dump_*.jsonwhen output is empty — the error body is there.- The Pro/Max OAuth path returns different errors depending on the day — both expose the same underlying gate:
- Sometimes:
HTTP 400 invalid_request_error "Third-party apps now draw from your extra usage, not your plan limits. Add more at claude.ai/settings/usage and keep going."— a hard policy refusal. - Sometimes:
HTTP 429 rate_limit_error {"message":"Error"}— opaque body, no Retry-After. Anthropic hides the real cap. - Same Claude.ai account quota appears to be shared across tools — if the user is concurrently using Claude Code on the same account, Hermes calls get throttled even when the policy block isn't tripped.
The OAuth token always authenticates (no 401), but inference is gated. Two ways to make this work: (a) add extra-usage credits at https://claude.ai/settings/usage AND ensure no concurrent heavy use of the same account elsewhere, or (b) use Path C (paid
ANTHROPIC_API_KEY).
- Sometimes:
So when a user asks "can Hermes use Claude without an API key?" the honest answer is now:
- Path A (auto-link Claude Code credentials): only works if standalone Claude Code CLI is installed and logged in — fails in Agent SDK / IDE host environments because the host manages credentials privately.
- Path B (Claude.ai OAuth via PKCE): wires up, but inference is blocked unless the user has paid extra-usage credits. Effectively not free.
- Path C (Anthropic API key): paid pay-per-token, always works.
Default to local Ollama for genuinely-free local inference. The skill's main flow assumes this. The OAuth code path remains in Hermes — and may resume working for free if Anthropic reverses the policy — but as of May 2026 it requires payment.
If the user explicitly wants to try Path B anyway (e.g. they've added extra-usage credits):
hermes config set model.provider anthropichermes config set model.default claude-opus-4-7(or whichever model)- Trigger the PKCE flow by importing
agent.anthropic_adapter.run_hermes_oauth_login_purein the venv Python, OR runhermes modelinteractively and pick option 1 from the auth-method menu. - After login, the access_token + refresh_token persist to
~/.hermes/.anthropic_oauth.jsonin camelCase schema:{accessToken, refreshToken, expiresAt, scopes}. Do NOT use snake_case —read_hermes_oauth_credentials()will silently ignore it.