Run agents

Approvals

Let a person decide before a tool call runs, with the job waiting durably until someone does.

Some calls should not happen without a person saying yes: merging a pull request, sending money, deleting data. List them in the tool's requires_approval, and every call to them waits for a decision.

oz0-plugin.yaml
tools:
  - id: github
    mcp: ["python", "-m", "github_tools.mcp"]
    requires_approval: [github.merge]

The tool's plugin decides this, so it holds for every agent that uses the tool, from any plugin.

What happens

  1. The agent calls github.merge. Before the call runs, the job asks for a decision and waits. It shows up on the web UI's Approvals page, on the job's page, in orchestrator-zero approval list, and in the job's live stream.
  2. An admin approves or denies it, with a comment if they like.
  3. Approved: the call runs and the agent goes on. Denied: the call is not made, and the agent is told who said no and why, for example The call to github.merge was not made: user:kevin denied it: not before the release., so it can explain or try something else.
  4. No answer within 24 hours counts as a no: nobody answered.

The wait is part of the job's durable state in Temporal. It costs nothing while it lasts, and it survives restarts of servers and nodes: the job goes on wherever its agent can run once someone decides.

Decide from the web UI

Approvals in the sidebar lists everything that waits, with a count, oldest first: what waits, the agent, the job, how long it has waited and when it is denied unless someone answers. Click one to open it in a drawer with the call's arguments. The job's own page shows its pending approvals above its tabs. Write a comment if you want the agent to know why, then Approve or Deny.

Operators, admins and owners of the tenant decide; readers see what waits but cannot decide, and see the call's arguments only with the permission to see the tenant's content.

Decide from the CLI

Terminal
orchestrator-zero approval list
orchestrator-zero approval approve job-bb270cf1-... a-3d3774fd06c3 --comment "fine by me"
orchestrator-zero approval deny job-bb270cf1-... a-3d3774fd06c3 --comment "not before the release"

orchestrator-zero run and job watch show a waiting call as it happens, with the command that approves it:

helper → team.hello {"name":"e2e"}
helper ⏸ team.hello waits for approval a-3d3774fd06c3: {"name": "e2e"}
  orchestrator-zero approval approve job-0879b9bc-... a-3d3774fd06c3   (or deny)
helper ▶ team.hello approved by operator:admin: fine by me
helper ← team.hello Hello, e2e!

From your own app

The runtime API has ListApprovals and DecideApproval. The edge records who decided from the caller's credentials; a request cannot name someone else.

Approvals cover tool calls of Pydantic AI agents, flow steps with approval:, hooks that answer escalate, and the tools of a harness session listed in the agent's harness.requires_approval, which wait as claude-agent-sdk.Bash and the like. A timeout other than 24 hours, and approvals limited to a role per tenant, come later.
Copyright © 2026