Product

Runtime enforcementPolicy engineAgent governanceApprovalsEvidence

Developers

Developer guideIntegrationsArchitecture

Company

SecurityCompany
Request access

    Stop the action. Ask a human.

    Agents should not need a person for everything. They should need one for the small number of actions where judgement is the control - and when that happens the action stops rather than slows down.

    Held : awaiting review approval_required
    tool_namecustomer_export
    actionExport 40,000 customer records to CSV
    agentrevops-analysis-agent
    approval_idapr_5f2c91a0e7
    reviewersecurity_lead
    tool executedno

    Not a queue you can wait in.

    A hold is not a deferred allow.

    The most dangerous misreading of Anubis is “approval required means wait, then proceed”. Stated exactly, because every surface behaves this way:

    the decisionis not permission
    the tool callmust not execute - not now, not after a wait, not after a reviewer acts
    resolutionrecords a human judgement beside the hold, never over it
    that decisionnever becomes allow
    continuing lateris a new run, a fresh evaluation, and possibly another hold
    automatic resumedoes not exist - no callback, no token, no consume endpoint, no poll API

    An agent that could approve itself would make the control meaningless.

    Which credential may call which route
    OperationWho may call it
    POST /api/runtime/evaluateAn agent runtime credential, scope runtime:evaluate
    POST /api/runtime/approvalA signed-in human with the security_lead role
    GET /api/runtime/events/{id}A signed-in human, organization-scoped from the session

    Approval resolution is a control-plane operation behind a browser session. An agent runtime credential can never call it, and there is no configuration that creates one that could.

    There is also no agent-facing route to read an approval's state. So no client in the product offers poll(), wait_for_approval(), resume() or consume() - not the SDKs, not the adapters, not the CLI. Building a client for a call that cannot be made would be worse than not having it.

    What actually happens.

    What actually happens
    agent calls evaluate | vpolicy says a human must review this | vHTTP 200 { "decision": "approval_required", "approval_id": "apr_5f2c…" } | +--> the tool DOES NOT RUN +--> runtime event + approval + audit entry, one transaction +--> your run stops here | v a security_lead resolves the approval in the control plane | v nothing is sent back to your agent. no callback. no token. no resume.

    What a correct integration does

    Stop the run, report the approval_id to the operator, and - if the work should continue later - re-enter it as a new run, which issues a new evaluate call and gets a fresh decision.

    What it never does

    Never poll evaluate waiting for the answer to change. Every accepted call writes an evidence row, so a loop turns one held action into a flood of them - and it converts a review control into a delay the agent eventually wins.

    Every surface stops the same way.

    How each integration surface behaves on approval_required
    Python SDKdecision.approval_required is true and approval_id is set. raise_for_decision() raises.
    TypeScript SDKSame shape. throwIfNotAllowed() throws.
    Framework adaptersRaise at the tool seam. The tool does not run.
    CLIPrints the decision and exits 4.
    RESTHTTP 200 with approval_required. Your branch must refuse.

    None of them waits. None of them retries.

    Private access

    Decide which actions deserve a human.

    The hard part is not the integration. It is agreeing which actions belong in each of the three answers.

    Human approvals - Anubis