# Frameworks, state, and when not to use an agent AI for Software Engineers, part 5.3 (13 of 22) > A framework gives you building blocks, a harness runs the loop and a runtime keeps it alive; checkpoints and durable execution decide what survives a crash so side effects like payments don't run twice. Start with plain code and reach for a framework only when you need checkpoints, interrupts and resume. You've probably done this with Claude Code. You start a long task, close the laptop, and come back the next morning. You run `claude --continue`, and it picks up the conversation where you left it. Nice. Nobody thinks twice about it. Now picture your own agent. It's processing a refund. It has looked up the order, called the payment API, and is about to email the customer when the pod gets restarted. Your job runner sees a failed job and starts it again. So what survives? Does it know the refund already went through? Or does it pay twice? Before we answer that, a word about the tools that promise to handle it for you. **Framework, harness, runtime** Once you decide to build your own agent, you'll find a crowded shelf of frameworks, with more every month. It helps to separate three words. A framework is a library. It gives you building blocks for the loop, the tools and the control flow, so you don't write them from scratch. As of October 2026, two I'd look at first are LangGraph, which describes itself as a low-level orchestration framework and runtime for long-running, stateful agents, and Microsoft Agent Framework, which reached 1.0 in April 2026 and brings together what Microsoft previously had in Semantic Kernel and AutoGen. The harness, from article 01b, is what you end up with: your prompts, your tools, your rules about what runs. A framework helps you build a harness. It doesn't hand you one. You own it either way. A runtime is where the thing actually runs and keeps its state between steps. Sometimes it's your own process plus a database. Sometimes it's managed. Anthropic's Claude Managed Agents, for example, is a pre-built harness that runs in Anthropic's infrastructure, with sessions that keep history and a sandbox on the server side. It's in beta as I write. You trade control for not having to run the loop, the sandbox or the storage yourself. ![Layer diagram of a governed agent harness with lifecycle hooks and runtime controls between a framework and tools.](assets/09-agent-harness-lifecycle.png) *The harness is where model behavior becomes controlled runtime behavior.* You'll also hear "graph" a lot. Don't let it sound exotic. A graph here is a state machine. Nodes are steps (call the model, run a tool, ask a human), edges say what comes next, and a shared state object travels through it. Both LangGraph and Microsoft Agent Framework's workflows work this way. If you've drawn an order lifecycle as states and transitions, you've already done this. Here's roughly how I'd choose. | If you need | Reach for | |---|---| | A short task inside one request, one provider | that provider's SDK, or plain code | | Long runs, pause and resume, human approvals | a framework with checkpointing (LangGraph, Microsoft Agent Framework) | | An agent without running the loop and sandbox yourself | a managed runtime, if the data rules allow it | | Strict steps that must finish no matter what | the workflow engine you already trust | Honestly, the framework matters less than people think. I ran the same governance patterns on LangGraph and Microsoft Agent Framework and wrote about it in [Your Framework Choice Matters Less Than You Think](https://www.allsrc.dev/posts/your-framework-choice-matters-less-than-you-think/). **State, checkpoints, durable execution** Back to the refund. In article 02a we saw the model API is stateless. Your app keeps the history. An agent run is the same, only longer. If the state lives only in memory, a crash loses it. So the frameworks save it. LangGraph's checkpointer writes a snapshot of the graph state after each step, grouped under a thread ID. Microsoft Agent Framework does the same at the end of each step in its workflows. On a restart, you load the last checkpoint and carry on. If you know databases, it's the write-ahead log idea. Write down where you are before you move on, so recovery is a replay. Human approval works the same way. In LangGraph you call `interrupt()` inside a step. The state is saved and the graph waits, for hours if it has to, until someone answers. Then you resume it with their answer. An approval is just a pause with the state on disk. ![Steps one and two each end with a saved checkpoint, then step three runs. If the pod restarts during step three, the run loads the last checkpoint and step three runs again.](assets/05b-checkpoints.svg) *What survives a crash, and which step runs again?* Now the catch. What do you think happens to the step that was running when it crashed? It runs again. LangGraph's docs say that when you resume after an interrupt, the node restarts from the beginning, so any code before the interrupt runs again. Crash recovery works the same way. Checkpoints make resume cheap, and they do nothing to stop a payment from going out twice. That's at-least-once execution, the same thing you deal with in any message queue. So anything with a side effect, like paying, emailing or creating a ticket, needs an idempotency key, and you record the intent before you do the effect. I wrote this up in [The Retry That Paid The Invoice Twice](https://www.allsrc.dev/posts/pattern-durable-execution/). If you need stronger guarantees than a framework's checkpointer, there are durable execution engines built just for this. Temporal is the well-known one. It records an event history for each workflow so it can resume after crashes and outages. One security point. A checkpoint holds the whole conversation, tool results and all. Microsoft's docs call checkpoint storage a trust boundary, and I'd treat it like any database with customer data in it. **Context inside your own harness** When you use Claude Code, the harness handles context for you. In your own harness, that's your job now. In 03b we had prune, summarise and persist, and LangChain's four words: write, select, compress, isolate. Write things that must survive to a file or store. Select only what this step needs, like the two relevant files instead of the whole repo. Compress old turns and big tool results, or offload a large result to a file and keep only the path. Isolate noisy work in a subagent with its own context. Managed harnesses and provider APIs will compact for you, which is fine until you need control over what the summary keeps, like the fact that a human said no. More on that in [Context Rot: When Your Agent Forgets It Was Denied](https://www.allsrc.dev/posts/pattern-context-compaction/). **When not to use any of this** So when shouldn't you use an agent framework? Or an agent at all? If one model call does the job, make one model call. Classifying a ticket, extracting fields from a document, drafting a summary. A function and a retry are enough. If the steps are known, write them as plain code. You'll debug it with the tools you already have. If your company already runs a workflow engine or a durable job queue, put the model calls inside it as steps. You get retries, monitoring and on-call runbooks that already work. Frameworks also cost you something. They change fast, they add their own abstractions over the model APIs, and when something goes wrong you end up reading their source to find out what was actually sent. That's a leaky abstraction, and moving off one later is real work. My rule is simple. Start plain. Reach for a framework when you genuinely need checkpoints, interrupts and resume, and not before. Next, when the answers aren't good enough: do you change the model, or change the context? ## Common questions ### What is durable execution for AI agents? It is what lets a long agent run survive a crash or restart and carry on. Frameworks save a checkpoint of the state after each step, so a restart loads the last one, much like a write-ahead log. For stronger guarantees there are durable execution engines like Temporal, which record an event history for each workflow. ### Do LangGraph checkpoints stop a step from running twice? No. The step that was running when it crashed runs again from the beginning, and LangGraph's docs say the same about resuming after an interrupt. That is at-least-once execution, so anything with a side effect, like paying or emailing, needs an idempotency key, and you record the intent before you do the effect. ### Agent framework vs harness vs runtime: what's the difference? A framework is a library of building blocks for the loop, the tools and the control flow. The harness is what you end up with, your prompts, tools and rules about what runs, and you own it either way. A runtime is where it actually runs and keeps its state between steps, either your own process plus a database or a managed service. ### When should you not use an AI agent framework? When one model call does the job, or the steps are known and plain code will do. If your company already runs a workflow engine or a durable job queue, put the model calls inside it as steps. Frameworks change fast and add their own abstractions, so start plain and reach for one when you need checkpoints, interrupts and resume. ## References - LangGraph persistence (https://docs.langchain.com/oss/python/langgraph/persistence) - What is Temporal? (https://docs.temporal.io/temporal) - Context engineering for agents, LangChain (https://www.langchain.com/blog/context-engineering-for-agents)