The problem is not the “Approve” button
Imagine a sales assistant that reads correspondence, proposes changing a delivery address and discount in a CRM, and sends a card to a manager for approval. The manager opens it an hour later. The customer may have updated the order, a colleague may have changed the terms, and the manager's permission to edit that deal may have expired. Clicking “Approve” no longer means consenting to the current action.
This is a design scenario, not a report of a specific incident. The longer an agent waits for a person, the more likely its source data and the person's permissions are to change. Safe approval is therefore not a conversational “yes, go ahead”. It is a record of who approved exactly which operation on which version of an object, and until when.
What a graph pause does and does not provide
In LangGraph's documentation, `interrupt()` stops execution, persists state through a checkpointer, and lets the run continue after an external decision. Resumption requires the same `thread_id` and a value supplied through `Command(resume=...)`. LangGraph's official diagram shows the path “model — human — tool executor”: the person is placed before the external action, not asked to observe it afterward.
The pause itself is not authorization, however. The documentation also warns that code in a node before `interrupt()` runs again on resumption. If it has already sent an email or updated a CRM before pausing, the rerun can duplicate the side effect. Separate external writes from proposal preparation, and make repeatable operations idempotent. LangGraph supplies pausing and persistence; approval expiry, permission checks and duplicate prevention remain the application's responsibility.
OWASP identifies excessive agent privileges as a risk and recommends human approval for consequential actions. The tool executor should nevertheless independently check the access scope, exact parameters and approval state. A button in the interface must not turn model-generated text into an unrestricted service credential.
A minimal design for one operation
For a pilot, take a single CRM deal-field change rather than a money transfer or bulk deletion. The workflow can be split into six explicit steps:
1. The agent reads authorized data and prepares a **proposal**, but does not call the write method.
2. The application stores a structured plan: deal ID, field, old and new values, record version, initiator, evidence source and unique operation ID.
3. The manager sees those exact values and the business context; the interface shows the change to be made, not merely the model's polished summary.
4. Approval is stored separately: who clicked, which plan version they approved, under which permissions, and until when the decision is valid.
5. Immediately before the write, the executor checks permissions, expiry, plan equality and the current deal version again. A changed object goes back to a person for a fresh decision.
6. After a conditional write, the system stores the result and operation ID so that a rerun cannot execute the same command twice.
A plan hash or signature can reveal parameter changes between display and execution, but does not replace authorization. If the CRM supports a conditional update using a version or ETag, use it: a plain “read, then write” check leaves a race window. Where the API cannot do a conditional write, explicitly limit the risk with a narrower operation set, an additional check or manual execution.
Data and infrastructure required
This takes more than an LLM server. It needs a verified initiator identity, permissions for the action, an immutable proposal record, durable storage for the paused workflow, a queue to notify managers, a least-privilege CRM executor, and an audit trail of “proposed — approved — executed/rejected”. In a local deployment, all of these components must stay inside the permitted network; the model itself can change without changing the approval rule.
Do not copy an entire customer correspondence thread into an approval card if a few fields and links to authorized records suffice. Nor should the audit log become a warehouse of sensitive prompts. Keep what is needed to verify the decision: identifiers, version, operation parameters, participants, time, outcome and rejection reason. The process owner should define retention in line with data requirements.
Some actions do not need a person, such as preparing a draft reply or highlighting a discrepancy. Writing master data, changing deal terms and sending an external message carry a higher cost of error. Risk-based separation prevents staff from being flooded with approvals and turning control into a formality.
Economics and limitations
This design has a cost: an approval interface, state storage, CRM version handling, audit and manager time. Its value cannot be measured only by fewer clicks. In a pilot, compare the time from proposal to execution, rejected and stale-plan rates, retry counts, manual rework and audit time. Also measure how many actions truly need approval and how many can safely remain drafts.
A local model is useful where customer correspondence and data must not go to an external API. But local deployment does not guarantee that a CRM write is authorized or current. If the agent chooses the wrong field or address, responsibility for the final action remains with the organization and its process, not with the location of the model weights.
A short pilot test
Choose one type of write and prepare ten de-identified scenarios. In each, the agent proposes a change and a manager approves or rejects it. Then deliberately change the underlying deal between proposal and approval, revoke the approver's access, deliver the command twice and let an approval expire. In all four negative tests, the expected result is that the record does not change without a new valid decision.
Once these checks pass, evaluate model quality and time saved. If they fail, increasing autonomy is premature. The most useful management conclusion is to approve a specific, current action, not the agent's vague intention to “fix something in the CRM”.
