On this page
Choose a bounded action
The worked example is an assistant that prepares a workshop follow-up message from approved notes. It can retrieve resources and draft content. Sending requires a person to review the exact recipient list and message. This separates flexible language work from the consequential action and keeps the first implementation understandable.
Write the goal, available tools and prohibited actions before implementing the loop. An assistant that only needs resource lookup should not receive a general database console or unrestricted shell. Tool capability should follow the task, not every service the organisation happens to use.
Define tool contracts
Give each tool a clear input schema, permission requirement, side-effect description and result format. Validate calls on the server. A model-provided argument is a proposal, not proof that the current user is authorized. Keep read-only tools separate from tools that change records or communicate externally.
lookup_resources(event_id) -> verified resource records
prepare_draft(event_id, resource_ids) -> draft_id, version, body
request_review(draft_id, version) -> review state
send_approved_draft(approval_id) -> delivery recordThese signatures illustrate boundaries rather than a particular provider API. The final send operation should resolve the approved payload from a trusted record. It should not accept an arbitrary new body supplied by the model after approval.
Persist a state machine
Record states such as preparing, awaiting_review, approved, sending, completed, rejected and failed. Define which actor may move between them and what evidence the transition requires. A generated sentence saying ‘approved’ is not approval evidence. A stored reviewer decision tied to a specific draft version is.
| Transition | Required evidence | Failure handling |
|---|---|---|
| Preparing to review | Complete draft and resolved recipients | Keep draft with missing fields visible |
| Review to approved | Authorized reviewer and exact version | Reject or request changes |
| Sending to completed | Provider result or reconciled delivery record | Check outcome before retrying |
Make approval concrete
The review screen should show destination, subject, full body, attachments and any meaningful consequence. Let the reviewer reject or edit the draft. If an edit changes the approved object, create a new version and obtain the appropriate review again. Expiration and revocation should be explicit states rather than informal assumptions.
Do not require the reviewer to infer what is hidden behind a summary. A sentence such as ‘send the usual follow-up’ does not expose the actual recipients or commitments. The approval boundary should match the action the service will execute.
Bound execution and retries
Set limits for total tool calls, elapsed time and paid usage. Include retries in those limits. Stop repeated searches or failures when they no longer produce new evidence, and return a handoff packet with completed work and the missing decision. Preserve the draft so a person can continue without restarting.
Use an idempotency key for the concrete send action where the integration supports it, or maintain an equivalent durable reconciliation mechanism. A timeout may occur after a service accepted the message. Before repeating the action, determine whether it already happened. The application, not the model’s memory, must own this protection.
Test the boundaries in isolation
Use synthetic recipients and a test delivery adapter. Try unauthorized tool calls, changed draft versions, expired approvals, duplicate execution and a response lost after completion. Include a retrieved document containing an instruction to change the destination. Inspect actual tool calls and records, not only the assistant’s final explanation.
Log correlation IDs, tool names, safe arguments, states and outcomes. Avoid collecting hidden reasoning or unnecessary private content. Replaying a failure should use fixtures or an isolated environment so investigation cannot resend a real message.
The operating checklist
- Tools are narrow and server-authorized.
- Draft and approval versions are bound together.
- State survives process restarts.
- Retries cannot silently duplicate the action.
- Execution budgets include every stage.
- Handoffs preserve work and identify the next owner.
- Test traces demonstrate the protected boundaries.
Start with draft preparation only if the sending integration is not ready. That is still a useful complete workflow when the product clearly states its boundary. Add greater autonomy only after the necessary permissions, review and recovery behaviour are verified.
OWASP: prompt injection risks in AI applicationsShare or cite this guide
Innovate with Ajay Editorial (2026-10-04). Build an Agent Workflow with Permissions, Approval and Recovery. https://innovatewithajay.com/articles/build-an-agent-workflow-with-human-approval
