Claude inside operations: reviewed before it writes, logged after
Claude API pipelines, operations agents with narrow tools, and Claude Code set up for a team, built so a person confirms anything that writes, spend has a ceiling, and every call can be explained afterwards.
Claude is the right tool when the input is a mess a rule cannot parse and the output is something a person can check: a supplier invoice photographed on a warehouse floor, an inbound email that is really three requests, a free-text field that has to become a category, the first draft of a reply. That is the unglamorous middle of a process, and it is where a model does measurable work. It is how we use it ourselves: on the trading ERP, Claude is one of two model providers behind the invoice scanner.
It is the wrong tool for anything a rule can state. If the condition is an order value over a threshold, a supplier on an approved list or a date inside a window, an if-statement or a router is cheaper, instant, identical every time and explainable to an auditor. The test we apply is whether you could write the rule on one side of paper. If you can, write it. If you cannot, because the input is unstructured or the judgement is genuinely fuzzy, use a model for that one step and keep everything around it deterministic.
Agents are the same question with the dial turned up. An agent is a model choosing its own next step, with tools, in a loop. It is powerful, and much harder to bound. So we start with a fixed workflow that has a model at one or two steps, and promote it to an agent only when the path really cannot be known in advance. Claude Code is a separate matter: a coding tool we use day to day, useful in an operations codebase for some jobs and a liability for others. Both are covered below. We build on Claude through its public API and tools; we are not an Anthropic partner and hold no certification or endorsement from them.
What we build on Claude
Extraction and classification with a person on the write
The model reads the document, the output is parsed against a schema, the arithmetic that can be checked is checked, and a reviewer confirms or corrects it on screen beside the source. Only the confirmation writes. This is the shape of the invoice capture on the trading ERP, and it turns a data-entry job into a review job without ever letting the model near the ledger.
Operations agents with a short list of narrow tools
Triaging an inbox into the right queue, chasing the items stuck in an exceptions list, proposing the first-pass match in a reconciliation. The agent gets read-only access by default, a handful of tools each doing one thing (usually exposed through an MCP server over your own systems), a hard cap on steps, and no tool that sends, pays or deletes. Anything it wants to change comes back as a proposal.
Evals before the first prompt change
A small set of real documents, including the ugly ones, with known-correct answers, run against every prompt edit and every model change. It is an afternoon of work that turns we think the new prompt is better into a number. The model stays a setting rather than an architecture, which is also what makes failing over to a second provider a configuration change.
Cost controls that exist before the invoice does
A model matched to the difficulty of the job (a small fast one for routing and classification, a stronger one for the bad scan), with repeated context cached, non-urgent work pushed through the batch interface, a token budget per run, and usage logged per workflow so a rise has a name. A spend alert is a monitor you set before launch, not after the first surprising month.
Claude Code set up for a team, not for one person
A CLAUDE.md in the repository that states the conventions, the commands that run lint, types and tests, and the tables and modules nobody touches without a conversation. Project permissions committed and shared: test and typecheck commands allowed, reads of environment files and anything pointing at production denied. Hooks that run the checks after every edit, read-only MCP connections to staging rather than live, and every change arriving as a pull request that gets reviewed like anyone else's.
What Claude Code is actually good for in an ops codebase
Integration glue with paging, retries and back-off written to a pattern you already have. Reading an inherited codebase, or a Make blueprint export, and explaining what it does before anyone edits it. Characterisation tests that pin down existing behaviour. Drafted migrations and one-off reconciliation scripts, reviewed and run against a copy first. It is much less useful where the hard part is knowing the business rule, because nobody has written that down for it either.
What goes wrong on Claude
The patterns that turn up on this platform specifically, and what we do about each one.
- 01
Cost that runs away without anyone deciding it should
A retry loop on a rate-limit error, an agent that keeps trying a step that cannot succeed, a large document resent in full on every call, or the same invoice processed twice because two triggers fired. None of it looks like a bug; it looks like usage. We cap steps and tokens per run, deduplicate by document hash before the model is called, back off on rate limits instead of hammering, and alert on spend per workflow rather than on the account total.
- 02
No evals, so every change is a guess
A prompt tweak that fixes the invoice someone complained about quietly breaks three others, and nobody finds out until month end. A model upgrade is the same risk with a bigger blast radius. A small labelled set of real documents, run on every change, makes both a measurement that takes minutes. Without one, you are not tuning a system, you are reacting to whoever shouted last.
- 03
Prompt injection from documents you did not write
A supplier invoice, a PDF attachment or an inbound email is untrusted text, and a model can be talked into treating text inside it as an instruction. We do not claim to make that impossible. We limit what it can cost: the step that reads untrusted content gets no tool that can send, pay or delete; its output is parsed against a schema and treated as untrusted input; credentials are read-only and narrow; and a person confirms before anything leaves the system or touches money.
- 04
A plausible wrong answer reaching the ledger
Models fail by being confidently fluent, not by throwing errors. A total that is almost right looks the same as one that is. So line items are checked against the stated total, supplier names are matched against suppliers you already hold, doubtful documents are flagged rather than a field, and the source image sits beside the extraction. The rule underneath all of it is that the model proposes and a person writes.
- 05
No audit trail, so nobody can say why it did that
When a figure is queried six months later, we want to know which document went in, which prompt version and model produced the output, whether it passed validation, and who confirmed it. On the trading ERP every write passes through one data-access layer that appends a field-level diff to a table staff can insert into but never update, so a confirmed invoice leaves the same trail as a hand-typed one. The model call gets logged alongside it, not instead of it.
- 06
Claude Code changes that nobody really read
The failure is a large diff, green tests that the tool wrote to match its own code, and a reviewer who skims. It is worst in money, permission and migration logic. We keep diffs small, write or review the tests first for anything touching those, keep production credentials out of reach of the tool entirely, and treat the output as a colleague's first draft: read in full, and never merged on the strength of the checks alone.
Where Claude is the wrong answer
Claude, or an agent, is the wrong answer more often than the current enthusiasm suggests. If the decision can be written as a rule, use a router, a lookup table or a few lines of code: it will be faster, free per run and identical every time. If the data already arrives structured (an API, a CSV, an EDI feed), there is nothing for a model to read, and Make or n8n will move it for far less. Where no one will ever review the output, or a wrong answer cannot be undone, a model should not be the last step at all. Open-ended agents are the weakest fit for money, stock and permissions; a fixed workflow with a model at one step is almost always what we would build instead. On the coding side, Claude Code is not a substitute for someone on your team who can read a diff, because speed you cannot review is just a faster way to build something you cannot maintain. Nor are we tied to one model: the trading ERP fails over to a second provider, and where another model is the better fit for the job, we will say so.
Built on Claude
Projects that did not use Claude
Here for the argument rather than as evidence of Claude work. Each one bears on a decision above, and the note says which.
- A fleet-telematics providerOrders that file themselves, and an SLA clock that never forgetsNot a Claude build as written up. It is the case for the rollout discipline we would use to introduce an agent: parsing into a board with an ingest ledger, and a shadow mode that logs what the system would have done before it is allowed to do it.Case study
- Skofi OutreachSkofi Outreach: deliverability rules the database refuses to breakNot a Claude build. It is our argument for putting the rules that must never break in the database rather than in a prompt or in application code, which is where any model-driven step that can send email or touch money should be fenced.Case study
Related reading
Claude, specifically
No, and we will not claim to be. We build on Claude through the public API and use Claude Code ourselves, and one production system we built uses Claude for invoice reading. But we hold no partnership, certification or endorsement from Anthropic, and nothing on this site should be read as one. If your procurement requires a certified partner, raise it in the first conversation rather than the last.
Ask whether the rule fits on one side of paper. If it does, a rules engine or a Make or n8n scenario is cheaper, faster and fully explainable, and an agent adds risk for nothing. If the input is unstructured or the judgement is fuzzy, use a model at that one step and keep the rest deterministic. An agent that picks its own path is justified only when the path genuinely cannot be known in advance, and even then it should get narrow tools and no authority to send or pay.
By putting limits in before launch rather than reading the bill after it. That means a token budget and a step cap per run, deduplication so the same document is never processed twice, the cheapest model that does the job, cached context and the batch interface for non-urgent work, and usage logged per workflow with an alert on it. Cost is driven by tokens in and out, so we estimate it from a sample of your real documents rather than quoting a per-document figure in the abstract.
Yes, which is called prompt injection: text inside a document that tries to give the model instructions. It cannot be fully prevented, so the design assumes it will occasionally work and limits what that can achieve. The step that reads untrusted content has no tool that sends, pays or deletes, its output is validated against a schema, credentials are read-only, and a person confirms before anything leaves the system or changes the books.
Treat it as a new contributor with fast hands and no context. Put the conventions, the check commands and the off-limits areas in a shared CLAUDE.md, commit permission settings that allow the test and typecheck commands and deny environment files and production access, run lint and tests with hooks, point any MCP connection at staging read-only, and require a reviewed pull request for every change. The aim is that nobody has to remember the safe way to use it, because the repository enforces it.
It is as safe as the access you give it and the review that follows. Work on a branch, keep production credentials out of reach, run migrations against a copy first, and read every diff in full. It is good at glue code, tests for existing behaviour and explaining an unfamiliar system. We would not let it change payment, permission or migration logic without the tests being written or reviewed first by a person.
Not on the standard commercial API terms, which is what we build against, but terms change, so check the current ones for your plan before sending anything sensitive. Where the data matters enough that this is not sufficient on its own, the practical mitigation is scope: send the fields the model needs rather than whole records, redact what is irrelevant, and make that a decision during the build rather than a default.
Page copy drafted with AI assistance. Skofi is accountable for it. Editorial policy
Tell us about the process that keeps costing you.
A 15-minute call is usually enough to say whether this is an automation, an integration, or something that should be built, and whether we are the right people for it.
What happens on the call
- 15 minutes, no deck
- We map the process on the call
- A written scope, or an honest no