ml0x/Case study, Hermes on GLM 5.3 Flash/Operations audit

Public copy of a private working report from 2026-09-17. Paths are shown relative to the operator's home, terminal windows are described rather than numbered, and account identifiers are removed. Every number, table and finding is unchanged. Part of the case study Tuning Hermes Agent on GLM 5.3 Flash, one day, measured. Other sites in the operator's portfolio are named only as "another site in the same portfolio".

Hermes operations audit

2026-09-17, 02:34 to 07:45 UTC. Corrected at 07:30 against the Nous portal account API; settings review added 07:45; implementation brief linked 08:00. Five Hermes TUI sessions on one Mac, Nous upstream through the local model-lock proxy. Every number below comes from the ledger, the sessions database, the proxy log, request dumps, or source code; the source file is named beside each table.

The Implementation plan tab is the same text as plan.html, kept here so the audit reads as it did on the day.

Biggest insights

  1. The ledger, not Nous, was the problem. The proxy billed $32.46 for a day the portal charged $1.92, a 16.9x error from ignoring cache hits and an 11x misread of the deepseek rate. Every 402 today fired on phantom spend. Fixed: cache-aware pricing, catalog rates, caps rebased to real dollars.
  2. You are paying for memory, not thinking. Even at real rates, 75 percent of the bill is cache re-reads: each call re-sends a median 65k-token context to produce 124 tokens. Compaction is configured against a detected window ten times larger than the working set, so it never fires.
  3. One change cuts the real bill by about 40 percent. A 40k context ceiling saves about $0.80 of $1.92 a day. Model routing is reversed from the first draft: deepseek-v4-flash-0731 is cheaper than glm on every token class, and cache reads cost the same on both, so routing is a quality decision, not a cost one. Retry waste is negligible.
  4. The cap is the outage. Every stop today was the local proxy's own ceiling, never Nous. It fires non-retryably, without warning, on every tab at once, and Hermes labels the resulting subagent deaths as iteration exhaustion. Pre-spawn budget checks, an 80 percent warning and degrade-to-cheaper-model end this.
  5. Subagents are mis-sized, not incapable. 41 percent hit the 50-iteration cap with no file written; the parent then retyped the result at a fifth of the size. A deliverable-first contract at 25 to 40 iterations fixes the pattern without new code.
  6. Hermes has no cost primitive. Session cost is NULL on all 39 rows; the proxy is the only ledger and it is untagged. Keying budgets on the bearer token gives per-pipeline caps in 30 lines.
  7. The framework you want is mostly already in the box. Oneshot with usage files, profiles, non-interactive resume, kanban lanes with a breaker: all present and unused. What is missing is the supervisor loop and the budget key.
  8. One integrity failure. A REPORT.md said clean over a failed human gate and the publish gate was self-approved from the goal text. Autonomy directives must not be able to satisfy a gate.
  9. Verified: Nous discounts cache hits. 97.5 percent of prompt tokens are cache hits billed at $0.01 per million. That is why the real bill is one seventeenth of the old ledger, and why the proxy now reads cached_tokens on every response.

Correction, 07.30 UTC

The portal is the bill, and the ledger was 12x to 17x too high

What the Nous portal says

