cd /news/ai-agents/i-replaced-200-lines-of-ad-hoc-state… · home topics ai-agents article
[ARTICLE · art-13869] src=dev.to pub= topic=ai-agents verified=true sentiment=↑ positive

I replaced 200 lines of ad-hoc state management in my Hermes agent with one object.

A developer replaced 200 lines of ad-hoc state management in a Hermes research agent with a single `StateBag` object. The object wraps a dictionary with features for snapshotting, diffing, incrementing, and saving state, enabling rollback on failure and turn-by-turn replay. The solution uses only Python standard library modules and is available as the `agent-state-bag` package.

read2 min publishedMay 25, 2026

This is a submission for the Hermes Agent Challenge.

My Hermes research agent was tracking state across 20+ variables. Turn counter. Running cost. Message history. Sub-tasks done. Sub-tasks pending. Errors per tool. Each was a standalone variable at the top of the loop, updated individually, saved separately, and restored manually after a crash.

By turn 47, the state management was 200 lines of ad-hoc code spread across the loop. I replaced it with one object.

from agent_state_bag import StateBag

state = StateBag({
    "turn": 0,
    "cost_usd": 0.0,
    "messages": [],
    "sub_tasks_done": [],
    "errors": 0,
})

for turn in range(1, 50):
    state["turn"] = turn
    state.increment("cost_usd", 0.05)
    state.increment("errors") if tool_failed else None

    response = call_llm(state["messages"])
    state["messages"].append({"role": "assistant", "content": response.text})

StateBag

is a dict wrapper with extra features. It passes through all the dict methods you expect, plus the things a long-running agent actually needs.

state.push_turn()   # saves current state to history

state.reset_to(state.last_snapshot())

At the start of each turn, push a snapshot. If something goes catastrophically wrong mid-turn, you can roll back to the clean state before that turn started.

snap = state.snapshot()


changes = state.diff(snap)

I log the diff to my trace file at the end of each turn. When reviewing a run, I can see exactly what each turn changed — without comparing full state snapshots manually.

state.increment("turn")               # += 1
state.increment("cost_usd", 0.05)     # += 0.05
state.decrement("retries_left")       # -= 1

Returns the new value. Initializes to 0 if the key is missing.

state.save("state.json")
state = StateBag.load("state.json")

Plain JSON. Grep-able, inspectable, resumable. I save state after every successful turn. On crash, StateBag.load

restores exactly where I was.

state.push_turn()    # checkpoint this turn
state.history        # list of all saved snapshots
state.turn_count     # 11
state.last_snapshot() # most recent snapshot

The history grows across the run. After the run, I can replay it to see how state evolved turn by turn.

state.merge(worker_output)   # other wins on conflict; deep-copied

In my multi-agent setup, workers return their results as dicts. The supervisor merges them into its own state.

Standard library only: json

, copy

, dataclasses

, typing

. No third-party packages.

pip install agent-state-bag
── more in #ai-agents 4 stories · sorted by recency
── more on @hermes 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/i-replaced-200-lines…] indexed:0 read:2min 2026-05-25 ·