ActionBoxBlog

SecurityPlatformBackendML engineer

AI Agent Audit Trails: Approval and Execution Best Practices

Build an AI agent audit log that records the proposed tool call, human decision, exact payload, and real execution outcome.

Data analytics dashboard with charts and visual audit signals

An agent audit log is more than a transcript. A useful record lets someone answer four questions after the fact: what did the agent propose, what did the person approve, what actually ran, and what happened next? If those records are separate or mutable, an incident review turns into guesswork.

The audit trail should follow the decision lifecycle

Architecture Flow
1 Create Action with exact proposal 2 Record created event 3 Show bounded context 4 Approve or reject with reason 5 Record typed decision 6 Return decision and receipt 7 Execute approved payload 8 Success or failure 9 Report immutable outcome 10 Record outcome and duration AI agent Actionbox Reviewer Production tool Audit record API- Tool- AI agent Actionbox Reviewer Production tool Audit record API- Tool-

The proposal, decision, and execution outcome are different events. Do not overwrite the proposal with the result: an approved request can still fail, and a successful tool call does not prove that the approval was valid.

Minimum fields for an AI agent audit log

EventRecord
ProposalRun ID, agent name, tool name, sanitized arguments, risk class, created time
ApprovalAction ID, reviewer identity, typed response, reason, decision time
ExecutionTool call ID, start/end time, target, idempotency key, result status
OutcomeSuccess or failure, duration, rollback flag, reason code
CorrelationTrace ID, workflow/thread ID, source, commit or deployment reference

Keep sensitive values out of titles and descriptions. Put a short, redacted summary in the Action and keep protected evidence behind an authenticated link. The person reviewing the request needs enough context to make a decision, not a copy of every secret the agent can access.

Create an auditable approval in Python

The SDK exposes the Action ID, version, fingerprint, typed response, and outcome methods needed to bind the lifecycle together:

python
import os
import time
from actionbox import Actionbox

box = Actionbox(os.environ["ACTIONBOX_API_KEY"])
tool_call_id = "call_7f3c"
started = time.monotonic()

action = box.create(
    title="Approve production database migration",
    description="The agent proposes applying the reviewed migration bundle.",
    interaction={
        "type": "boolean",
        "label": "Allow this migration?",
        "true_label": "Approve",
        "false_label": "Reject",
    },
    context=[
        {"type": "key_value", "items": {
            "agent": "release-agent",
            "tool": "apply_migration",
            "tool_call_id": tool_call_id,
            "environment": "production",
            "migration_sha": "sha256:…redacted…",
        }},
    ],
    idempotency_key=f"agent-tool:{tool_call_id}",
)

response = action.wait(timeout=1800)
approved = (
    isinstance(response, dict)
    and response.get("type") == "boolean"
    and response.get("value") is True
)

if not approved:
    print("Rejected or expired; the tool did not run")
else:
    try:
        apply_migration()
    except Exception:
        action.report_outcome(
            "failed",
            duration_ms=int((time.monotonic() - started) * 1000),
            reason_code="migration_error",
        )
        raise
    else:
        action.report_outcome(
            "success",
            duration_ms=int((time.monotonic() - started) * 1000),
        )

The outcome is tied to the Action's server-side version and fingerprint. That prevents a later process from reporting success for a different payload and gives an auditor a single chain from proposal to result.

Make retries boring

Retries are where audit trails often become misleading. Use the same idempotency key for the same logical tool call, keep a stable run ID, and never create a new approval simply because a worker restarted. If the arguments change, create a new proposal and make the difference visible to the reviewer.

Use a fail-closed policy for malformed responses, rejected decisions, expired Actions, and missing checkpoints. “No answer” is not an approval, and “the tool returned 200” is not the same as “the policy was followed.”

Turn the log into an operating control

An audit trail becomes valuable when it supports a recurring review:

  • Find approvals without a reported outcome.
  • Find successful executions whose payload hash differs from the approved snapshot.
  • Find repeated expiry or rejection for the same tool and owner.
  • Find actions that exceeded their runtime or rollback budget.
  • Sample high-risk approvals and verify the reviewer had the required role.

For the full pause/resume pattern, see durable execution explained. The maintained framework adapters are the OpenAI Agents SDK approval tutorial and LangGraph human-in-the-loop tutorial. For the API boundary, see human approval for AI agents and the human approval API.

Create a free Source · Human approval API · Read the docs

Sources and further reading

Try this workflow in minutes

Create a free Source, then run the exact commands from this post against the live API — no approval infrastructure to build.

S
Suson Sapkota

Founder, Actionbox