Skip to main content

Hermes (Nous Research)

Hermes Agent is a multi-provider Python coding agent. On Jetty it's the most flexible runtime — it speaks Anthropic, OpenAI, OpenRouter, Google, and AWS Bedrock natively, including third-party Bedrock catalog models (DeepSeek, Zhipu GLM, etc.) that other runtimes can't reach.

Use the hermes runtime when you need:

  • A non-Anthropic Bedrock model (DeepSeek, Zhipu, Mistral, Llama)
  • Multi-provider parity in one runbook (drop-in swap between Bedrock, OpenAI, OpenRouter, and Gemini)
  • Native AWS SigV4 / AWS_BEARER_TOKEN_BEDROCK Bedrock access
  • A single binary that drives every gateway your collection has keys for

Provider support

ProviderSupportedHow it routes
AWS BedrockBuilt-in bedrock plugin via hermes-agent[bedrock] (Anthropic Bedrock SDK / SigV4)
AnthropicCustom jetty_anthropic provider (anthropic_messages transport, direct API)
OpenAICustom jetty_openai provider (chat_completions transport, direct API)
OpenRouterCustom jetty_openrouter provider (chat_completions transport, pinned to https://openrouter.ai/api/v1)
GoogleBuilt-in gemini provider

Confirmed-working models

These configurations have been verified end-to-end in production runs (metaphrenie/write-a-poem, May 2026). For Bedrock, use the cross-region inference profile form (us.anthropic.*) for Anthropic models and the bare catalog ID for third-party models.

ProviderModel IDNotes
AWS Bedrockus.anthropic.claude-sonnet-4-6Cross-region inference profile
AWS Bedrockus.anthropic.claude-haiku-4-5-20251001-v1:0Full versioned profile also accepted
AWS Bedrockdeepseek.v3.2Third-party Bedrock catalog model
AWS Bedrockzai.glm-5Third-party Bedrock catalog model

Known-broken model IDs

Model IDWhat happensUse instead
anthropic.claude-sonnet-4-6 (bare)Bedrock rejects without the us. prefix on us-east-1us.anthropic.claude-sonnet-4-6
qwen.qwen3-32b-v1:0Fails — qwen models on Bedrock require a different ID shape or aren't enabled on the bearer-token's accountPick a different model
meta.llama4-maverick-17b-instruct-v1:0Fails for the same reasonPick a different model

If a Bedrock model fails silently, the upstream error is suppressed by Hermes's -Q flag but is captured in ~/.hermes/logs/errors.log inside the sandbox. Jetty also surfaces "agent 'hermes' produced no /app/results files" in the trajectory output as a hard failure.

Setup

Configure provider keys on your collection. Hermes auto-routes based on which keys are present.

TOKEN="$(cat ~/.config/jetty/token)"
cat <<'BODY' | curl -s -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"https://flows-api.jetty.io/api/v1/collections/{COLLECTION}/environment" \
--data-binary @-
{
"environment_variables": {
"AWS_BEARER_TOKEN_BEDROCK": "ABSK...",
"AWS_REGION": "us-east-1"
}
}
BODY

For Anthropic, set ANTHROPIC_API_KEY; for OpenAI, OPENAI_API_KEY; for Google, GEMINI_API_KEY.

Use it in a runbook

---
agent: hermes
model: us.anthropic.claude-sonnet-4-6
snapshot: python312-uv
---

# Write a Poem

Generate a haiku about {{prompt}} and write it to `{{results_dir}}/poem.md`.

Or via the Chat Completions API:

{
"model": "us.anthropic.claude-sonnet-4-6",
"jetty": {
"runbook": true,
"agent": "hermes",
"collection": "my-collection",
"task": "my-task"
}
}

How routing works

When Jetty creates the sandbox, the runner reads the collection's environment variables and picks a provider in this priority order:

  1. AWS_BEARER_TOKEN_BEDROCK or AWS_ACCESS_KEY_ID--provider bedrock (built-in plugin)
  2. ANTHROPIC_API_KEY--provider jetty_anthropic (custom direct-API entry)
  3. OPENROUTER_API_KEY--provider jetty_openrouter (custom OpenRouter entry)
  4. GEMINI_API_KEY / GOOGLE_API_KEY--provider gemini
  5. OPENAI_API_KEY--provider jetty_openai (custom direct-API entry)

The order is important on two counts. First, Hermes v0.12.0+ requires one of OPENAI_API_KEY / OPENROUTER_API_KEY / ANTHROPIC_API_KEY in the env to pass its first-run guard. When routing through Bedrock without one of those, Jetty sets a sentinel OPENAI_API_KEY that's never actually read — but Bedrock is still chosen because AWS_BEARER_TOKEN_BEDROCK is checked first. Second, OPENROUTER_API_KEY is checked before OPENAI_API_KEY so that fan-out collections with both keys configured still route OpenRouter calls through the explicit OpenRouter entry rather than falling through to OpenAI.

Limitations

  • Token usage is captured post-run by reading ~/.hermes/sessions/session_<id>.json after the agent exits. The streaming log file (/logs/agent/hermes.txt) contains only the final assistant text plus a session_id: anchor — usage numbers do not stream.
  • Errors under -Q are quiet by design. If a run fails with no obvious cause, check /logs/agent/hermes.txt first; if it's empty, the model call itself returned 4xx/5xx silently. See Troubleshooting below or run scripts/debug_hermes_bedrock.py from the mise repo to reproduce in isolation.
  • OpenRouter base URL is hardcoded to https://openrouter.ai/api/v1. Hermes's config schema doesn't support env-var indirection on the api: field, so the YAML baked at install time is the URL. Corp-gateway / self-hosted OpenRouter proxies that work with claude-code / codex / opencode (which honor OPENROUTER_BASE_URL) currently can't be wired through hermes without rebuilding the snapshot.

Troubleshooting

A run that fails fast (under 10 seconds) with success: false and an empty results_files is almost always the model call returning 4xx. Common causes:

  • 404 "model does not exist" — the model ID isn't in your account's Bedrock catalog or is missing the regional prefix.
  • 401 "is not available for this account" — the model exists but you don't have entitlement; check the AWS Bedrock console.
  • Expired AWS_BEARER_TOKEN_BEDROCK — bearer tokens expire; re-issue from the Bedrock console.

To reproduce locally inside a sandbox identical to production, see mise/scripts/debug_hermes_bedrock.py.