← Back to MuseHub

Hermes Ops Notebook

Current identity-routing guidance — 2026-09-15: This notebook preserves historical setup notes. Its unprofiled launch/resume examples and session-only identity explanation are superseded for NIGHTINGALE seats. Use /home/hatch/workspace/bin/hermes-seat mit chat or /home/hatch/workspace/bin/hermes-seat cornell chat, and resume only a session belonging to that profile. Current standing handles: /home/hatch/workspace/agents/hermes-seats.json. Current operating guide: /home/hatch/workspace/agents/HERMES_PROFILES.md. Separate sessions alone do not isolate persistent memory; separate profiles do.

A running log of operating Hermes on this machine — every command, config, and "why", written so it can be followed step-by-step to set up Hermes on any other machine later.

Install — 2026-09-11

Machine: Ubuntu 24.04, Python 3.12.3, Node v24.20.0

Steps:

python3 -m venv ~/workspace/venvs/hermes
~/workspace/venvs/hermes/bin/pip install hermes-agent

Result: Hermes Agent v0.19.0 (2026.7.20)

Why a venv: it keeps Hermes's Python packages isolated from the system Python, and everything lives under ~/workspace, which survives VM restarts. (~/.venvs would work too; ~/workspace/venvs/ keeps all agent envs in one visible place.)

Key paths: - Binary: ~/workspace/venvs/hermes/bin/hermes - Python packages: ~/workspace/venvs/hermes/lib/python3.12/site-packages - Hermes's own data dir (created on first run): ~/.hermes/

Not yet done: no model provider / API key configured, so hermes chat can't actually talk to a model yet. That's the next step (likely OpenRouter).

CLI patterns worth knowing

hermes chat -q "your prompt here"              # one-shot, non-interactive
hermes chat --query-file - < prompt.txt        # prompt from stdin, verbatim
hermes chat --resume <session_id> -q "..."     # continue a persistent session
hermes chat --provider openrouter -q "..."     # force OpenRouter
hermes chat -Q -q "..."                        # quiet: script-friendly output
hermes --resume latest                         # reopen the most recent session

The --resume pattern is the whole "persistent agent" trick: one long-lived session that keeps memory across calls, driven from the shell.

Config — TODO

Walk through ~/.hermes/config.yaml once the first run creates it.

1Password — connected 2026-09-11, with a real wrinkle

What happened: AK created a 1Password service account (a special login meant for software, not humans) in the 1Password web app under Developer → Service accounts, scoped to a dedicated vault, and pasted the token into a secure entry page. The token now lives in the Secure Vault as the custom.1password connector. I also scaffolded a 1password skill at ~/workspace/skills/1password/ (built with /opt/hatch/skills/skill-creator/bin/scaffold-connector-skill --provider 1password).

The wrinkle (verified, not guessed): the vault hands out credentials only inside web requests — it swaps a placeholder (hsurr:...) for the real secret as the request leaves the machine. But the op command-line tool needs the actual token text in its OP_SERVICE_ACCOUNT_TOKEN environment variable, and it checks the token's format before doing anything on the network. I tested it: op rejected the placeholder with failed to parseToken, format is invalid. And 1Password publishes no public web API that accepts service-account tokens (the only 1Password HTTP API belongs to 1Password Connect, a separate self-hosted server with its own tokens).

What this means in plain terms: the token is safely stored, but I can't plug it into op from inside the vault's rules. The loop closes when the token reaches this machine's environment through a channel AK controls — e.g. the planned Ansible pull setup, which can deploy the token as an environment variable. Long-term alternative: run a 1Password Connect server on AK's own infrastructure; its web API does fit the vault's pattern (and a service-account token can bootstrap the Connect server itself).

Commands used (all safe — no secret ever printed):

/opt/hatch/skills/skill-creator/bin/scaffold-connector-skill --provider 1password
# created ~/workspace/skills/1password/SKILL.md

python3 -c "... dynamic_credential_entry('custom.1password', 'access_token') ..."
# confirmed the vault returns a surrogate placeholder, not the secret

OP_SERVICE_ACCOUNT_TOKEN="<surrogate>" ~/workspace/bin/op vault list
# -> [ERROR] failed to DecodeSACredentials: failed to parseToken, format is invalid
# (proves the CLI validates locally; the placeholder never leaves the machine)

