Building Agentic Workflows with Claude Code

I run Claude Code as the execution layer behind several of my autonomous systems, including the content and SEO machine that powers BizFlowAI ContentStudio. It writes, refactors, publishes, and cleans up after itself while I sleep. What surprised me over the last year is how much of the reliability came from workflow design, not from smarter prompts. Below are the patterns I keep reaching for, and the ones I stopped using after they burned me.
Why Claude Code became my default execution layer
Most agent frameworks give you an orchestrator that pretends to hold state. Claude Code gives you a shell, a filesystem, a real editor loop, and a model that can plan across many tool calls without losing the thread. That combination matters more than people admit. When an agent needs to read a config, run a script, inspect the output, patch a file, and re-run, you want the environment to be the source of truth, not a JSON blob in memory.
For me the practical wins are three: long-horizon tasks stay coherent past 40 or 50 tool calls, subagents can be spawned for isolated work without polluting the parent context, and failures leave real artifacts on disk that I can inspect the next morning. That last point is what makes unattended runs possible at all. If your agent only exists in RAM, you cannot debug it after the fact.
I still use LangGraph and my own orchestrators for hard-typed pipelines. But when the work involves code, files, shell, and judgment, Claude Code is where I go first.
Pattern 1: The plan file as durable memory
The single highest-leverage habit I picked up is forcing the agent to write and update a plan file on disk. Not the internal todo list. An actual PLAN.md in the working directory that persists across sessions, restarts, and human interventions.
Here is the shape I use:
# Task: Publish weekly SEO brief for cluster "RAG in production"
## State
- [x] Pull last 7 days of GSC data for cluster
- [x] Cluster queries by intent (informational / commercial)
- [ ] Draft brief with 3 candidate H1s <-- current
- [ ] Score against existing posts (cannibalization check)
- [ ] Write final brief to /briefs/YYYY-MM-DD.md
## Notes
- GSC export at /tmp/gsc-2026-07-20.csv
- Skip "AI agents" head term, already covered
- Cannibalization threshold: cosine > 0.82 against embeddings/posts.jsonl
The rule I give the agent is simple: before any non-trivial tool call, read PLAN.md; after any state change, update it. This costs maybe 200 tokens per loop and buys me the ability to kill a run, restart it two hours later, and have it pick up exactly where it left off. It also gives me a diff to review when something goes sideways.
If you take one thing from this post, take that one.
Pattern 2: Tool orchestration by capability, not by API
Early on I made the mistake of exposing tools that mirrored the underlying APIs: create_post, update_post, delete_post, get_post_by_slug, and so on. The agent would happily call three of them in the wrong order and leave a half-published draft.
The fix was to design tools around capabilities the agent actually reasons about, and hide the sequencing inside them. Instead of five WordPress endpoints, I expose one publish_brief(slug, markdown, metadata) that internally handles idempotency, slug conflicts, image uploads, and category mapping. The agent thinks about "publish this thing" and the tool handles "how".
A rough hierarchy I keep in mind:
| Layer | Example | Who owns the retry logic |
|---|---|---|
| Raw API | wp.posts.create |
Nobody uses this directly |
| Capability | publish_brief(...) |
Tool, with idempotency key |
| Workflow | weekly_publish_cycle() |
Agent, via plan file |
The agent should live at the workflow layer. It should never see raw APIs unless you are explicitly asking it to write integration code.
A second rule I enforce: every capability tool returns a structured result with status, artifact_path, and next_hint. The next_hint is optional freeform text the tool can use to nudge the agent (for example, "post created but featured image failed, run attach_image before announcing"). It sounds minor. In practice it cut my error-recovery loops roughly in half.
Pattern 3: Error recovery that does not spiral
The failure mode I see most often in agentic workflows is the death spiral: something breaks, the agent tries to fix it, that fix breaks something else, twenty tool calls later you have a mess and a burned context window.
Three guardrails I always add:
1. A retry budget per tool, not per task. Each capability tool tracks its own attempt count in a small state file. On the third failure of the same tool with the same arguments, the tool refuses to run and returns a blocked status. The agent is instructed to treat blocked as a signal to escalate, not to try harder.
2. A "diagnose before you patch" prompt. When any tool returns an error, the agent's system prompt requires it to:
- Read the full error output
- Write a one-paragraph hypothesis to
PLAN.md - Only then propose a fix
This sounds like ceremony. It stops the agent from reflexively adding try/except around everything or deleting files it does not understand.
3. A hard budget on tool calls per phase. I set numeric limits like "no more than 15 tool calls in the drafting phase" and enforce them by having the agent count in the plan file. When it hits the limit, it stops and writes a status report. I would rather review a half-finished run at 8am than find out at noon that it burned through my Claude API budget looping on a broken regex.
For unattended runs, the escalation path is a message to a Slack channel and a JSON snapshot of the plan file plus recent tool outputs to S3. In practice I check it once a day and clear stuck jobs in a few minutes.
Pattern 4: Subagents for isolation, not for cleverness
Claude Code lets you spawn subagents. It is tempting to use them to parallelize everything. Do not.
The rule I converged on: spawn a subagent only when you need context isolation, not when you need speed. The main cases where it earns its keep:
- Research spikes. When the agent needs to grep through a large codebase or read fifty files to answer one question, a subagent can do that and return a summary without polluting the parent context.
- Risky refactors. A subagent can experiment on a branch, and if it fails, the parent never saw the failed attempts.
- Untrusted content. If the agent is processing scraped web content, I run the extraction in a subagent so any prompt injection lives and dies in that isolated context. This one matters more every month.
What I do not do: use subagents to run steps of a linear workflow in parallel. The coordination overhead almost always costs more than it saves, and debugging becomes painful. If two things truly are independent, run them as separate top-level jobs, not as siblings under one parent.
Pattern 5: The unattended run checklist
An unattended run is not a normal run with the human removed. It is a different animal, and I treat it that way. Before I let any Claude Code workflow run overnight, it has to pass this list:
- Idempotency. Every capability tool must be safe to call twice with the same input. I usually implement this with a content-hash key. If the same brief hash arrives twice, the second call is a no-op.
- A dry-run mode. The whole workflow can run end-to-end with side effects disabled. I use this to test prompt changes without publishing junk.
- Structured logging. Every tool call writes a JSONL record with timestamp, tool, args hash, status, and duration. I feed this into a small dashboard, but even
grepon the file catches most issues. - A kill switch. A
HALTfile in the working directory that the agent checks at the top of every loop. If it exists, the agent writes a final status and exits cleanly. This has saved me from myself more than once. - A budget. Hard caps on tool calls, wall-clock time, and API spend. Enforced by the runner, not by the agent's good intentions.
- A post-run report. At the end of every run, the agent writes a short report to
runs/YYYY-MM-DD-HHMM.mdsummarizing what it did, what it skipped, and what needs human attention. This is the artifact I actually read in the morning.
The content loop that powers my own site follows this exact template. It runs on a schedule, produces a report, and only pings me when something is genuinely stuck. That is what "autonomous" looks like in practice: not zero human involvement, but human involvement that scales sub-linearly with volume.
A real prompt fragment
I get asked for prompts often. Here is a lightly edited slice of the system prompt for the publishing agent in my content loop. It is not clever. That is the point.
You are the publishing agent for the content pipeline.
Rules:
- Read PLAN.md before every non-read tool call.
- Update PLAN.md after every state change. Never delete history, only append.
- Never call a capability tool with args you have not first written into PLAN.md
under "Next action".
- On any tool error, do NOT immediately retry. Write a hypothesis paragraph to
PLAN.md under "Incidents", then propose ONE fix and try it.
- If the same tool fails 3 times with the same args, stop and write "BLOCKED:"
followed by what a human needs to do.
- Check for a HALT file at the top of every loop. If present, write a final
status to PLAN.md and exit.
- You have a budget of 40 tool calls for this run. Track the count in PLAN.md.
Style:
- Prefer capability tools over shell.
- Use shell only for read-only inspection or when a capability tool does not exist.
- Never edit files under /published/ directly. Use publish_brief.
The strict tone is deliberate. Claude Code responds well to explicit, enumerated rules, and it holds them across long runs. Loose "please try to" language degrades faster than I would like.
What I would do if you are starting now
If you are building your first serious agentic workflow with Claude Code, here is the shortest path I would take:
- Start with one boring workflow you already do by hand. Not something ambitious. Something you understand cold, so you can tell when the agent is wrong.
- Design your capability tools before you write any prompts. Half the reliability of the system lives in the tool boundaries.
- Use the plan file from day one. Retrofitting durable state later is painful.
- Instrument before you scale. JSONL logs and a post-run report will teach you more in a week than any framework choice.
- Give the agent less power, not more. Narrow tools with clear contracts beat broad tools with clever prompts. Every single time.
- Run it unattended only after it survives a week of supervised runs with zero human intervention. If you are still nudging it, it is not ready.
The teams I see struggling with agent projects are almost always the ones that started with a framework and worked backwards to the problem. The ones shipping started with the problem, wrote sharp tools, and let the model do what it is good at: reasoning across a well-defined surface.
If you are working on something like this and want a second pair of eyes, or you are trying to move an agent from a nice demo to something that runs on its own, I am happy to talk. You can reach me at lazar-milicevic.com/#contact, or dig around the blog for more field notes from systems I have actually put into production.
Frequently asked questions
Why use Claude Code instead of a traditional agent framework like LangGraph?
I reach for Claude Code whenever the work involves code, files, shell commands, and judgment, because it gives the agent a real environment (shell, filesystem, editor loop) as the source of truth instead of a JSON state blob in memory. This means long-horizon tasks stay coherent past 40-50 tool calls, subagents can be spawned for isolated work without polluting the parent context, and failures leave real artifacts on disk you can debug the next morning. For hard-typed, deterministic pipelines I still use LangGraph or custom orchestrators, but for anything requiring adaptive execution across files and tools, Claude Code wins. The key insight is that unattended runs are only possible when the agent's state persists somewhere you can inspect after the fact.
How do I make a Claude Code agent resume work after a crash or restart?
The technique I rely on is a durable plan file, typically a PLAN.md written to the working directory that persists across sessions, restarts, and human interventions. The rule I give the agent is: before any non-trivial tool call, read PLAN.md; after any state change, update it. The file contains a task description, a checklist of completed and pending steps with the current step marked, and freeform notes like file paths and thresholds. This costs about 200 tokens per loop but lets you kill a run, restart it hours later, and have the agent pick up exactly where it left off, plus it gives you a diff to review when something goes wrong.
How should I design tools for an agentic workflow to avoid errors?
Design tools around capabilities the agent reasons about, not around raw API endpoints. Instead of exposing five separate WordPress endpoints like create_post, update_post, and delete_post, I expose one publish_brief(slug, markdown, metadata) tool that internally handles idempotency, slug conflicts, image uploads, and category mapping. The agent thinks about 'publish this thing' while the tool handles the sequencing. I also make every capability tool return a structured result with status, artifact_path, and an optional next_hint field that nudges the agent about follow-up actions, which in my experience roughly halved error-recovery loops.
How do I prevent an AI agent from going into a death spiral when something breaks?
I use three guardrails that have proven essential. First, a retry budget per tool (not per task): each capability tool tracks its own attempt count and returns a 'blocked' status after three failures with the same arguments, which the agent treats as a signal to escalate rather than try harder. Second, a 'diagnose before you patch' rule that forces the agent to read the full error, write a one-paragraph hypothesis to the plan file, and only then propose a fix. Third, a hard budget on tool calls per phase (e.g., 15 calls in the drafting phase) enforced by having the agent count in the plan file, so a broken loop stops itself instead of burning through your API budget.
How can I safely run Claude Code agents unattended overnight?
Unattended runs work reliably when three things are true: state lives on disk (via a persistent plan file), tools have their own retry budgets that convert repeated failures into a 'blocked' status instead of infinite retries, and phase-level tool-call budgets stop runaway loops before they drain your API quota. For the escalation path, I have stuck jobs post a message to a Slack channel and dump a JSON snapshot of the plan file plus recent tool outputs to S3. That way I can check once a day, review any half-finished runs in a few minutes, and clear stuck jobs without needing to reconstruct what the agent was thinking.
Building something hard with AI or automation? I am open to talk.
Get in touch