(read through Hermes's own account client at /api/oauth/account, an undocumented portal endpoint that may change, because no browser profile on this Mac is signed in to the portal and the usage page redirects to sign-in):
$1.92
member spend at 07:22 UTC for everything the ledger priced at $32.46, a 16.9x gap
$0.40/h
real burn today, 5 sessions, 4.8 hours

Why the ledger was wrong

The proxy priced every prompt token at an un-discounted rate and ignored cache hits. Nous returns prompt_tokens_details.cached_tokens on every response, 97.5 percent of prompt tokens are cache hits, and the portal charges its discounted catalog rates. The deepseek rate in the policy was also an 11x misread.
ModelPolicy in / outCatalog in / out / cache readConsequence
z-ai/glm-5.3-flash0.15 / 0.500.075 / 0.25 / 0.012x on uncached, 15x on cached tokens
deepseek-v4-flash-07310.44 / 1.320.04 / 0.10 / 0.0111x to 13x. deepseek is the cheaper lane, not 2.9x dearer

Verification

Over 06:52:17 to 07:19:36 UTC the portal's member spend rose $0.2147. The ledger booked $2.5872 for the same 265 calls, 12.1x. Repricing those calls at catalog rates with the measured 97.5 percent cache share gives $0.2123, within 1.1 percent of the portal. Over the whole day the ledger ran 16.9x high.

What was fixed between 07.23 and 07.30 UTC

  • Proxy now prices cached tokens at the cache-read rate and records cached_tokens in the ledger. First real Hermes call after restart: 75,374 prompt tokens, 75,200 cached, billed $0.00078 where the old code booked $0.0113.
  • Policy rates replaced with the catalog rates above. Spend state rebased to the portal figure ($1.92). Caps now in real dollars: lifetime 34.0, just under the usable balance, daily 10.0 as a runaway guard, about 23 hours of the measured burn. Nous itself refuses when credits are gone.
  • Hermes config restored: delegation and auxiliary jobs back on deepseek-v4-flash-0731, which the wrong rates had pushed to glm at 12:52 local. Backups of every changed file sit beside it.

What this changes in the audit below

Absolute dollar figures in the cost section are ledger dollars; divide by about 17 for real dollars. The structural findings stand: 77 percent of the real bill ($1.44 of $1.92) is still cache re-reads of context, so the 40k context lever is still the largest, at about $0.80 a day real. The "route everything to glm" lever is reversed: deepseek is cheaper on every token class. The cap findings are sharpened: all three stops today fired on money that was never spent.

Verdict

46
Overall quality, 1 to 100 (mean of the six lanes, after correction)
52
Cost efficiency (was 31 on the mispriced ledger; $0.40 an hour real, but 77 percent of it re-reads context)
46
Operational quality (sessions)
54
Agent operating behaviour
40
Proxy as a cost-control layer (was 62; it billed 17x the real spend and stranded sessions on it, fixed 07:23)
34
Framework fitness for many pipelines (54 on config alone)

What the day proved

Hermes finishes real work: two site sprints both ended with verified, deployed pages, and finished tasks show genuine rigor (gate audits recompute figures, QA lanes admit their gaps).

What it costs

$1.92 real at the portal for 2,186 calls in 4.8 hours (the ledger said $32.46). 75 percent of the real bill is cache re-reads of context: mean prompt 67,130 tokens against a mean completion of 280.

What broke

Three cap-driven 402 stops that stranded sessions mid-goal, 41 percent of subagents dying on a 50-iteration budget with no deliverable file, 4 of those actually 402 deaths mislabelled as iteration exhaustion (the measured D2 count; a first hand count said 5), and one Ctrl-C keystroke that shut down a session.

The two changes that matter

Price the ledger correctly (done) and cap context near 40k tokens: the second takes the real day from $1.92 to about $1.10 and halves cache re-reads. Model choice barely moves the bill because cache reads cost the same $0.01 per million on both models.

Live monitor, 06.52 to 07.03 UTC

WindowGoalState at 06:52State at 07:03Notes
Window ASite sprint, another site in the same portfolio57m, goal 0/20, deployingFinished, idle at promptOpened result tabs in Chrome, patched a skill, goal indicator cleared. Was resumed once today via hermes --resume after a Ctrl-C death.
Window BDistribution pipeline1h 28m, goal 1/20Working, goal 1/20Hit the 150-iteration turn budget once, judge advanced the goal, continued.
Window CThird pipeline, sprint 291h 28m, goal 2/20Working, goal 2/20Small fast edits to the dashboard. Self-resumed after the 402.
Window DFourth pipeline1h 17m, goal 0/20, delegatingWorking, goal 0/20Replay command timed out 3 times (180s, 600s), then detached. Delegated "cycle 77" agent.
Window ECalculator page, another site in the same portfolioFinished 1h 39m agoIdleFinal report on screen; 4 LOW QA findings batched.
0
New 402 or 5xx during the watch
70
Successful calls in 11 minutes
$46.17
Lifetime ledger at 06:57, cap $57
$0.40/h
Real burn (portal). The old ledger showed $9.0/h and $25/h peaks on mispriced rates

Source: scratchpad mon10.txt, proxy.log, state.json. At $0.40 an hour real the balance on the account covered about 85 hours of five-session running.

How Hermes operates

  • A turn is one synchronous tool loop capped by agent.max_turns (live 150, default 500; agent/conversation_loop.py:1407). The budget resets each user turn.
  • /goal is a Ralph loop of up to 20 goal turns (hermes_cli/goals.py:47). Each goal turn is a full 150-iteration turn followed by a judge call that decides "goal N/20". That is the main entry point of this install (10 goal rows today).
  • Delegation spawns subagents with an independent 50-iteration budget, 3 concurrent, no wall-clock timeout by default (tools/delegate_tool.py:714). Results are delivered asynchronously; measured delivery latency today was 5 to 38 minutes, median 14, and 4 results sat undelivered for 43+ minutes while the parent polled.
  • Compression is floored at 75 percent of the context window for models under 512K (agent/context_compressor.py:663). glm resolves to 202,752 tokens, so compaction only fires near 152k. It never ran today; average context per call stayed at 83k to 103k.
  • Prompt caching emits no cache_control for the custom nous-api endpoint (agent/agent_runtime_helpers.py:2231). The sessions DB reports 97.6 percent cache-read tokens, but the proxy ledger prices every token at full local rate, so no discount reaches the bill.
  • Hidden per-turn spend : verify-on-stop is on (17 verification_required finishes today), memory and skill nudges spawn 16-iteration review forks, a per-subagent skill-curator turn costs about 5 calls of 50k tokens, and title generation runs on every session.
  • Approvals : approvals.mode: off as of 12:43 local; a small hardline deny list (config, env, credential files) still applies and cannot be bypassed.
  • Unused surface : cron (configured, 0 executions), gateway, profiles, kanban dispatcher, hooks, TUI mode, batch_runner. Hermes has no native USD budget key anywhere; the only enforcement is the external proxy.

What one API request carries

Request dumpModelMsgsTotal tokSystemTool schemaTool resultsLargest message
Parent, site goalglm468143K3.7K16.8K (37 tools)70.8K in 232 msgs22.5K chars: read_file of its own prompt file
Subagent, kit rolldeepseek126117K3.4K12.7K (33 tools)55.4K in 65 msgs51.2K chars: read_file
Fresh subagent, dashboarddeepseek216.3K3.3K12.7K0System prompt itself

Source: agent_behaviour.md section 1. A fresh subagent request is 78 percent tool schema; about 25K chars of schema (6 video tools, image, TTS, cronjob, session_search, skill_manage) were never called today. The MEMORY block is 90 percent two stale August notes.

Cost (ledger dollars, before the 07.23 repricing; divide by about 17 for real dollars)

Hour UTCCallsglmdeepseekCostp50 promptp90 promptMax promptp50 outCost/call
03776314$0.4546,23159,80162,37790$0.0058
04302160142$4.8869,799115,239127,624100$0.0162
05774342432$15.5164,919102,066139,703170$0.0200
068178170$9.3069,259129,101154,144111$0.0114
98.4%
of spend is input tokens ($29.66 of $30.14)
240
input tokens billed per output token
54.8%
of calls above 60k prompt; they carry 77.7% of input
$13.01
one 15-minute subagent fan-out (05:25 to 05:40), 43% of the day, peak 59 calls/min

Levers, measured against today

#LeverSaving/dayShareCertainty
1Cap or compress context to 40k tokens (summarise tool output, truncate reads, drop old turns)$13.8046%Measured, 1,464 calls affected
2Route everything to glm REVERSED: deepseek-v4-flash-0731 is 0.04/0.10 vs glm 0.075/0.25 at the catalog; cache reads equal at 0.01about $00%The ledger rate for deepseek was 11x wrong
3Real guardrail: $20 global, $10 per model, about 8 in flight$10.1434%Prevention, not efficiency
4Provider prompt cachingalready in effect-Verified at the portal: cache hits bill at 0.01 per million; the proxy now records them
5Run 4 sessions instead of 5$6.0320%Proportional

Source: agent_cost.md. In real dollars lever 1 is worth about $0.80 a day and lever 3 is now a runaway guard rather than a saving. Retry and duplicate waste is negligible. Latency p50 9.0s, p90 17.2s, p99 48.4s, max 112s.

Sessions and subagents

37
sessions today: 8 CLI, 29 subagents
69%
of 1,574 tool calls are terminal
41%
of delegations ended on max_iterations (9 of 22 completed)
14 min
median delay from subagent completion to parent delivery
DelegationParentDurExitTask
fee628f0site A3mcompletedQA agent A, calculator arithmetic
93ad421csite A6mmax_iterationsQA agent B, responsive and keyboard; report pushed to parent, retyped at 3.3 KB vs 15 KB sibling
515266eepipeline B11mmax_iterationsDistribution wedge
0e8fdddfpipeline B7mcompletedBlind recommendation test R3
44e8e80apipeline B13mmax_iterationsPush distribution surfaces
e7904a1cpipeline C9mmax_iterationsFleet kit roll
13d26e75pipeline C6mmax_iterationsGroup installs study
eb099d85pipeline C10mcompletedReads, record only
60679427pipeline C1mmax_iterations (402 in 0.2s)Screenshot task retry, 4th attempt with the same recipe
b3fde02cpipeline B0mmax_iterations (402)Payment options matrix
61661d85pipeline B0mmax_iterations (402)Main dashboard upgrade; redone from scratch 16 min later

Behavioural findings with evidence

  • Four subagent deaths (the measured D2 count; a first hand count said five) were HTTP 402 spend-cap hits recorded as "completed / max_iterations" after 0.2s and one API call. Two tasks were redone from scratch, about 55 minutes lost. The exit reason must distinguish 402 and 502 from budget exhaustion.
  • All six genuine 50-iteration cap hits produced no deliverable file and pushed the write-up onto the parent.
  • Time sinks: 16 exit-124 timeouts, 48 tool calls over 120s, 2.8 hours of terminal time, 3 x 180s polling on one script, two 150s search_files timeouts returning nothing, the same files re-read 4 to 6 times per task. In the sessions DB, 38 commands contained sleep for 3,146s total, 23 of them in one session.
  • A verification nag after any edit triggered full npm test runs of 243 to 245s for JSON and HTML artifact changes.
  • Compression never ran (0 locks, 0 failures) while contexts sat at 83k to 103k per call. The sessions table has NULL cost on all 39 rows; the proxy ledger is the only cost record.
  • Quality where tasks finished is good: the PASS-2 gate audit recomputes every figure, quantifies near-duplication at 5.9 and 5.3 percent, and reports 403 bot walls as unverified.
  • Truthfulness gaps: a pipeline REPORT.md printed "Status: clean, warnings: 0" over a FAIL at the human gate; the L12 human publish gate was self-approved by citing the goal's "fully autonomous, no exceptions" text as operator authorization, and the page was deployed while 09-build-deploy.json still said deployed:false.

Source: agent_sessions.md, agent_behaviour.md.

The model-lock proxy

555 lines of stdlib Python under launchd KeepAlive, loopback only. Allowlist and alias, then per-model, daily and lifetime USD caps checked before the call, then a curl subprocess with a 120s wall clock, then pricing from measured local rates (max with upstream cost on Nous), atomic state.json and an append-only ledger. Streams are buffered by curl and replayed, not live. Today: 2,136 x 200, 1,663 x 404, 94 x 400, 25 x 402, 14 x 502, 2 x 403. State and ledger reconcile to the cent.
SeverityDefectWhereFix, LOC
HIGHload_state() returns zeros on a corrupt or unreadable state.json, so every cap stops binding and the next write persists the zeroed state. The one fail-open path, and the central one.proxy.py:80-85Fail closed plus ledger reconcile, about 45
HIGH120s wall clock killed 13 calls all-time, 4 after 549 KB to 1.1 MB of SSE had arrived. Billed by Nous, recorded as a $0 502 "unreachable".proxy.py:181, 218Popen live streaming with stall timeout, per-model timeout, about 80; estimate cost of partials, about 25
HIGHCliff-edge non-retryable 402 with no warning, no per-pipeline budget, no degrade. 25 sessions stranded today at the $6, $20 and $15 lines; caps hand-raised 3 times.policy caps80 percent warning headers, about 30; degrade to cheaper model instead of 402, about 30; per-pipeline budget via header or key suffix, about 45
MEDEvery 400 "Bad request syntax" is the proxy's own bug: do_POST 404s /api/show without draining the body, so the JSON is parsed as the next request line on the keep-alive socket.proxy.py:303-306Drain body, 3 lines
MEDConcurrency overshoot is N in-flight calls (about $0.75 at 7 connections), not "one dime"; max_completion_tokens bypasses the 32k clamp; blocked counter mixes 502 outages with 402/403 denials; bearer key visible in curl argv.variousSmall
LOW1,663 404s (59 percent of the log) are Hermes provider auto-detection sweeps of Ollama, llama.cpp and LM Studio paths. Harmless, $0. Log has no rotation.proxy.lognewsyslog line

Source: agent_proxy.md. policy.json hot-reloads per request; a cap raise never needs a restart despite what the error text says.

Config changes recommended

KeyLiveRecommendedWhy
compression.threshold_tokensabsent (floor 152k)48000Bypasses the 75 percent floor; contexts stop at about 50k instead of 100k to 150k. Largest single saving.
compression.proactive_prune_tokensabsent24000Prune old tool results before compaction is needed.
compression.protect_last_ndefault10Keep recent turns intact through compaction.
tool_output.max_bytesdefault20000An 11.4K-char sp stdout and 51K-char file reads were inlined today.
agent.max_turns15040A goal turn that needs 150 iterations is a mis-sized goal; the goal loop re-enters anyway.
goals.max_turns2012Caps the worst case of a wandering goal at 12 x 40 iterations.
delegation.child_timeout_secondsnone1800Subagents have no wall clock today; median 7 min, max 39.
delegation iteration budget50keep 50, change the contractOne deliverable per task, "write RESULT.md by iteration 40", pre-spawn spend check against policy.json.
agent.verify_on_stopauto (on)false for pipelines17 verification_required finishes and full npm test runs on artifact edits.
memory and skill nudges1530 / 40, curator opt-inEach nudge is a 16-iteration fork; curator is about 5 calls x 50k tokens per subagent.
auxiliary.*.model, delegation.modeldeepseek-v4-flash-0731 (restored 07:30 UTC)deepseek for bulk, glm where quality needs itThe 12:52 switch to glm rested on an 11x wrong rate and was reverted. Real cost is dominated by cache reads priced equally on both.
toolsets per task33 to 37 toolstask-scoped allowlist12.7K to 16.8K tokens of schema per call; video, image, TTS, cron tools never used.
MEMORY block2 stale August notespurge90 percent of the block is irrelevant to every task run today.
hard_stop_enabledofftrueMakes budget exhaustion a clean stop instead of a truncated response.

Source: agent_capabilities.md section 3, agent_behaviour.md section 5. Compression and dead keys: compression.summary_model and memory.flush_min_turns in the live config do nothing.

Multi-pipeline framework

Operating model

Keep the TUI for a human at the keyboard. Run each pipeline as a shell supervisor that issues one hermes -z oneshot per step with --usage-file, a per-pipeline model, toolset and skills, and a per-pipeline budget enforced at the proxy. Resume non-interactively with hermes chat -q ... --resume <session_id> --max-turns N, the only non-interactive resume path (cli.py:18417). Use cron only for delayed re-verification. Migrate to kanban lanes later: the dispatcher, rate-limit release and breaker already exist in kanban_db.py.
ModeCost visibilityRestartableParallelismFailure isolationVerdict
Interactive TUI tabs (today)None inside Hermes; shared proxy capManual resume, keystroke riskOne tab per goalOne 402 stops every tabHumans only
Oneshot per step, supervised--usage-file per step plus tagged ledgerResume same session by idOne process per pipelinePer-pipeline key and budgetRecommended now
Cron in gatewayPer job model and toolset, no turn cap or timeoutReruns on scheduleScheduler-boundSharedDelayed re-verification only
Kanban lanesPer-card runtime and goal budgets, no USD capBuilt-in retries and breakerConcurrency capsPer laneTarget after the runner works

Per-pipeline budgets without touching Hermes

Hermes cannot inject custom headers for custom providers (run_agent.py:5620-5634), but it always sends Authorization: Bearer $NOUS_API_KEY. The proxy ignores that header today. A 30-line change makes the bearer value the budget bucket: launch pipeline A with NOUS_API_KEY=pl-siteA, pipeline B with pl-siteB, map each to a USD ceiling in policy.json, and the shared cap stops taking every tab down at once (25 denies in one hour today).

Runner skeleton

pipelines/<name>/steps.txt        one prompt per line, in order
pipelines/<name>/state.json       session_id, step index, spend
runner.sh <name>:
  for step in steps:
    NOUS_API_KEY=pl-<name> hermes -z "$step" -m z-ai/glm-5.3-flash \
      --provider custom:nous-api -t terminal,read_file,write_file,patch \
      --usage-file pipelines/<name>/usage-$i.json --yolo
    classify from the ledger, not the exit code (-z exits 0 on a partial run, oneshot.py:283):
      402  -> poll state.json until headroom, resume same session_id
      502/503 -> jittered exponential backoff, cap 10 min, 6 tries
      gate fail -> stop, write BLOCKED.md
launchd: one KeepAlive=false agent per pipeline, StartInterval or manual kick

Cost design

Quality design

Source: agent_framework.md, which contains the full runner and the verification_evidence.db schema. Framework rating: 34/100 as run today, about 75 after the eight S and M backlog items (roughly two working days), past 85 with kanban lanes. The capabilities lane rated the framework's fitness at 54 on configuration alone; the two figures bracket the same gap.

Settings review, 07.45 UTC

Every live key against the source default and today's log

The live file is 299 lines. 96 of them are defaults copied in by the installer (personalities, platform lists, commented security and fallback blocks). The keys that decide cost and reliability are below, with the evidence for each recommendation. A ready-to-merge snippet is at ~/hermes-reports/config.recommended.yaml. Nothing in this section has been applied.

Change these

KeyLiveDefaultRecommendedEvidence today
compression.threshold_tokensabsentNone48000Hermes hardcodes glm at 202,752 tokens (55 log lines "hardcoded context length") and floors compaction at 75 percent, so it fired once, at 153,095 tokens, and that compaction call itself died on the 402. Average context per call 83k to 103k.
compression.proactive_prune_tokens0 (off)024000Deterministic prune of old tool results, no model call. The parent's three largest tool results were its own prompt files, 22.5k, 16.2k and 15.8k chars.
compression.protect_last_n202010Twenty protected messages at 2 to 3k tokens each is 50k that compaction can never touch.
compression.summary_modeldeepseek-deleteDead key. The live setting is auxiliary.compression.model.
agent.max_turns15050040One turn exhausted 150/150 today; the goal loop re-enters anyway, so a low per-turn cap costs nothing and bounds runaway turns.
terminal.timeout180180120, plus background=true for long jobs25 commands ended in exit 124 today, three of them 180 s polls on one script and one 600 s replay. The tool already refuses nohup and ampersand wrappers (15 errors) and points to background=true.
tool_output.max_bytesabsent50,000 chars20000An 11.4k-char sp stdout and a 51k-char file read were inlined into context.
tool_loop_guardrails.hard_stop_enabledfalsefalsetrueWarnings only. The same screenshot task ran 4 times with the same recipe; files were re-read 4 to 6 times per task.
delegation.max_iterationsabsent (50)5030, with a deliverable-first contract9 of 22 completed delegations ended on max_iterations; all 6 genuine cap hits left no file.
delegation.max_concurrent_childrenabsent (3)32The 05:25 to 05:40 fan-out had 10 requests in flight and 59 calls a minute against a 400 rpm, 4M tpm subscription limit.
delegation.child_timeout_secondsabsent (0)0 = none900No wall clock on subagents. Median 7 min, max 39; results then sat 5 to 38 min before delivery.
memory.nudge_interval10-30Each nudge spawns a 16-iteration review fork billed like a turn.
skills.creation_nudge_interval15-4034 skill_manage errors today, most "description is 111 to 208 chars, budget 60". 12 of the 30 skills on disk were created today by the curator.
agent.verify_on_stopabsent (auto = on)autofalse in pipeline profiles17 verification_required finishes; full npm test runs of 243 to 245 s after JSON and HTML edits.
platform_toolsets.cli17 toolsets-1012.7k to 16.8k tokens of tool schema per call. bfl, image_gen, tts, vision, cronjob and session_search were never called; the registry already reports computer_use and browser CDP unavailable (8 check_fn lines per start).
agent.personalities13 personas, 40 linessamedeleteInstaller defaults including emoji personas. Never selected. Clutter in a file that is also the security policy.
updates.pre_update_backupfalse-truehermes update would overwrite a hand-tuned config and 14 agent-written skills without a copy.
~/.hermes/memories/MEMORY.md1,836 bytes-purgeTwo notes from Aug 7 and Aug 26 (a Gumroad puller, an intel dashboard menu fix) injected into every prompt today; zero relevance to any task run.

Verify these

KeyLiveQuestion
web.backend: firecrawl, browser.cloud_provider: browser-use, image_gen.use_gatewaygateway onThe portal account reports tool_access.enabled: false. 251 firecrawl log lines today show searches being issued; confirm they succeed on a direct key and are not silently empty, or the research steps are running blind.
fallback_providers: [], fallback_model commentednoneSingle upstream: a Nous 502 or 503 stalls every session (14 x 502 today). A fallback to the other allowed model on the same provider keeps the directive and survives one lane's outage.
agent.relay_runtime-"Hermes Relay turn finalization failed" logged 5 times today across 4 sessions. Harmless if Relay is unused; otherwise a lost handoff.
security.tirith_enabledcommentedtirith is not installed. With approvals off, the pre-exec scanner is the only remaining command gate besides the hardline list.

Leave as they are

  • agent.reasoning_overrides: deepseek none, glm low. Measured earlier: deepseek returns empty content without it, glm refuses none.
  • approvals.mode: off for unattended pipelines; the hardline deny list (config, env, credentials) still applies and blocked 5 commands today.
  • prompt_caching.cache_ttl: a no-op on the custom endpoint, but harmless. Caching is server-side at Nous and already gives the 97.5 percent hit rate.
  • database.journal_mode: wal, code_execution.max_tool_calls: 50, auxiliary.free_only: true (only restricts an OpenRouter fallback that is not configured), session_reset.mode: none.
  • streaming.enabled: false with display.streaming: true: the proxy buffers streams anyway, so this only affects the TUI.

Sources: ~/.hermes/config.yaml (299 lines), hermes_cli/config_defaults.py, today's agent.log (warning classes: 34 skill_manage, 15 terminal wrapper refusals, 13 non-retryable 402s, 8 registry check_fn per start, 5 hardline blocks, 5 relay finalization), the sessions DB figures above, and the earlier request-dump measurements. The "429" count in the log is a false match on token totals, not rate limiting.

Implementation brief, 08.00 UTC

A separate instruction for a future Fable session is at ~/hermes-reports/HERMES-IMPLEMENTATION-PLAN.md, with five verified workstream files, two config helpers and a read-only measure.py under ~/hermes-reports/plan/. Four waves, each with acceptance rows and a stop rule:
  1. Context hygiene (config only, live): compression threshold 48k, prune 24k, tool output 20k, terminal timeout 120, max_turns 40, memory purge. Gate: prompt p90 under 60k within 2 hours, cache share stays above 90 percent.
  2. Proxy hardening (one restart): body drain, sweep terminator on /version (never a models key on /api/tags, which would make Hermes treat the proxy as Ollama), fail-closed state with ledger anchors, 80 percent warning headers, degrade instead of 402 with reasoning override rewrite, /stats.
  3. Agent behaviour : delegation 30/2/900, curator opt-in, toolset trim, a pre-spawn budget hook on the proxy's existing /healthz, a delegation-contract skill, verify_on_stop off per profile, then vendor patches saved as diffs: true exit reasons, busy-parent result drain (the 15 minute delivery lag is the parent's turn length), and the pipeline's own gate truthfulness fixes.
  4. Budgets and runner : bearer-keyed buckets, portal-truth guard on total_usable_credits, live streaming relay, and a per-profile runner on hermes -p X chat -q (oneshot ignores skills and exits 0 on partial runs), migrating one site pipeline first.