Skill layout: ~/workspace/skills/1password/SKILL.md documents the gap honestly; bin/op_api.py is a minimal authenticated-HTTP helper for the connector's native pattern (useful if we ever point it at a Connect server).

OpenAI OAuth setup — 2026-09-14

Decision (AK, 2026-09-14): no API keys, no OpenRouter — both agents authenticate with OpenAI OAuth. Model: gpt-5.6-terra, thinking high.

PATH fix: ~/workspace/venvs/hermes/bin was appended to ~/.bashrc (2026-09-14). Note: Muse's own exec sessions run with a clean environment (bash --norc --noprofile), so every command below needs export PATH="$HOME/workspace/venvs/hermes/bin:$PATH" explicitly.

The proxy bug (real, diagnosed): the first hermes auth add --type oauth openai-codex --no-browser attempt died with httpx.InvalidURL: Invalid port: ':1]'. Root cause: httpx 0.28.1's get_environment_proxies() turns every no_proxy entry into a URLPattern, and this machine's no_proxy contains bracketed IPv6 addresses ([::1], [fd8b:...]), which produce unparsable patterns like all://*[::1]. Verified by constructing URLPattern per key in the venv Python — exactly the IPv6-derived keys failed.

Workaround: run Hermes with the IPv6 entries stripped from no_proxy:

export NO_PROXY="localhost,127.0.0.1,198.19.0.1,198.19.0.2"
export no_proxy="localhost,127.0.0.1,198.19.0.1,198.19.0.2"

Shell gotcha that cost a retry: export A="x" B="$A" expands $A before the assignment, so B gets the OLD value. Set them in two separate export statements. (httpx reads lowercase no_proxy first, so the broken one wins if you get this wrong.)

Auth flow (device code, headless-safe):

export PATH="$HOME/workspace/venvs/hermes/bin:$PATH"
export NO_PROXY="localhost,127.0.0.1,198.19.0.1,198.19.0.2"
export no_proxy="$NO_PROXY"
script -qec "hermes auth add --type oauth openai-codex --no-browser" /dev/null
# -> prints https://auth.openai.com/codex/device + a code like CB32-BI7ZS
# -> user opens the URL on their phone, enters the code, approves
# -> "Added openai-codex OAuth credential #1"

script supplies the pseudo-terminal the login flow demands. The --no-browser flag keeps it from trying to open a browser on the VM.

Verify (no secrets printed):

hermes auth list        # shows: openai-codex (1 credentials): #1 ... oauth device_code
hermes doctor          # "✓ OpenAI Codex auth (logged in)"

Model + provider selection (non-interactive): hermes model is interactive-only, but the config file takes the same values. The schema is model: {provider, default}:

hermes config set model.provider openai-codex
hermes config set model.default gpt-5.6-terra
hermes config set agent.reasoning_effort high

Resulting ~/.hermes/config.yaml:

model:
  provider: openai-codex
  default: gpt-5.6-terra
agent:
  reasoning_effort: high

Per-invocation overrides also exist: hermes -m <model> and the HERMES_INFERENCE_MODEL / HERMES_INFERENCE_PROVIDER env vars.

What models does this OAuth login actually unlock? The openai-codex provider talks to the Codex backend (chatgpt.com/backend-api/codex/models), whose model list differs from OpenClaw's catalog. Queried live with the stored OAuth token (transient, in-memory only — never printed or saved): gpt-6-astra, gpt-reserve, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.3-codex-spark, codex-auto-review. The 5.6 family (sol/terra/luna) exists here — AK's gpt-5.6-terra pick is valid on both agents.

End-to-end test (2026-09-14):

hermes -z "Reply with exactly: HERMES-OK"   # -> HERMES-OK (~8s)

Key files: ~/.hermes/auth.json (OAuth tokens, 600 perms — never copy these anywhere), ~/.hermes/config.yaml (model/provider/reasoning), ~/.hermes/sessions/ (persistent sessions for --resume).

Hermes interaction log

Shared record of every Hermes run — prompt, what it did, outcome. (Starts 2026-09-14; earlier history: none, provider was just configured.)

Date Prompt Actions Outcome
2026-09-14 Reply with exactly: HERMES-OK One-shot -z turn via openai-codex / gpt-5.6-terra OK — HERMES-OK in ~8s

← Back to MuseHub