Series · After the meetingAgent harnessArchitectureApprove every step

The harness: the same webhook twice does nothing twice

A reliable sales agent is a compiled graph: typed steps, fixed tools, one approval interrupt, idempotent writes, checkpoints, and a CRM login with hard limits.

Jared Hawkins-Young · Founder, Lost Star TechnologyOctober 8, 20265 min readPart 11 of 13

Key takeaways

  • A reliable AI sales agent is a compiled state graph with typed nodes, a fixed tool allow-list and one interrupt where a person approves before anything is written.
  • Every write is keyed on the run, the tool and the target record, so a redelivered webhook re-runs the graph and lands on the same records instead of duplicating them.
  • A checkpoint after each step lets a failed run resume from the last successful step without re-extracting the call or re-drafting mail already written.
  • In Salesforce the boundary on stage, dates and amount is a field permission on the integration user; HubSpot's property restrictions do not apply to API writes, so there the write tool's allow-list carries it.

A reliable AI sales agent is a compiled graph, not a long prompt: typed steps, a fixed list of tools, one pause where a person decides, writes that are safe to repeat, a checkpoint after every step, and a CRM login that cannot touch stage, dates or amount. The interesting engineering is the boundary around the model, and knowing which steps should stop being agents at all. This part is for the head of sales whose CTO asks how it actually runs.

What is the harness connected to?

Recorder
Fathom, Fireflies, Gong or Zoom
ReadsTranscripts, speakers, timestampsWritesNothing
Inbox
Gmail or Outlook
ReadsThreads and repliesWritesDrafts only
Slack
The team's workspace
ReadsApprovals and dismissalsWritesReview requests, alerts
Agent runtime
One compiled graph
LangGraph for the graph, Claude Code for the model steps
  • Typed nodes, conditional edges
  • A fixed tool allow-list
  • One interrupt: a person decides
  • A checkpoint after every node
  • Writes keyed on run, tool and record
Cannot write stage, close date, invoice date or amount. Cannot send.
CRM
HubSpot or Salesforce
ReadsThe current recordWritesApproved evidence fields; recommendations queued
Price book
Your quote template
ReadsStated scopeWritesDraft priced lines
Documents
Google Drive or SharePoint
ReadsApproved material, the SOC 2 reportWritesDraft proposals and recaps
Figure 1. The runtime in the middle and six systems around it, each with what the runtime may read and what it may write. Every write ends in a draft, an approved evidence field or a queued recommendation. Nothing on this board sends to a customer.

In the Lost Star build the graph is LangGraph and the model steps run through Claude Code. The names matter less than the shape. A compiled state graph means every step is a node with typed inputs and outputs, and the edges between them are conditions written in code: if an extraction comes back below its confidence threshold, the next node is the rep's review queue, not the CRM. The tool list is fixed when the graph is compiled. The node that extracts signals from a call cannot call the email tool, and the node that drafts the recap cannot call the CRM write.

What does "the same webhook twice does nothing twice" mean?

The run starts when the recorder says a recording is ready, usually through a webhook. Webhook senders retry when they do not get a quick answer, so the same event can arrive twice. Without protection, the Northwind call from part 1 produces eight open issues instead of four, two recap drafts, and two notes on the deal.

The fix is to make every write idempotent: keyed on the run, the tool and the target record. Before a write, the harness checks the key. If it already exists, it returns the earlier result instead of writing again. A redelivered event re-runs the graph and lands on the same four issues in the open-issue ledger, not eight. Reps stop trusting a ledger the first time it doubles.

What happens when a run fails halfway?

It picks up where it stopped. LangGraph's checkpointer saves a snapshot of the graph's state at each step, and its documentation describes the recovery directly: if a node fails, you restart from the last successful step, and writes from nodes that already finished in that step are not run again.

In practice, a timeout on the price book call does not re-extract the recording or re-draft the recap that is already written. That matters for two reasons. The model steps are the slow and expensive part, so re-running them because one API blinked is waste. And a re-drafted recap can come out different from the one the rep already read, which is worse than waste.

Where does a person decide?

At one interrupt. LangGraph's interrupts pause the graph at a chosen point, save its state, and wait, indefinitely if need be, until the run is resumed with outside input. In this harness the interrupt sits at the approval step. The drafted record waits in review. When the rep approves, edits or rejects each field, the graph resumes with that decision and only then writes.