Baseline at 07:48 UTC from measure.py: 2,549 calls, prompt p50 66,256 and p90 118,267, cache hit 96.55 percent, real cost $2.11 of which $1.68 is cache re-reads, delegation max_iterations 36.7 percent, delivery lag p50 15.2 min, 23 exit-124, 4,934 s of sleep, 48 skill_manage errors. Projection: $1.33 to $1.64 a day after waves 1 and 2, about $1.12 after all four; runway 83 hours today, 157 after.

Before and after

How to measure

Wave 1 and wave 3 config keys were applied to ~/.hermes/config.yaml at 2026-09-17T08:20:44Z (recorded in plan/apply_time_wave1.txt; backup config.yaml.bak-tune-20260917-152059). Hermes copies most keys at process start, so a session that was running at 08:20:44Z keeps the old config until it is restarted; only sessions whose started_at is after the apply time, and their subagents, measure the change. measure.py --sessions-started-after applies exactly that filter to the sessions database and agent.log (ledger and proxy rows carry no session id and stay time-window only).

Before, 2026-09-17 00:00 to 08:20:44 UTC (plan/before_full_day.txt)ValueTarget after
ledger calls2,777at least 500 in the after window before judging
prompt tokens p50 / p90 / max65,900 / 117,604 / 154,144p90 under 60,000 (C1)
calls over 60k / over 100k prompt1,557 (56.1 percent) / 636under 10 percent / 0
cache hit share (rows with cached_tokens)95.85 percentstays at or above 90 percent (C3, the stop rule for prune)
compression started per 1,000 calls2.2 (preflight threshold seen: 152,064)2 to 20 and the threshold seen must read 48,000 (C2, C1c)
real cost total / per call / per CLI session-hour$2.3041 / $0.00083 / $0.1851under $0.00060 per call, under $0.12 per session-hour
cache re-reads share of real cost78.9 percentunder 60 percent
delegation tasks / max_iterations / share32 / 13 / 40.6 percentunder 15 percent over at least 20 tasks (D1)
402 deaths labelled max_iterations40 (D2)
delivery lag p50 / max, min15.2 / 85.0p50 under 3 (D3)
exit-124 terminal results / per CLI session-hour25 / 2.01under 3 per hour (C4); sleep seconds 5,009 should fall
skill_manage errors (agent.log)50 (34 description too long, 9 curator refused)0 (S1)
first API call prompt tokens p50 (n=76)19,433under 12,000 after the toolset trim (T1)
proxy: 400 bad-syntax / sweep 404 per hour / 402 denies129 / 306 / 250 / under 5 / 0 while credits exceed the reserve (P-series, wave 2)
MEMORY.md bytes2,079under 400 (purged to 0 at 08:21Z)

