What Can You Build With Claude? A Production Blueprint

Most "what can I build with Claude" lists are idea lists: summarizers, support bots, code reviewers. The ideas aren't the hard part. The hard part is the gap between a demo that works on your five favorite inputs and a system that runs unattended on the fiftieth thousand input at 3 a.m. After ten years of shipping automation, I'd rather hand you a blueprint than another list. This is how I would structure a Claude-powered project so that "prototype" and "production" are separated by a checklist, not a feeling.
I'm deliberately not describing one specific build here. This is the skeleton I would reuse for almost any useful automation, with a concrete example to keep it honest.
Pick a project with a boring, measurable shape
The best first Claude project is a repetitive workflow where a human currently reads something, decides something, and does one small action. Ticket triage, inbound email classification, document extraction into a database, drafting replies for human approval, enriching CRM records. These share a shape: unstructured input, a bounded decision, a typed output, and a clear "was that right?" signal.
I avoid open-ended projects ("an agent that handles operations") as a first build. Anthropic's own guidance in Building effective AI agents recommends finding the simplest solution that works, and warns that autonomy brings higher costs and compounding errors. I read that as: earn complexity. Start with a single model call with good context. Add a loop only when a single call demonstrably fails.
For the rest of this post, my running example is inbound request triage: read an incoming message, classify it, pull account context from your systems, and either draft a response for human approval or route it. It's generic enough to transfer, and it forces every production question I care about: tool access, evaluation, errors, and cutover.
Design tool access as a permission boundary, not a convenience
In Claude's tool use model, Claude doesn't execute anything. It returns a structured call, and for client tools your application runs it and returns a tool_result. Anthropic's docs describe the canonical shape: a loop keyed on stop_reason, where tool_use means run the tools, append results, and call again. That single fact should shape your architecture, because it means you own the blast radius. The model proposes; your code disposes.
Here is the skeleton I start from, stripped to the parts that matter:
MAX_TURNS = 8
def run(messages, tools, handlers):
for turn in range(MAX_TURNS):
resp = client.messages.create(
model=MODEL, max_tokens=2048,
tools=tools, messages=messages,
)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason != "tool_use":
return resp # done
results = []
for block in resp.content:
if block.type == "tool_use":
results.append(execute(block, handlers)) # validate, scope, log
messages.append({"role": "user", "content": results})
raise AgentBudgetExceeded("hit MAX_TURNS without finishing")
Three decisions in that snippet carry most of the production weight:
- A hard turn cap. Anthropic notes that agents commonly use stopping conditions like a maximum number of iterations. Without one, a confused model plus a flaky tool is an infinite, billable loop.
- An
executewrapper you control. Every tool call goes through one function that validates arguments, enforces scope, and logs. I never let the model's output touch a database or API directly. - A typed failure when the budget runs out. Not a silent return. The caller must know the run did not finish.
On tool design itself, Anthropic's docs say a description should cover what the tool does, when it should and shouldn't be used, and what each parameter means. I'd add a practical corollary: the "when not to use it" half is where most of my reliability gains come from. A lookup_account tool described as "gets account info" gets called constantly. One that says "use only after you have a verified account ID from the message; do not use to search by name" gets called correctly.
Scope tools by blast radius:
| Tier | Example tools | Default policy |
|---|---|---|
| Read-only | account lookup, doc search | Allow, log |
| Reversible write | draft reply, tag ticket | Allow, log, rate limit |
| Irreversible write | send email, issue refund, delete | Human approval gate |
| Shell / code execution | bash, scripts | Isolated container, least privilege |
If you give Claude a shell, take Anthropic's bash tool guidance literally: run it in an isolated environment (container or VM) as the least-privileged user that can do the work, and treat every command as untrusted input. The model is not malicious, but its input can be, and a prompt-injected email that reaches a shell with broad credentials is how a triage bot becomes an incident.
One more option worth knowing: programmatic tool calling lets Claude write code that calls your tools inside a code execution container, avoiding a model round trip per tool call. Anthropic's example is checking budget compliance across 20 employees with one script instead of 20 round trips. If your workflow fans out over many records, that's worth evaluating before you build a sprawling multi-turn loop.
Write the success criteria before the prompt
This is the step I see skipped most, and it's the one that separates a prototype from a product. Anthropic's recommended order is to define success criteria first and then design evaluations to measure performance against them. Their docs also say criteria should be measurable, and they make the point with a nice example: even safety can be quantified, for instance fewer than 0.1% of outputs flagged for toxicity by a content filter across 10,000 trials, versus a vague "safe outputs."
For triage, my criteria would look like this (these are illustrative targets, not benchmarks from a real system):
- Routing accuracy against a human-labeled set, with a threshold set before I look at results.
- Per-class recall on the categories that are expensive to miss (anything with an SLA, anything legal).
- Tool-call correctness: right tool, valid arguments, no calls outside the allowed scope.
- Escalation rate: how often the system says "I'm not sure," tracked as a feature, not a failure.
- Cost and latency per request at the volume I expect.
Anthropic's ticket-routing guide frames production readiness the same way: evaluate performance against success criteria and thresholds set up front, including things like a rater-scored explainability metric with a target average. The principle matters more than the specific numbers: the threshold exists before the first result, so you can't rationalize a mediocre outcome afterward.
My eval set construction rules:
- Pull real inputs, not invented ones. Synthetic examples flatter the model because you write them in the style you expect.
- Over-sample the ugly cases: empty messages, forwarded chains, two requests in one, wrong language, pasted logs.
- Include adversarial inputs that try to make the model ignore instructions or call tools it shouldn't.
- Freeze the set and version it. If you change the eval set and the prompt in the same commit, you've learned nothing.
I run this eval on every prompt change and every model change, in CI, with a pass/fail gate. It is the single cheapest way to stop silent regressions, and it matters more as models update under you.
Plan for errors you'll actually hit
Error handling for LLM systems has two layers: the API failing, and the model being wrong. Treat them separately.
API failures. The Claude API error docs distinguish a 529 overloaded_error (high traffic across all users) from a 429 rate_limit_error, and the distinction changes what you should do. A 529 is transient: back off with jitter and retry. A 429 is more subtle. It can mean you hit a rate limit, but it can also mean your usage tier's monthly spend cap was reached, and that variant has no retry-after header and keeps failing. Blind retries on it are pointless and just burn time. Likewise, a 400 is returned when an org or workspace spend limit you set is reached.
So my retry policy is not one policy:
| Failure | Response |
|---|---|
| 529 overloaded | Backoff with jitter, bounded retries, then queue |
| 429 rate limit | Backoff, then slow the producer |
| 429 that persists / spend cap | Stop retrying, alert a human |
| 400 from spend limit | Stop, alert; this is a budget event, not a bug |
The common mistake is wrapping everything in retry(3) and calling it resilient. A spend-cap 429 inside a naive retry loop looks like an outage and is actually a billing decision someone needs to make.
Model failures. These are quieter and more dangerous. My defaults:
- Validate every structured output against a schema before acting on it. A malformed classification is a retry or an escalation, never a guess.
- Make "I don't know" a first-class output. Give the model an explicit escape route, such as an
escalate_to_humantool or aconfidence: lowfield, and route on it. - Make side effects idempotent. If the loop retries, tagging a ticket twice must be harmless.
- Log the full trace: input, every tool call and result, final output, model ID, prompt version. When something goes wrong at 3 a.m., the trace is the only witness.
- Dead-letter queue for runs that exhaust the turn budget or fail validation, so nothing disappears silently.
Know when the prototype is actually ready
"It looks good in the demo" is not a gate. I use a checklist, and a project doesn't graduate until every line is a yes:
- Eval passes its pre-set thresholds on a frozen, realistic set, including the ugly and adversarial cases.
- Shadow mode ran on live traffic. The system produced outputs for real inputs for a meaningful period while humans still did the work, and I compared the two. This catches the distribution shift your eval set missed.
- Every irreversible action sits behind an approval gate or a reversible equivalent, with an audit trail.
- Failure paths are tested, not assumed. I've deliberately injected 529s, malformed outputs, tool timeouts, and a hit-the-turn-cap run, and watched the system degrade gracefully.
- There's a kill switch and a rollback. One flag that returns the workflow to the human path, tested.
- Cost per request is known at expected volume, with a budget alarm below the spend cap, so you hear about it before the API says no.
- Someone owns it. A named human gets the alert and has the authority to turn it off.
Then roll out in stages: shadow, then draft-for-approval, then autonomous on the lowest-risk category only, widening as the live metrics hold. The approval-gated stage is where most teams should stop for a long while, and where a lot of the real value already lives.
One note on model choice, since people always ask. Anthropic's official model catalog describes Haiku-class models as suited to classification, routing, extraction and sub-agent tasks, and I'd start the cheap, high-volume steps there and reserve a larger model for the genuinely hard reasoning. But I won't name a "best current model" here, because the lineup moves quickly and sources disagree on what's generally available. Check Anthropic's models and pricing pages before you commit, and never construct model IDs by hand. Pin one, put it in config, and let your eval suite tell you when a change is safe.
What I'd do
If I were starting a Claude project this week:
- Choose a triage-shaped workflow with a typed output and a clear right-or-wrong signal. Skip the "autonomous operations agent."
- Write the success criteria and build the eval set before the first prompt. Freeze it. Gate CI on it.
- Start with one model call. Add tools only when it fails without them, and add the loop only when tools force it.
- Put every tool behind one
executewrapper with validation, scoping, logging, and a hard turn cap. - Tier tools by blast radius. Irreversible actions get human approval until the live data earns them autonomy.
- Handle spend-cap errors differently from overload errors. One is a retry, the other is a phone call.
- Run shadow mode before anyone trusts it, and keep a tested kill switch.
None of this is glamorous. All of it is the difference between a demo people clap for and a system nobody thinks about because it just works.
If you're scoping something like this and want a second pair of eyes on the architecture, you can reach me at lazar-milicevic.com/#contact, or keep reading on the blog for more production notes on agents and LLM systems.
Frequently asked questions
What can you build with Claude?
The best Claude projects are repetitive workflows where a human reads something, decides something, and takes one small action. Good examples are ticket triage, inbound email classification, document extraction into a database, drafting replies for human approval, and CRM enrichment. These share unstructured input, a bounded decision, a typed output, and a clear signal for whether the result was right. I'd start there instead of building open-ended agents.
How does tool use work with Claude?
Claude doesn't execute anything itself. It returns a structured tool call, and your application runs it and sends back a tool_result. The standard pattern is a loop keyed on stop_reason: when it equals tool_use, you run the tools, append the results, and call the model again. This means you own the blast radius, since the model proposes and your code decides what actually happens.
How do you stop a Claude agent from looping forever?
Put a hard cap on turns in your agent loop, for example a MAX_TURNS of 8. If the loop hits that limit without finishing, raise a typed failure rather than returning silently, so the caller knows the run didn't complete. Without a cap, a confused model combined with a flaky tool becomes an infinite, billable loop. Anthropic's guidance on agents also lists a maximum number of iterations as a common stopping condition.
How should I control which tools Claude can access in production?
Treat tool access as a permission boundary and scope tools by blast radius. Read-only tools like account lookup can be allowed and logged, reversible writes like drafting a reply need logging and rate limits, and irreversible actions like sending email or issuing refunds should go through a human approval gate. Route every call through a single execute wrapper that validates arguments, enforces scope, and logs. If you give Claude a shell, run it in an isolated container as the least-privileged user and treat every command as untrusted.
How do I write good tool descriptions for Claude?
A good description covers what the tool does, when it should and shouldn't be used, and what each parameter means. In my experience the 'when not to use it' part delivers most of the reliability gains. A lookup_account tool described only as 'gets account info' gets called constantly, while one that says to use it only after you have a verified account ID, and not to search by name, gets called correctly.
Building something hard with AI or automation? I am open to talk.
Get in touch