๐พ pugmark
The durable agent runtime built on object storage.
Pugmark treats an agent’s history the way Git treats a codebase. Every step the agent takes becomes a JSON event appended to a session log in object storage. From any point in that log you can branch a run, replay it exactly, or read the whole trajectory back as a plain list of events.
The handler stays stateless. On every invocation pugmark hands it the whole log;
it replays the log, decides one next event, appends it, and exits. The same
script runs locally under pugmark run, or on AWS Lambda and GCP Cloud Run.
Bring your own model, your own tools, your own framework. Pugmark sits
underneath, recording what happened so you can replay it or branch it later.
Because the handler is stateless and the log lives on object storage, pugmark gives you durable execution. An agent that crashes mid-step, gets killed when Lambda times out, or hits a rate-limit wall doesn’t lose its work and doesn’t give up: the next invocation sees the full prior trajectory and picks up from the first missing step. The resilience is a property of the data, not of any process that happens to be alive.
Install
brew install firetiger-oss/tap/pugmark
Quickstart
A session is an append-only log of JSON events. On every invocation pugmark feeds your handler the whole log; it replays the log, decides one next event, appends it, and exits. Here’s a complete chat agent:
# agent.py
import pugmark, anthropic
events = [o.decode_json() for o in pugmark.read()]
messages = [{"role": e["role"], "content": e["text"]} for e in events]
match events[-1]["role"] if events else None:
case "user":
reply = anthropic.Anthropic().messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
messages=messages,
)
pugmark.write({"role": "assistant", "text": reply.content[0].text})
case _:
pugmark.pause("your turn")
Push a message and run it:
pugmark start
pugmark push <<<'{"role":"user","text":"name three primes"}'
pugmark run -- python agent.py
pugmark log
pugmark run loops the handler until it pauses. Every event is a checkpoint, so
re-running after an interruption just replays the log and picks up where it left
off.
Fork the conversation and take it a different direction:
echo '{"role":"user","text":"now name three even ones"}' > turn.json
pugmark fork turn.json # branch from here, seeded with a different question
pugmark run -- python agent.py
pugmark log -A # the branching tree
That’s the whole model.
Where to next
If you want the reasoning behind the design, start with the concepts. When you need the precise version, the handler protocol and storage layout are written out in full. The examples run from a no-dependency smoke test up to the same agent deployed on Lambda, and there’s reference for the command-line tool and the Python and Go SDKs when you’re building your own handler.