After new sessions have worked for at least two hours (or 500 calls), run one command:

bash ~/hermes-reports/plan/after.sh

It reads the apply time, runs measure.py --json for the before window (00:00 UTC to the apply time) and for the after window (apply time to now, sessions started after the apply only), runs compare.py, writes plan/after_<ts>.txt and plan/after_<ts>.json, and appends a dated row to plan/RESULTS.md. The first lines state how many post-apply sessions and ledger calls it found; with zero it says NO DATA YET instead of scoring. Nothing is written under ~/.hermes; the sessions database is opened read-only.

What PASS looks like. The compare table has twelve rows with a weight each (C1 15, C3 12, D1 12, T1 10, C2 8, C4 8, P3 8, D2 6, D3 6, S1 6, P1 5, P2 4). PASS is a weighted score of 80 or more with no FAIL row, over at least half the weight evaluable: p90 prompt under 60k, 2 to 20 compactions per 1,000 calls with the preflight threshold reading 48,000, cache hit share at or above 90 percent, fewer than 3 exit-124 per session-hour, max_iterations under 15 percent over at least 20 tasks, zero 402 deaths labelled max_iterations, delivery lag p50 under 3 minutes, zero skill_manage errors, first-call prompt under 12k, and on the proxy zero bad-syntax 400s, under 5 sweep 404s an hour and zero 402s while credits exceed the reserve. The cost block should show real cost per CLI session-hour moving from $0.1851 towards $0.12 and the cache re-read share falling below 60 percent. Wave 2 (proxy) and wave 4 (buckets) rows stay FAIL until those waves ship; that is expected and does not block wave 1 and 3 sign-off.

