Last updated on

I Tuned Every Line of Hermes config.yaml — 3 Settings That Stop Long Tasks From Getting Stuck


The most frustrating thing about using Hermes Agent on complex tasks isn’t getting a wrong answer — it’s watching the job freeze halfway through: API calls hang, context length explodes after many turns, or a failed tool gets stuck in an endless retry loop. Most of the time, these aren’t model problems. They are default values in ~/.hermes/config.yaml that haven’t been tuned for long-running work.

After running hundreds of long tasks, I went through my config line by line and found that only three settings really decide whether a long task finishes smoothly. Set them to match your workload, and most complex jobs will run to completion without manual intervention.

Below, each section follows the pattern: symptom → cause → fix → recommended values, with copy-paste YAML snippets.


Setting 1: Put a Tight Leash on API Calls — Provider Timeouts

Symptoms

  • The task reaches 50%, the terminal goes silent, and after thirty seconds you see “Connection timed out.”
  • A background or cron job shows running, but the log hasn’t moved for minutes.
  • After switching to a different OpenRouter provider, responses become erratic and occasionally hang entirely.

Cause

Hermes API calls fall back to two environment variables by default: HERMES_API_TIMEOUT (1800 s) and HERMES_API_CALL_STALE_TIMEOUT (90 s). However, the request_timeout_seconds and stale_timeout_seconds keys under the providers block in config.yaml take precedence; the environment variables are only used when no config is set.

Without per-provider tuning:

  • Cloud models with long thinking (Claude Opus, o1, deep-research) may be killed before they finish.
  • Local endpoints (LM Studio, Ollama, vLLM) can take tens of seconds to cold-start, but default request timeouts are much shorter.
  • A single flaky provider can deadlock the whole run because there is no explicit timeout.

Fix

Add a providers block at the top of config.yaml and tune per provider:

providers:
  anthropic:
    request_timeout_seconds: 600      # tolerate 10 min for slow thinking
    stale_timeout_seconds: 300      # non-streaming calls only
  openrouter:
    request_timeout_seconds: 300
    stale_timeout_seconds: 120
  lmstudio:
    request_timeout_seconds: 300      # local cold-start is slow
    stale_timeout_seconds: 900        # explicitly re-enable stale detection
  ollama-local:
    request_timeout_seconds: 300
    stale_timeout_seconds: 900

If you mostly use one provider, configuring just that provider is enough. request_timeout_seconds is passed directly to the SDK as timeout=, overriding the legacy environment variable.

Scenario request_timeout_seconds stale_timeout_seconds
Fast cloud models (Claude 3.5 Sonnet, GPT-4o mini) 60–120 60–90
Long-thinking models (Claude Opus, o1, deep-research) 300–600 120–300
Local models (LM Studio / Ollama / vLLM) 180–300 600–900
Background / cron jobs 300–600 120–300

Note: stale_timeout_seconds only applies to non-streaming calls. Streaming calls are considered alive as long as tokens keep arriving.


Setting 2: Don’t Let Context Blow Up First — Compression Strategy

Symptoms

  • After many tool turns, the model starts answering off-topic or throws “context length exceeded.”
  • Compression fires too late, at 80% of the window, and already compresses away important intermediate results.
  • After compression, the agent “forgets” things you just confirmed: API keys, file paths, constraints.

Cause

Hermes’ compression block triggers when token usage hits threshold × context_length. The defaults may not fit your workload:

  • threshold: 0.50 is aggressive for a 200K context but too late for a 32K context.
  • protect_last_n: 20 keeps only the last 20 messages, which may cover only 2–3 critical turns in a long task.
  • target_ratio: 0.20 decides how much recent tail to keep; too small loses detail, too large wastes space.

There is also a hidden rule in the code: for models with context windows under 512K, the threshold is floored to 0.75. So small-window models don’t trigger at 50% at all — they trigger at 75%. Knowing this helps you estimate the real compression point.

Fix

compression:
  enabled: true
  threshold: 0.65           # trigger earlier than default
  target_ratio: 0.25        # keep 25% recent tail
  protect_last_n: 30        # ~15 full turns
  protect_first_n: 1        # only system prompt + first user message
  codex_app_server_auto: native

If your task needs frequent early context (e.g., “always use Python 3.11”, “this project uses pnpm”), raise protect_first_n to 3. Otherwise, keep it at 1 to save space.

