Hermes Agent Deep Cuts: The Flag That Turns Agent Runs Into Auditable Jobs
Most agent automation has a blind spot: it can tell you whether a job returned text, but not what the job consumed to produce it.
Hermes Agent has a quiet answer. hermes -z with --usage-file turns a one-shot run into a small, auditable job. The command still returns only the final answer to the caller, while writing a JSON sidecar with estimated cost, token counts, API-call count, model, provider, session ID, service tier, and completion status.
That is not a billing system. It is something more useful at the automation boundary: evidence attached to each invocation.
The feature hiding in plain sight
The normal interactive CLI is designed for a person. It has a banner, spinner, tool previews, and a session line. hermes -z is designed for a script, cron job, or parent process:
hermes -z "Summarize the changed files" \
--usage-file /var/tmp/hermes-usage.json
The official CLI documentation says that one-shot mode emits only the final response, and that --usage-file is a per-run JSON report. The installed Hermes Agent in this environment independently reports version 0.19.0 and exposes the same flag in hermes --help.
A caller can therefore keep its stdout contract clean:
answer=$(hermes -z "Produce a release-note paragraph" \
--usage-file "$RUN_DIR/usage.json")
status=$?
if [ "$status" -ne 0 ]; then
jq '{failed, failure, model, provider, api_calls}' "$RUN_DIR/usage.json" >&2
exit "$status"
fi
printf '%s\n' "$answer"
jq '{estimated_cost_usd, total_tokens, api_calls, model, provider, service_tier}' \
"$RUN_DIR/usage.json"
The output and the accounting record are deliberately separate. A downstream program does not need to scrape banners or parse a prose footer that may change with the UI.
What the sidecar actually records
The implementation’s _write_usage_file function serializes these operational fields:
estimated_cost_usd, pluscost_statusandcost_source;- input, output, cached-read, cached-write, reasoning, and total token counts;
api_calls;modelandprovider;session_id;service_tierwhen a run requested one;completedandfailedflags.
The repository’s focused tests also establish two important behaviors. The report creates missing parent directories, and a failed run can still produce a report containing failed: true and a failure field.
This is the observed fact. The systems-level inference is that an agent invocation now has a second interface besides its answer: a compact record that a scheduler, cost monitor, or incident collector can consume.
A practical scenario: bounded batch research
Imagine a nightly job that asks Hermes to inspect a repository and produce a short risk summary. Without a sidecar, the scheduler sees only an exit code and a Markdown file. A model change, provider fallback, or unexpectedly long tool loop can increase cost without changing the artifact’s shape.
With one report per run, the job can append a normalized event to its own ledger:
RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)"
RUN_DIR="artifacts/hermes/$RUN_ID"
mkdir -p "$RUN_DIR"
hermes -z \
--model openai/gpt-5.5 \
--provider openrouter \
--toolsets file,terminal \
"Review the repository and write a risk summary to $RUN_DIR/risk.md" \
--usage-file "$RUN_DIR/usage.json" \
>"$RUN_DIR/answer.txt"
jq --arg run_id "$RUN_ID" \
'. + {run_id: $run_id}' "$RUN_DIR/usage.json" \
>> artifacts/hermes/ledger.jsonl
The command flags are not magic configuration. The CLI source defines --usage-file as one-shot-only, while the one-shot implementation documents that the report is written after the run, including when the run fails.
That makes this useful for more than cost dashboards. A ledger can answer questions such as: which model generated this artifact, how many provider calls did it take, did the run fail after spending tokens, and did the requested service tier travel with the request?
The gotcha: one-shot is intentionally non-interactive
The happy path is easy to copy and easy to misunderstand.
The source explicitly sets HERMES_YOLO_MODE=1 and HERMES_ACCEPT_HOOKS=1 for one-shot execution. That is not a hidden safety recommendation; it is a consequence of running without a person who can answer an approval prompt. A pipeline that uses -z must treat the command itself as a pre-approved execution boundary.
There is a second trap: delegation behaves differently. One-shot mode declares a stateless channel so detached subagent results do not disappear after the parent process exits. If a workflow depends on asynchronous work re-entering a later interactive session, -z is the wrong surface.
In other words, -z is not “interactive Hermes, but quieter.” It is a batch contract with batch semantics. The source comments make both points explicit: approvals are bypassed because a prompt would hang, and the stateless channel routes delegation through a synchronous path.
The operational response is straightforward:
- Use a dedicated working directory and narrow
--toolsetsrather than inheriting every configured tool. - Give the process least-privilege credentials and an isolated filesystem.
- Treat the command line and prompt as code-reviewed job configuration.
- Store the usage sidecar beside the artifact, not in a shared mutable “latest run” file.
- Alert on
failed, unexpectedproviderormodel, missing cost data, and cost or token thresholds.
The report improves observability; it does not replace isolation or approvals. It also does not make estimated_cost_usd equivalent to an invoice. The field is explicitly estimated, and the report includes status and source so a ledger can distinguish known, estimated, or unavailable pricing.
Verify it without spending an inference call
There are two useful verification layers.
First, verify the installed interface and environment:
hermes --help | grep -A4 -- '--usage-file'
hermes --version
Second, test the report writer with Hermes’s own focused test file if the development dependencies are installed:
python3 -m pytest -q tests/hermes_cli/test_oneshot_usage_file.py
The test covers successful reports, failure reports, nested output paths, missing fields, unwritable paths, and the failed flag. It does not call a model. For a real smoke test in a controlled environment, use a disposable output path and an explicitly selected provider/model, then verify both the command exit code and the JSON schema:
jq -e '
has("estimated_cost_usd") and
has("input_tokens") and
has("output_tokens") and
has("api_calls") and
has("model") and
has("provider") and
has("failed")
' /var/tmp/hermes-usage.json
A missing report is not automatically proof that the model run failed: the writer is intentionally best-effort and never masks the run’s own outcome. That is another reason to check both the process status and the sidecar, and to alert when either is absent.
Facts, inference, and the open edge
Observed: the current Hermes CLI exposes -z/--oneshot and --usage-file; the official documentation defines a JSON usage report; the implementation writes token, cost, call, identity, tier, and status fields; and the tests cover failure accounting.
Inference: attaching a usage record to every batch invocation makes agent work more governable because artifact provenance and resource consumption can be analyzed together.
Open question: an estimated per-run report still depends on provider pricing metadata and does not by itself reconcile provider invoices, shared credential pools, or costs created by external services called through tools. A serious deployment should reconcile the sidecar with provider-side billing and its own tool telemetry.
The interesting part is not that Hermes can print token counts. Many systems can. The interesting part is the boundary: a response-only interface for the caller, and a structured evidence interface for the operator. That is the difference between piping an agent into a script and operating an agent as a job.