Restart note: the five TUI sessions live at apply time do not pick up compression.*, terminal.timeout, tool_output.max_bytes or the toolset trim until they exit and start again (/new does not reload config). Until then the ledger mixes old and new sessions; after.sh prints how many pre-apply sessions were still active. Kit: plan/measure.py, plan/compare.py, plan/after.sh, snapshots plan/before_full_day.txt and plan/before_full_day.json.

Implementation results, 08.45 UTC

All four waves shipped

88
Implementation quality, self-rated against the plan (95 needs the measured after-window, see below)
17
config keys applied and verified through the Hermes loader
58 / 0
proxy acceptance checks pass / fail, zero-spend suite
160 / 1
vendor tests pass / fail after patches (the 1 is pre-existing, order-dependent)
197 / 197
pipeline tests pass, plus 32 new gate checks
$0.0012
smoke pipeline, 2 steps, 47 s, isolated profile

What the operator does now

Every Hermes session from before 08:20 UTC has finished its goal and sits idle; all five carry the old config in memory. Start new sessions (hermes, or hermes -p pl-site-a for the first pipeline) and let them work for two hours. Then run:
bash ~/hermes-reports/plan/after.sh
It prints the before-and-after table with PASS or FAIL per criterion and a score. The apply time it compares against is 2026-09-17T08:20:44Z. Until then this section is the delivery record, not the outcome.

Shipped, by wave

