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.
Recommended values
| 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_secondsonly 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.50is aggressive for a 200K context but too late for a 32K context.protect_last_n: 20keeps only the last 20 messages, which may cover only 2–3 critical turns in a long task.target_ratio: 0.20decides 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.
Recommended values
| 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
Recommended values
| 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_turnsis the per-request tool iteration limit, not the lifetime message limit of the whole session. You can reset context anytime with/newor 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:
- 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. - Simulate API jitter. Briefly block the provider IP with
timeoutoriptablesand confirm the agent fails within the configured timeout and attempts fallback, instead of hanging forever. - Inspect compression. During a long task, run
/compressor 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.