That is the difference between a promise and a structure. A sentence in a prompt asking the model to wait for approval can be ignored. A node the graph cannot route around cannot.

How is the boundary enforced, not promised?

Part 1 said the agent's CRM login cannot write stage, dates or amount. How that is enforced depends on the CRM, and the difference is worth knowing before you sign anything.

In Salesforce it is a permission. Field permissions control whether a user can see and edit a particular field. The agent signs in as its own integration user, and that user's permission set denies edit on stage, close date and amount. The runtime could not move them if the prompt told it to.

In HubSpot it has to live one layer up. HubSpot's property restrictions are an Enterprise feature, and HubSpot's own documentation says users can still set restricted properties through the API and that restrictions should not be used as a security measure. So on HubSpot the write tool carries the boundary: it accepts an allow-list of evidence properties, has no parameter for deal stage, close date or amount, rejects anything else before the API call, and logs every write with its run. That is code, not a CRM permission, which is why the log is how you audit it.

Which steps should stop being agents?

An agent is how you find the shape of a job. It is an expensive way to keep running one. The same seven steps, today and at fifty times the volume:

StepTodayAt 50x volumeWhy
Pull signals from a callAgentAgentLanguage is unbounded. No fixed schema survives contact with real calls.
Draft the recap and follow-upsAgentAgentIt has to sound like the rep wrote it.
Classify an inbound questionAgentAgentNew questions arrive forever. A rules engine rots.
Write evidence to the CRMAgent tool callDeterministic jobOnce the field map settles, it is an upsert.
Create open issuesAgent tool callDeterministic jobThe typing already happened upstream.
Build the quoteAgent tool callPrice book functionIt is arithmetic against a price book, not judgment.
Detect a deal gone quietAgentA scheduled queryReply timestamps and a threshold. No model needed.

A step graduates the moment its output schema stops changing. The agent is how you find that schema, not how you run it forever. Four account executives might record two hundred calls a month, an illustrative figure; fifty times that is ten thousand. At ten thousand calls a month, paying a model to ask whether a deal has gone quiet is a bill, not an architecture. The first three rows are language problems and stay agents. The last four are schema problems wearing a language problem's clothes.

The outbound series draws the same line from the other side: automate the known, escalate the consequential. A known event with an approved action belongs in a job. An ambiguous one belongs in front of a person.

Next in the series

Part 12, What to measure, and what the published numbers already say, covers how you would know any of this worked: the industry figures worth quoting with their weaknesses, two worth refusing, and the measures to baseline before anything ships.

Common questions

What makes an AI agent safe to run on a real CRM?
Structure rather than instructions: a compiled graph with a fixed tool list, an approval step the graph cannot skip, idempotent writes so repeated events do not duplicate records, checkpoints so failed runs resume cleanly, and a CRM login or write tool that cannot touch stage, close date or amount.
Can HubSpot field permissions stop an AI agent from changing deal stage or amount?
Not on their own. HubSpot's documentation says restricted properties can still be set through the API and advises against using property restrictions as a security measure. On HubSpot the limit has to be enforced in the agent's write tool, with an allow-list of properties and a log of every write. In Salesforce, field permissions on the integration user enforce it directly.
Should every step in a sales workflow be an AI agent?
No. Steps that read or write open-ended language, like extracting signals from a call or drafting a recap, stay agents. Steps whose output schema has stopped changing, like writing approved fields, creating issues, pricing a quote or flagging a quiet deal, should become deterministic jobs as volume grows.

Sources

  1. LangChain, LangGraph documentation: Checkpointers (checkpoints at each step, fault tolerance, pending writes)
  2. LangChain, LangGraph documentation: Interrupts (pause, persist state, resume with input)
  3. Salesforce Trailhead, Data Security module, unit on field-level security (field permissions control whether a user can see and edit a field)
  4. HubSpot Knowledge Base, Restrict view and edit access for properties (API edits not restricted)

Written by Jared Hawkins-Young from the system he builds and runs. Diagrams are drawn from the same specs as the software. Published October 8, 2026. Illustrative numbers are labelled as such; every other figure carries its source.

Lost Star Technology

See one of your own calls become the record.

Fifteen minutes with Jared. Bring a recorded call if you like, and watch its record draft itself with the sentence behind every field.