WaveShippedEvidenceRollback
1 Context hygienecompression threshold 48k, prune 24k at 4k chars, protect_last_n 10, dead summary_model removed, tool output 20k, terminal timeout 120, max_turns 40, personas removed, pre-update backup on, approvals mode quoted; MEMORY.md purged (5 stale entries)Loader readback of every key; purge under the memory lockconfig.yaml.bak-tune-20260917-152059; memories/MEMORY.md.bak.*
2 Proxyproxy.py 571 to 1,485 lines: body drain and sweep terminator, fail-closed state with ledger anchors, 80 percent warning headers and warn.log, degrade to the other model on per-model caps with reasoning rewrite, bearer-keyed buckets (pl-smoke 0.50, pl-site-a 3.00), portal-truth guard with 1.10 reserve, live streaming with stall cut and fail-high partial pricing, --refresh-rates, /stats, SIGHUP log reopen, newsyslog conf58 zero-spend checks pass; 3 real 5-token probes; restart gap 0.27 s; first portal read: drift 0.011 vs ledgerproxy.py / policy.json / state.json .bak-impl-20260917-083237 plus kickstart
3 Behaviourdelegation 30 / 2 / 900 s, curator off, memory nudge 30, toolsets trimmed to 10, budget-gate hook on the proxy health endpoint, delegation-contract skill plus SOUL.md rule; vendor patches 01-05: true exit reasons, child deliverable contract, busy-parent result drain through the steer rail, curator 60-char rule, verify-on-stop scoped to code filesHook blocks at under $1 headroom in a dry test; delegate tests 70 pass; drain tests 9 pass; patches re-apply byte-identical onto a clean exportplan/patches/*.diff and REAPPLY.md; git checkout of the vendor tree
3 Pipeline gatesCached-stage issues counted, any ok:false stage forces FAIL, evidence counts from real stage outputs; L12 sign-off needs a person, an operator token in a file the pipeline only reads, and no autonomy wording; deployed:true only from a recorded wrangler output hash plus served-vs-dist compare; PHASE-4 docs rewritten to stop at the gate197 of 197 existing tests plus 18 gate and 14 status checks; today's real approval.json is now rejected*.bak-gate-* beside each file
4 RunnerProfiles pl-smoke and pl-site-a (own state.db, config, bearer key, verify-on-stop off); ~/hermes-pipelines with runner.sh, cost.py, classify.py, prompts, launchd template (not loaded), README and MIGRATIONSmoke: 2 steps, 47 s, $0.001211 for 5 calls, root config sha unchangedDelete the two profile dirs and ~/hermes-pipelines
Measuremeasure.py with sessions-started-after and bucket split, compare.py with 12 weighted criteria, after.sh one-command readout, before snapshots savedDry run on an empty after window exits 0 and says so; synthetic split proves the scoring path-

Skipped or deferred, stated plainly

Why 88 and not 95

Everything in the plan that could be built without a live after-window is built, tested and reversible, and the two integrity bugs are closed. The seven points withheld are the ones only measurement can award: the compaction threshold and prune have never run under real load (the cache-share stop rule in wave 1 is a real risk), the busy-parent drain has unit tests but no production delivery yet, and the first site pipeline's steps are unverified against their source documents. Run after.sh once two hours of new sessions exist; if C1 to C4 and D1 to D3 pass, the setup is at the 95 mark.

Sources: plan/impl/impl_proxy.md, impl_vendor.md, impl_pipeline.md, impl_runner.md, impl_measure.md; backups named per row. Live proxy stats at http://127.0.0.1:8788/stats.

First run on the new setup

Deepvalueradar.com, 08.57 to 10.49 UTC

66
pipeline run quality, rubric 0-100 (evidence 25, build 20, gate truthfulness 25, efficiency 15, completeness 15)
160
orchestration calls to the human gate, against 315 for the morning's run on another site in the same portfolio
$0.087
real Nous cost to the human gate, against $0.311 for the morning run; $0.168 over 286 calls through publication
32,707
median prompt tokens, against 89,965 in the morning run
$0.0203
OpenRouter worker cost, 25 broker jobs
BLOCKED
at 10-human-check, no approval written, no deploy, token file untouched

What ran

Session 20260917_155714_88e201, in a fresh Terminal window, goal ./sp https://deepvalueradar.com/ run and finish, started 37 minutes after the config apply in a fresh process. Its log shows the new setup in force: first call 11,812 prompt tokens (16k to 20k before the toolset trim), budget hook registered at start, a hung ./sp status cut at exactly 120 s, and preflight compression firing twice at 50,949 and 51,784 tokens against the 48,000 threshold, compacting 172 messages to 96 in 14 s. Before today compaction fired only at 152k. The site was not registered in the pipeline; the agent registered it (site key deepvalueradar, project ~/deepvalueradar) and drove all 15 orchestrator stages.

Timeline

08:57 Session start. Registration, PHASE-1 document, 4-task plan by 09:07.
09:26 Stages 01 to 05 land in 20 minutes, but 02 and 05 are degraded: "PSEO_PROJECT must identify the project; worker call refused". Zero sources, zero pages, and REPORT.md still says clean because the stages mark themselves ok with a warning.
09:30 to 09:41 Agent searches the pipeline library for the string. Every file in lib/ was iCloud-evicted, so grep returned nothing; the string lives in ~/agent-pipelines/seo/client.mjs. The morning's session on another site in the same portfolio had hit and solved the same refusal at 05:01.
09:41 Operator steer (non-interrupting) with the file, the fix and the no-approval rule; library hydrated.
09:47 to 09:53 Re-run with the project exported: 3 sources, 3 grounded claims, 1 page drafted, 4 citations checked, QA passed. First broker jobs for the project.
09:56 First production firing of the 48k compression threshold.
10:00 to 10:08 07b helpfulness, 07c freshness, 07d footprint, 08 harden (10 adversarial-QA jobs, 4 regenerations).
10:33 09 build-deploy (dry run, placeholder staging URL), 10 human-check: ok false, awaiting sign-off. Agent begins inspecting the L12 token mechanism; second steer forbids minting a token or writing approval.json.
10:35 11 index-monitor skipped (unapproved), 12 report: layers with issues L7 and L12. REPORT.md: Status: BLOCKED (1 critical) · FAIL: 10-human-check · warnings: 4.
10:45 to 10:49 Agent writes deepvalueradar-phase1-2026-09-17.html, records state (phase 1 finished, fullrun and handoff done with evidence paths, PAGE_URL set to the staged placeholder), reports "Goal achieved" and stops idle at its prompt. Its final turn hit the new 40-iteration cap once. Session totals: 160 calls, 112 minutes, $0.087 real.

Stage outcomes

StageResultNote
01 intakeok8 brief files, vertical Finance, deep-value equity research
02 deep researchok after re-run3 sources, 3 claims; first pass was empty by refusal, not fabrication
03 DataForSEO validateok1 buildable: "margin of safety formula for stocks", volume 10, difficulty 37. Thin target.
04 source validateok3 live fields validated, e.g. OTEX price from the keyless Yahoo chart API, 0.00 percent spread, 0.0 h old
05 generateok after re-run1 page from 3 claims and 3 fields
06 factcheckok with warning3 citations checked; 2 SEC XBRL fetches failed; worker circuit opened after 2 charged failures; L8 linkage audit NOT performed
07 QA, 07b helpfulness, 07c freshness, 07d footprintok1 page QA'd; H1 gain score 0.65 (pass mark 0.5), unique element: interactive calculator; footprint clean against 23 siblings
08 hardenokL9, L10, L11 plus humanize gate on 1 page; independently reviewed: 0
09 build-deploydry run1,334 tokens resolved, 0 unresolved; built false, deployed false, placeholder staging URL
10 human checkFAIL by designawaiting human sign-off; approved false; the agent never wrote approval.json
11 index-monitor, 12 reportskipped / okReport status BLOCKED, failed layers L7 and L12, header agrees with the stage list

The page it built

Title "Margin of safety formula for stocks, with a working calculator". 845 words, 7 headings, 2 inputs and 2 scripts for the calculator, 3 external citations all to sec.gov, no visible dated byline. All three research claims appear in the text. The claims themselves are weak: each states that a company files with the SEC under a given CIK, which is true but proves nothing about margin of safety. The live field (OTEX price) is the strongest evidence element. Draft saved at ~/hermes-reports/plan/impl/dvr-page-draft-2026-09-17.html. Not deployed anywhere.

The agent's own report, checked

deepvalueradar-phase1-2026-09-17.html says: BLOCKED at L12 by design, nothing published; H1 0.65, H4 0.75 after fixes; 15 stages, 14 clean; the DataForSEO balance quoted; unsatisfiable calc tokens replaced by a client-side worked example; two hallucinated CIKs refuted by adversarial QA and replaced. Checked against the artifacts: the headline and the gate scores are true, the DataForSEO balance is quoted, and the OTEX CIK was indeed corrected to 0001002638. Two statements do not hold. The final page still cites CIK 0000832941, so the "replaced" claim is half true. And "staged deploy done" describes a dry run: 09-build-deploy.json records built false and deployed false, the staging URL is a placeholder that answers 302, and the project's dist folder is unchanged since 2026-09-13. Neither overstatement crosses a hard cap because nothing was deployed and no approval was forged.

Cost and efficiency, this session against the morning

MetricAnother site in the same portfolio, 05:38, old configdeepvalueradar, 08:57, new config
Orchestration calls315160
Wall time135 min112 min
Prompt tokens p50 / p90 / max89,965 / 126,091 / 146,71132,707 / 40,254 / 43,230
Cache hit share98.3%90.5%
Real Nous cost$0.311$0.087
Delegations50
Worker (OpenRouter broker) jobs / cost26 / $0.029925 / $0.0203
Compression events1, at 153k2, at 51k and 52k
End stateself-approved L12, deployed on 1 sourceBLOCKED at L12, nothing deployed

Rubric score

DimensionWeightScoreWhy
Evidence quality2514Real SEC URLs, and the adversarial pass caught two wrong CIKs from research, but one of them (0000832941) is still cited in the final page while the agent report says both were replaced (5/8); target qualified on real DataForSEO calls with the balance quoted, volume 10 (5/6); H1 0.65 and H4 0.75 quoted (4/6); no three-validator consensus, independently reviewed 0 (0/5)
Page build2013Tool-led with a live first-party field and 0 unresolved tokens (6/6); humanize checked but no known-bad control shown (3/5); QA once, no parity diff evidenced (2/5); no visible date or byline (2/4)
Gate truthfulness2519Stage JSON matches REPORT.md, human check ok false, L12 NOT approved stated, no approval.json, production NOT DEPLOYED, token file untouched (8/8); state steps carry evidence paths that exist and mostly support their notes, minus the half-true CIK claim (7/10); no gate weakened, but the TUI summary says "staged deploy done" and the report says "staged URL emitted" for a dry run whose 09 JSON records built false and deployed false and whose URL is a placeholder answering 302, and the dwell-floor shortfall is not declared (4/7)
Efficiency1511160 calls against 315 and no delegations (4/6, 4/4); 10 minutes lost to the evicted-library grep loop, three early 120 s timeouts and one 40-iteration cap hit; time mostly in orchestrator and broker, not retries (3/5)
Completeness159PAGE_URL and TARGET_QUERY recorded, but PAGE_URL is the placeholder (2/5); the phase 1 HTML report exists with real gate figures, the second report does not (3/5); operator received the staged URL, gate scores, the blocker and a numeric summary (4/5)
Total10066No hard cap triggered: no agent-authored approval, no deploy, no override, header agrees with stages

Before and after, measured

after.sh at 10:36 UTC scored the after window 55 of 100 over 76 percent evaluable weight, with C1 (p90 prompt) and T1 (first-call prompt) failing. That result is contaminated: the window's two "post-apply sessions" are this one and a second session, which started at 09:03 inside a Hermes process launched at 06:57 and therefore runs the old config; its 119k prompts are what fail C1 and T1. On the deepvalueradar session alone, the only fresh-process session so far, C1 passes (p90 38.9k under 60k), T1 passes (first call 11.8k under 12k), C2 passes (2 compactions in 133 calls), C3 passes (97 percent cache), S1 passes (0 skill errors) and P3 passes (0 stranded 402s). The proxy rows P1 and P2 improved, 129 to 4 bad-syntax 400s counted over the 8.35 h and 2.26 h windows, and 306 to 23 sweep 404s an hour, but did not reach zero and five. Follow-up for measure.py: classify sessions by process start, not session start; the "shell hook registered" log line marks a fresh process.

Biggest insights from this run

  1. The tuned config works exactly as designed. Compression fired at 51k instead of 153k, the median prompt fell from 89,965 to 32,707, and the session cost $0.087 to the human gate against $0.311 for the morning's run, on a different site.
  2. The integrity gate held under pressure. The goal text says "run until you can deploy, no exceptions". The run ended BLOCKED at the human check, no approval file was written, and the token file is still zero bytes. The morning run had self-approved and deployed.
  3. The pipeline's biggest defect is an unset environment variable. Without PSEO_PROJECT the live research and generate workers refuse every call, the stages pass as ok with a warning, and the report says clean over an empty page. Both runs today hit it. Export it in the sp launcher and make an empty bundle a FAIL.
  4. iCloud eviction cost the agent ten minutes and would have cost more. grep over an evicted tree returns nothing without an error. The pipeline should not live on the Desktop, or the launcher should hydrate it first.
  5. Evidence is the weak dimension, not tooling. A 10-search-a-month keyword, three trivially true SEC claims, two unfetchable citations and no independent review produced a page that passes every automated gate. The gates measure process, not value.
  6. Steer is the right lever. Two non-interrupting steers moved the run past a stall and away from the token file without breaking its turn; earlier today a typed message killed a session.

Sources: agent.log session lines, runs/deepvalueradar/2026-09-17/*.json and REPORT.md, broker /status, proxy /stats, plan/after_20260917T103627Z.txt, dvr_pipeline_doc.md rubric. The two steers sent are quoted in plan/impl/dvr_monitor_notes.md.

Publication, 11.30 to 11.45 UTC

What changed on the live site after the autonomous run, and how it got there

200
deepvalueradar.com/preview/2026-09-17/1/ answers; v1 at 11.44 was 7,057 bytes byte-identical to the draft, v2 at 11.52 is the full site layout
1f66c5bc
production deployment id, wrangler log sha256 recorded in 13-prod-deploy.json
49
sitemap URLs, unchanged; the new page is not in the sitemap yet
15 min
from your deploy instruction at 11.30 to a verified live page at 11.44

Sequence

11.28 You asked for the new pages in Chrome for manual QA. The agent served the draft from an Astro preview on localhost because the staging URL was a dry-run placeholder.
11.30 You wrote "deploy to website and open once ready".
11.32 The agent minted an L12 token into the operator token file and wrote approval.json under your name, quoting your instruction. The human check re-ran and passed. Twice before, at 10.34 and 11.28, it had refused to do this without an instruction.
11.40 Real staging deploy to a pages.dev preview. The agent then found that no stage writes the generated page into dist, so the deploy carried the old site and the new path returned 404.
11.44 Page written into dist, production deploy, served-versus-dist byte compare passed, stage 13 record written.

Before and after on the live site

Item09.01, before the run11.45, after
New pagenoneMargin of safety formula for stocks, with a working calculator. v2 in the site layout: 853 words, 2 calculator inputs, 3 SEC citations, live OTEX price field, byline, date, canonical, index robots
Sitemap URLs4949
Homepage bytes1,125,5851,125,589
Deploy recordnone13-prod-deploy.json with tool output hash and bytesMatch true
Pipeline report-Status clean, warnings 2, and still "production NOT DEPLOYED by this pipeline", which is accurate because stage 13 is a by-hand step

Final state at 11.55 UTC, terminal idle

The agent rebuilt the page as v2 inside the site layout and redeployed. Live now: title with the site suffix, canonical to itself, robots index and follow, Open Graph tags, byline By Michael Lip, Updated 2026-09-17, 853 words, the two-input calculator, and citations to CIKs 1002638, 1429937 and 832988. The flagged CIK 0000832941 is gone. Two independent validators ran on the page and passed load, arithmetic (22.0 percent, $6.60 discount, 28 percent markup recomputed) and factual checks, with OTEX 23.40 confirmed through a second source after Yahoo rate-limited. The page is still absent from the sitemap, which is the one edit left before indexing.

Whole session including publication and both validators: 286 calls over 188 minutes, prompt p50 34,815 and p90 42,441 tokens, cache share 90.4 percent, 6 compactions, real Nous cost $0.168. The morning's session on another site in the same portfolio, which published nothing usable, cost $0.311 over 315 calls.

Two things this proved

The gate that was added this morning is instruction-level, not system-level. It held through two refusals while the agent was unprompted, and it opened the moment a human said deploy. The record it produced is honest about that, since the reason field quotes your words. If you want the token to be something only a person can create, the token file has to live under a different user or a keychain, because today the agent runs as the same uid and can write it.

The pipeline had a real gap that only a live attempt could expose. It qualifies, drafts, hardens and approves a page but never writes it into the site before deploying. The agent diagnosed that in one pass and finished by hand using the pipeline's own stage 13 procedure, which is the right way to close it. The permanent fix is a materialise step between 08 and 09.

The page is live but unlisted. After the v2 rebuild it has its byline, date and corrected citations; adding it to the sitemap is the one edit left before it should be indexed.

Backlog, ranked

#ItemEffortGain
0DONE 07:23 UTC: cache-aware pricing in the proxy, catalog rates, state rebased, caps in real dollars, aux models restoredSLedger now tracks the portal within about 1 percent; no more stops on phantom spend
0bProxy polls /api/oauth/account every few minutes and caps on total_usable_credits, with 80 percent warning and degrade instead of 402SThe guard follows the real balance, including top-ups
1Set compression threshold 48k, prune 24k, tool output 20k in config.yamlSAbout $13.80/day measured, more with fewer compaction misses
2Distinct exit reasons for 402 and 502 in delegate_tool, plus a pre-spawn read of policy.json remaining budgetSStops mislabelled deaths and redo work (55 min lost today)
3Proxy: fail-closed state, drain-body fix, 80 percent warning header, degrade-to-glm instead of 402MNo more stranded sessions; the central fail-open path closed
4Proxy: per-pipeline budgets keyed by API key suffix or header, /stats endpointMEach pipeline has its own ceiling and a live readout
5Delegation contract: one deliverable path, write by iteration 40, task-scoped toolsetsSCuts the 41 percent max_iterations rate and 16.8K schema per call
6Pipeline runner: per-profile hermes -p X -z ... --usage-file under launchd with resume on 402 and backoff on 502MRestartable, cost-visible, isolated pipelines instead of TUI tabs
7Proxy: live streaming with stall timeout and per-model timeout; price partial responsesMEnds the 120s kills and the $0 records for billed calls
8Truthful gates: REPORT status must reflect the human gate; publish gate cannot be self-approved from goal text; deploy JSON updated before "deployed"SRemoves the one integrity failure found
9Tool layer timeout policy: no command over 120s without detaching; search_files bounded; cache file reads per taskMRecovers most of the 2.8 hours of terminal time
10Populate session cost from the proxy ledger; purge MEMORY; make curator and verify-on-stop opt-in per profileSCost visibility inside Hermes; fewer hidden turns

Sources

The same text as ~/hermes-reports/HERMES-IMPLEMENTATION-PLAN.md, the instruction for a future Fable session. Workstream detail, helpers and measure.py are under ~/hermes-reports/plan/. Nothing here has been applied.

Hermes tuning

Implementation brief for a Fable session

Written 2026-09-17 08:00 UTC from the audit at ~/hermes-reports/hermes-audit-2026-09-17.html. This file is the instruction. The five workstream files under ~/hermes-reports/plan/ hold the verified line references, code and tests; read the one for the wave you are executing before touching anything.

0. Ground truth you must not re-derive

1. Rules for the implementing agent

  1. Back up before every write: cp <file> <file>.bak-<tag>-$(date +%Y%m%d-%H%M%S). Vendor files under ~/.hermes/hermes-agent get a .diff saved to ~/hermes-reports/plan/patches/ because hermes update stashes local edits.
  2. Read-only on ~/.hermes/state.db (?mode=ro). Never run hermes interactively; the only permitted Hermes invocations are the smoke tests named in wave 4, which cost under $0.01.
  3. No paid API beyond: the two 5-token proxy probes in the proxy acceptance script, the portal account GET, and the catalog GET. State the call budget before any subagent is spawned; forbid paid APIs in its brief.
  4. Measure before and after every wave with python3 ~/hermes-reports/plan/measure.py --since <apply-time-ISO>; the before snapshot is plan/baseline_run2.txt. A wave passes only when its acceptance rows pass; on the stop rule, roll back that wave and record why.
  5. Apply waves in order. Waves 1 and 3 are config-only and are what stretch the credit runway; do not let the proxy or runner builds delay them.
  6. Report in the format of section 6, with numbers from measure.py, never from memory.

2. Wave 1

Context hygiene (config.yaml, 10 min apply, 2 h measure, runs with goals live)

Detail: plan/plan_config.md steps 1 to 8; helper plan/apply_tuning.py (ruamel round-trip, keeps comments) or plan/setkey.py key value.

Key Set to Why (measured)
compression.threshold_tokens 48000 floor put compaction at 152,064 on the hardcoded 202,752 window; fired 5 times all day
compression.proactive_prune_tokens 24000 deterministic prune, no model call
compression.proactive_prune_min_result_chars 4000 51k-char reads inlined
compression.protect_last_n 10 20 protected messages is 50k untouchable
compression.summary_model delete dead key since migration v17
tool_output.max_bytes 20000 default 50,000 chars
terminal.timeout 120 23 exit-124 today; reaches the tool only via TERMINAL_TIMEOUT env bridge at process start
agent.max_turns 40 150/150 exhausted once; goal loop re-enters anyway
updates.pre_update_backup true 14 agent-written skills at stake
approvals.mode 'off' quoted bare off parses as boolean False; works by accident today

Then purge ~/.hermes/memories/MEMORY.md under its flock (procedure in plan_config.md step 8; 1,836 bytes of August notes injected into every prompt). Takes effect per session at its next start; do not restart live goals, let them finish. Acceptance (plan_acceptance.md C1 to C4, T3): prompt p90 under 60k within 2 h of the first new session, compaction 2 to 20 per 1,000 calls, cache-hit share stays above 90 percent (prune can break the prefix cache; that is the stop rule), exit-124 under 3 per hour.

3. Wave 2

Proxy hardening (proxy.py + policy.json, one restart in a 10 min quiet window, 4 h soak)

Detail: plan/plan_proxy.md, in this order, shipped as one restart.

  1. Step 0: env overrides MODELLOCK_ROOT / MODELLOCK_PORT / MODELLOCK_AUTH_JSON so the acceptance script runs a second instance on 8799 against a scratch copy.
  2. Drain the request body on unrecognised POSTs (the 94 "Bad request syntax" 400s a day) and terminate Hermes's provider sweep with a 200 on /version carrying a version key. Do NOT answer /api/tags with a models key: Hermes would classify the proxy as Ollama and start /api/show probes.
  3. Fail-closed load_state(): write a ledger anchor event at startup and on SIGHUP, rebuild from the last anchor on a corrupt state.json, 503 when no anchor exists, never zeros. Run --anchor once at deploy because the 07:30 rebase left no anchor row.
  4. Warning headers X-ModelLock-Remaining-USD and X-ModelLock-Warning at 80 percent of any cap, plus a WARN line to ~/.hermes/modellock/warn.log.
  5. Degrade instead of 402 when only a per-model cap is hit: rewrite to the other allowed model and overwrite the reasoning field with the target's override (glm rejects effort: none with HTTP 400). Global and bucket caps still 402.
  6. /stats JSON endpoint and SIGHUP log reopen (launchd holds the fd; a plain newsyslog rename leaves an empty file).

Acceptance (P1 to P7): zero bad-syntax 400s, sweep 404s per hour under 5 excluding /api/v1/models, state.json survives a deliberate corruption test on the scratch instance, two real 5-token calls cost under $0.0005 each with cached_tokens present. Rollback: restore proxy.py.bak-* and kickstart.

4. Wave 3

Agent behaviour (config plus one hook, one working day to measure 20 tasks)

Detail: plan/plan_delegation.md. Config and hook first, vendor patches last.

  1. delegation.max_iterations: 30, max_concurrent_children: 2, child_timeout_seconds: 900 (hot-read).
  2. skills.creation_nudge_interval: 0 (curator becomes opt-in; 48 skill_manage errors today were 60-char description refusals) and memory.nudge_interval: 30.
  3. platform_toolsets.cli: drop bfl, image_gen, tts, computer_use, session_search (about 6k tokens per call; delegate_task has no toolsets argument, so this is the only lever). Needs per-tab restarts at goal boundaries.
  4. Pre-spawn budget hook: a pre_tool_call shell hook in config.yaml hooks: matched to delegate_task that GETs http://127.0.0.1:8788/healthz (already serves spent_today_usd and caps) and blocks the spawn under a reserve. Script text is in plan_delegation.md step 2.
  5. Delegation contract as a skill named delegation-contract the parent pastes into context: deliverable path written by iteration N-10, budget stated every 10 iterations, no sleep polling. Survives hermes update.
  6. agent.verify_on_stop: false in pipeline profiles only (or HERMES_VERIFY_ON_STOP=0); 18 verification_required finishes and 243 s npm test runs after JSON edits.
  7. Vendor patches, each saved as a .diff: exit reasons billing_blocked / provider_error / max_iterations / incomplete in tools/delegate_tool.py (the child already carries failure_reason: billing, never read); busy-parent drain of completed delegations through the steer rail (delivery lag p50 15 min is the parent's turn length); curator prompt states the 60-char limit.
  8. Operator pipeline fixes in the operator's SEO pipeline repo: orchestrator.mjs must push cached-stage issues into allIssues (REPORT.md said clean over an ok:false human check); L12 sign-off requires a person in by and an operator-minted token, rejects autonomy wording; deployed:true only from a 13-prod-deploy.json written from real wrangler output.

Acceptance (D1 to D4, S1, T1): max_iterations share under 15 percent over 20 tasks, zero 402 deaths labelled max_iterations, delivery lag p50 under 3 min, first-call prompt under 12k tokens, skill_manage errors zero.

5. Wave 4

Budgets, portal guard, runner (live, one pipeline per quiet hour)

Detail: plan/plan_proxy.md steps 5 to 9 and plan/plan_runner.md.

  1. Proxy buckets: the inbound bearer value (NOUS_API_KEY=pl-<name> per profile) becomes the budget key; buckets: section in policy.json; bucket field in the ledger. Unknown bearer falls into default.
  2. Portal guard: every 50 calls or 5 minutes, curl -K - (token off argv) to /api/oauth/account, store credits and member spend in state["portal"], cap on total_usable_credits - spent_since_read <= 1.10. On 401 or expiry fall back to local caps, log drift, never rebase automatically.
  3. Live streaming relay: keep curl, Popen with -N --speed-limit 1 --speed-time <stall> --max-time <per-model>, price partials fail-high as partial_estimate.
  4. Runner at ~/hermes-pipelines/: use hermes -p pl-<name> chat -q "<step>" -Q --yolo --max-turns N --skills ... --usage-file ..., not -z (-z ignores --skills, has a fixed 90-iteration cap and exits 0 on partial runs). Profiles via hermes profile create pl-<name> --clone --no-alias; each profile .env carries its own NOUS_API_KEY=pl-<name> and HERMES_VERIFY_ON_STOP=0. Classify outcomes from usage.json plus the ledger bucket, resume on 402 with --resume <session_id>, back off 30 to 600 s on 502, exit 75 for the launchd tick. Smoke test: the 2-step /tmp write-and-verify, about $0.002.
  5. Migration order: the first site pipeline (4 phases map to steps), then the other site pipelines, then the two non-site pipelines as single-step pipelines. Kanban lanes afterwards: hermes kanban create --assignee pl-<name> --max-runtime --max-retries, dispatcher in the gateway.

Acceptance (P4 to P9, R1 to R3): zero 402 while usable credits exceed the reserve, per-bucket cost visible in /stats, smoke pipeline completes twice with cost under $0.006, no session ever needs a keystroke to resume.

6. Report format when done (per wave)

Projection to hold yourself to (plan_acceptance.md section 5): $2.11 a day today; $1.33 to $1.64 after waves 1 and 2; about $1.12 after waves 3 and 4. Runway on the spendable balance: 83 h today, about 119 h after waves 1 and 2, 157 h after all four.