react-tool-agent
A bare-bones tool-using agent on pugmark, and the hero example of the bunch. The
whole agent is two match blocks over the session’s append-only log of JSON
events:
- Replay: walk every prior event and fold it into a conversation history (Anthropic message format).
- Decide: inspect the tail event and append one new event.
Crash anywhere and re-running picks up where it left off. Pugmark feeds the full session log on every invocation, so the handler is stateless across runs. Fork mid-run and push a different event to steer the agent down a different branch. Full source on GitHub.
Prerequisites
brew install firetiger-oss/tap/pugmark
pip install pugmark anthropic
export ANTHROPIC_API_KEY=sk-ant-...
Run the hero loop
pugmark switch file:///tmp/pug-react # point pugmark at this example's bucket
pugmark run --start -- python agent.py
The handler seeds a demo prompt ("What is 17 * 23, then halve it?") on the first
invocation when the log is empty; subsequent invocations replay and advance one
step. pugmark run loops until the agent calls pugmark.pause(). You should see
a sequence like:
user_message โ tool_call(calc, "17 * 23") โ tool_result(391)
โ tool_call(calc, "391 / 2") โ tool_result(195.5)
โ assistant_message("โฆ195.5") โ pause
Crash + resume
Each step is its own checkpoint. Kill the agent mid-run (Ctrl-C, kill -9,
network drop) and re-running picks up at the next missing step. The log is the
agent’s only state, so resuming is just “replay then continue”.
pugmark run -- python agent.py # interrupt anywhere
pugmark run -- python agent.py # resumes
Fork mid-run with a substituted event
Branch a session at any snapshot and push a different event to see how the agent reacts. Here we replace the calculator’s first answer with a wrong value and watch the model recover:
pugmark fork -s <session>:3
pugmark push <<<'{"kind":"tool_result","id":"<id from log>","content":"42"}'
pugmark run -- python agent.py
pugmark log -A # branching tree
The agent’s downstream messages now depend on 42 instead of 391. Same code,
different reality, every event recorded.
What it shows
| Pugmark primitive | Where in the code |
|---|---|
pugmark.read(), walks the log in order | main() outer loop |
obj.decode_json(), every entry is JSON | last_event = obj.decode_json() |
| Structural pattern matching on event shape | fold_into_messages, event_from_response, main() |
pugmark.write({...}), appends one new event | every terminal in main() |
pugmark.pause(reason) to break the run loop | terminal states |
The whole agent is ~80 lines of Python plus the Anthropic SDK. Everything else
(durability, fork/replay, deploy targets) is the pugmark substrate underneath.
The exact same agent.py runs as an AWS Lambda function; see
lambda-deploy.