Model context threshold target_ratio protect_last_n
≤ 32K (Claude 3.5 Sonnet, GPT-4o) 0.75 (default floor) 0.25 30–40
128K–200K 0.60–0.65 0.20–0.25 20–30
≥ 1M (Gemini, Kimi k1.5) 0.50–0.55 0.15–0.20 20

Tip: The compression summarizer defaults to Gemini Flash, which is fast and cheap. For code-heavy tasks, you can pin a different model under auxiliary.compression, but the default is usually good enough.


Setting 3: Lock the Tool Loop — agent.max_turns

Symptoms

  • A simple task invokes 50 tool turns and the agent is still “let me double-check.”
  • A network blip causes one tool to fail repeatedly, sending the agent into a retry spiral and your bill climbing.
  • A background task runs for half an hour and turns out to be stuck in a loop.

Cause

agent.max_turns caps how many tool-calling iterations the agent can make in one user request. The default of 60 is enough for casual Q&A, but it is quickly exhausted by complex debugging, batch processing, or iterative confirmation. Without a cap, a failing tool can retry indefinitely.

Pairing max_turns with tool_loop_guardrails.hard_stop_enabled creates a circuit breaker for abnormal loops.

Fix

agent:
  max_turns: 100              # room for complex tasks
  api_max_retries: 2          # fail fast and let fallback take over
  reasoning_effort: medium

tool_loop_guardrails:
  warnings_enabled: true
  hard_stop_enabled: true     # circuit breaker for abnormal loops
  warn_after:
    exact_failure: 2
    same_tool_failure: 3
    idempotent_no_progress: 2
  hard_stop_after:
    exact_failure: 5
    same_tool_failure: 8
    idempotent_no_progress: 5
Task type max_turns hard_stop_enabled
Casual Q&A / single-step queries 30–40 false
Code debugging / medium complexity 60–80 true
Batch processing / long background jobs 100–150 true
Exploratory research / multi-file refactoring 100–200 true

Note: max_turns is the per-request tool iteration limit, not the lifetime message limit of the whole session. You can reset context anytime with /new or other session-management commands from our Hermes v0.18 command panorama.


Complete Reference: A Ready-to-Use config.yaml Snippet

Here is a consolidated snippet for the common setup of OpenRouter as primary provider + occasional local models + frequent long tasks:

model:
  default: "anthropic/claude-opus-4.6"
  provider: "auto"
  base_url: "https://openrouter.ai/api/v1"

providers:
  anthropic:
    request_timeout_seconds: 600
    stale_timeout_seconds: 300
  openrouter:
    request_timeout_seconds: 300
    stale_timeout_seconds: 120
  lmstudio:
    request_timeout_seconds: 300
    stale_timeout_seconds: 900

compression:
  enabled: true
  threshold: 0.65
  target_ratio: 0.25
  protect_last_n: 30
  protect_first_n: 1
  codex_app_server_auto: native
  codex_gpt55_autoraise: true

agent:
  max_turns: 100
  api_max_retries: 2
  reasoning_effort: medium

tool_loop_guardrails:
  warnings_enabled: true
  hard_stop_enabled: true
  warn_after:
    exact_failure: 2
    same_tool_failure: 3
    idempotent_no_progress: 2
  hard_stop_after:
    exact_failure: 5
    same_tool_failure: 8
    idempotent_no_progress: 5

Save to ~/.hermes/config.yaml. New sessions pick it up immediately; already-running sessions need /new to reload it.


Verification: Did It Actually Help?

Three quick checks:

  1. Trigger long thinking deliberately. Ask the agent to process a 500-line log file or read ten source files at once. You should no longer hit context length exceeded.
  2. Simulate API jitter. Briefly block the provider IP with timeout or iptables and confirm the agent fails within the configured timeout and attempts fallback, instead of hanging forever.
  3. Inspect compression. During a long task, run /compress or wait for automatic compression, then verify that the last ~30 messages and the system prompt are still present.

For more complex failure modes, see our deep dive on Hermes error handling and recovery, which combines timeouts, fallbacks, and retries into a single resilience strategy.


Summary

Long tasks usually get stuck not because the model got dumber, but because API timeouts, context compression, and tool-loop limits are not aligned. After tuning these three settings:

  • API calls time out cleanly and fallback to another provider instead of hanging.
  • Context compresses at the right moment, preserving recent details without hitting the window limit.
  • Tool calls have a hard ceiling, preventing retry spirals and runaway bills.

If you are just getting started, read the install guide first to make sure your environment is solid, then keep this snippet as a “long-task template” to copy for demanding jobs.


References: this article is based on the official Hermes Agent cli-config.yaml.example and official documentation.