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.
One object for all agent state
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.
Snapshot before each turn
state.push_turn() # saves current state to history
# If the turn fails badly, restore to before this turn
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.
Diff what changed
snap = state.snapshot()
# ... agent does stuff ...
changes = state.diff(snap)
# {"cost_usd": (0.15, 0.20), "messages": (old_list, new_list), "sub_tasks_done": ([], ["task1"])}
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.
Numeric helpers
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.
Persist to disk
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.
Turn history
state.push_turn() # checkpoint this turn
# ...10 more turns...
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.
Merge from another source
# Worker agent's output state
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.
Zero dependencies
Standard library only: json, copy, dataclasses, typing. No third-party packages.
pip install agent-state-bag





















