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

> Source: <https://dev.to/mukundakatta/i-replaced-200-lines-of-ad-hoc-state-management-in-my-hermes-agent-with-one-object-24fa>
> Published: 2026-05-25 21:21:08+00:00

*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.

``` python
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

# 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.

```
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.

```
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
# ...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.

```
# 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.

Standard library only: `json`

, `copy`

, `dataclasses`

, `typing`

. No third-party packages.

```
pip install agent-state-bag
```


