/sessions/<id> in agentuse serve: it shows the run log, and when the session is suspended on an approval gate it also offers approve / reject / comment right there. /approvals remains as a filtered list of sessions currently waiting for review, and each row links to the session page. Slack is optional: it can notify reviewers and link them into the session page, but Slack is not where approval state lives.
How It Works
- Add
approval: trueto the agent frontmatter. - Run
agentuse serve. - The agent works normally until it reaches the approval point.
- AgentUse suspends the session on a pending approval gate.
- Reviewers open the session page (
/sessions/<id>), either from/approvalsor from a tokenized link. - A reviewer approves, rejects, or comments.
- AgentUse resumes the suspended session with the reviewer result.
- After the session finishes, reviewers can send follow-up instructions from the same session page to continue the session with its existing context.
A leaf agent’s approval gate works the same whether the agent is run directly or delegated by a
type: manager agent. See Approval in delegated sub-agents below.Create an Agent with Approval
Use the smallest possible config:Define the Approval Boundary
Approval gates are agent-driven: the agent calls the internalawait_human tool when it reaches the point where review is needed. AgentUse injects the approval mechanism, but your agent instructions can still define the policy boundary for your workflow.
Write the boundary in business terms. Describe what the agent may prepare without approval, and what it must not finalize until approval is granted.
For a social publishing agent:
- Usually safe before approval: local temp files, drafts, previews, dry runs, summaries, draft PRs
- Usually approval-required: publishing, sending email, scheduling posts, deploying, merging, deleting, charging, or changing production/external state
- If unsure, ask for approval before the action
Gated commands (mechanical enforcement)
The boundary above is guidance the model follows. For irreversible bash commands you can also enforce it mechanically, so the command cannot run before you approve it even if the model tries. List those commands undertools.bash.gated:
commands is what the agent can do; gated is what it can’t do without you. A gated command is still allowed to run (the effective allowlist is commands plus gated), but only after a human approves the exact action. A command matching both lists is gated (gated wins), so a broad birdc * in commands cannot un-gate birdc reply *.
Declaring gated enables the approval machinery automatically, you do not also need approval: true. When the agent reaches a gated command, AgentUse has it present the plan through await_human, and the command runs only once you approve.
The guarantee is two-fold, enforced per action (not once per session):
- A gated command never runs before approval.
- A gated command never runs anything other than what you approved. Approval binds to the exact complete shell command shown in
changes[]; payload text by itself grants nothing. If the agent revises the command or its payload, the old approval no longer covers it and it must re-gate.
- You rarely hand-write this. Skills that ship posting commands, the interactive command prompt, and generated agent files add
gatedfor you.agentuse doctor <file>also flags an allowlisted command that looks irreversible (reply,post,delete,git push,curl -X POST, …) but is not gated. AgentUse never auto-gates from a keyword guess, it only suggests. - Show the complete command. Put the exact executable command (
birdc reply "text") inchanges[]. You can show the reply text separately for readability, but only the complete-command entry creates the lease. For browser automation, gate and show the step that carries the words (agent-browser type "..."), not a contentless click. - Unattended runs suspend only on a declared gate, never on a tooling question. You approve outcomes, not commands.
Start the Server
Start the AgentUse daemon:/sessions/<id>.
If reviewers open links from another machine, start serve with a reachable public URL:
--public-url when reviewers need a URL other than the local server address.
Optional Slack Channel
Slack can alert reviewers when an approval is waiting. Approval state still lives in the AgentUse session page. The Slack channel message stays concise, and supporting approval details are posted in the message thread when the agent provides them. Those thread details can include summary, draft, artifact, context, and risk.Reviewer Flow
The session page shows the best available review details from the agent:prompt: the reviewer-facing decision promptchanges: the exact actions taken on approval, one{ label, content }entry per discrete action. Each renders as a highlighted “On approval” box with a copy button and character count, so the reviewer skims the verbatim payload firstreference: the original item the action responds to ({ label, author, title, url, excerpt }), such as the post being commented on or the message being replied to. Renders as a quoted card directly above the changesoptions: two or more choices for the reviewer, each with anid,label, and optionaldescription/recommended. The session page renders a single-choice picker before the decision controls. On approval, the selected id reaches the agent astoolResult.choicesummary: what changed and what is being approveddraft: inline draft content. Whenchangescarries the verbatim payload, the draft renders collapsed as supporting detaildraft_url: URL to a draft artifactartifact_url: URL to the primary review artifact, such as a PR, preview, document, or generated artifactartifact_path/artifact_paths: project-relative local files the session page can open in the artifact viewer. Images, HTML, and PDF artifacts render inline; MP4/WebM/MOV/M4V video and MP3/M4A/WAV/OGG audio use native players. Files are snapshotted at gate time so the reviewer approves immutable bytescontext: background the other fields do not already carry (constraints, inputs used, process notes); agents are steered to omit it rather than repeat the reference, changes, or summaryrisk: known risks, unresolved questions, or reviewer attention areas- Session logs before and after the decision
Approve: resumes the agent withstatus: "approve"Reject: resumes the agent withstatus: "reject"Comment: resumes the agent withstatus: "comment"and the reviewer comment
toolResult.choice.
On reject, AgentUse passes the decision back to the agent instead of applying a
universal workflow state change. If the agent tracks drafts, queue items, or
tasks in a store, describe the rejected-state transition in the agent
instructions, such as “when rejected, mark the current draft item rejected”
or “when rejected with feedback, mark it needs_revision.”
When Slack Socket Mode is configured, the approval details thread can also accept Approve, Reject, Comment, and normal thread replies. Without Socket Mode, reviewers open the session page link to decide.
When the agent receives a comment, it decides whether to revise, ask for approval again, or stop with a clear explanation.
After the run completes, the same session page becomes a lightweight continuation surface. Add a follow-up instruction in the Resume session box to resume the completed or errored session with its existing context. This matches Slack thread replies, but keeps the web session page as the source of truth for details and logs.
If an approval decision was submitted but the resumed run failed downstream, the session page may offer Retry. Retry reopens the latest resolved approval gate, preserves the original session token, and lets the reviewer submit the decision again. Use it only when it is safe to retry the downstream work; the UI warns about possible duplicate external side effects.
Approval in delegated sub-agents
A leaf agent’s approval gate behaves identically whether you run it directly or atype: manager agent delegates to it. You define approval: true once on the leaf, and the same human gate fires in both modes. Only the channel the request surfaces through changes.
reply-to-post.agentuse — the leaf, reused in both modes
- Run it directly (
agentuse run reply-to-post.agentuse) and you get the gate, as for any top-level agent. - Delegate it from a manager and the same gate fires inside the sub-agent. The request surfaces on the manager run’s session page (and the
/approvalsinbox, and Slack if configured), labeled with the originating leaf. Approve / reject / comment there: the decision resolves the leaf’s gate, the leaf finishes, and the manager resumes automatically.
manager.agentuse — delegates to the same leaf, unchanged
Approve at the manager root. The delegated leaf’s own session page is view-only and links up to the manager run, where the decision is made. This keeps one canonical approval surface per run.
- One approval at a time per manager run. To gate several items, have a single leaf loop and call the gate once per item (it re-suspends and re-surfaces at the root each time), rather than fanning out to many sub-agents that suspend simultaneously, concurrent multi-gate fan-out is not yet supported.
- The human always decides outward/irreversible actions (human relay). Automatic, classifier-based approval of low-risk calls is a separate, later option.
- Resolve a delegated gate from the manager’s approval page,
/approvalsinbox, or Slack, notagentuse sessions resume, which handles only single-session gates.
Configuration Fields
Approval config is intentionally small:approval:trueor an object to enable the approval gateapproval.timeout: optional suspension timeout, such as30m,24h, or7d. A bare number means seconds.tools.bash.gated: bash command patterns that run only after human approval, enforced by a per-action lease. Declaring it implies the approval gate. See Gated commands.
channels: optional external collaboration channels, such aschannels: [slack]channels.slack.events: events for Slack. Approval gates useapproval; terminal run events are documented in Channels.channels.slack.channel_id: Slack channel id. If omitted, AgentUse usesSLACK_APPROVAL_CHANNEL.channels.slack.enabled: optional switch for temporarily disabling Slack
Auth and the session token
Authentication follows the deployment invariant:- Local bind (
127.0.0.1/localhost): no API key, no token. View and approve are fully open. - Exposed host:
serverefuses to start withoutAGENTUSE_API_KEY(use--no-authto bypass, dangerous). The API key (Authorization: Bearer) authorizes everything.
Bearer header is not clickable from a Slack message or an email, each session also has a session token: a stateless, per-session value that stands in for the API key on that one session’s page.
await_human mints this token when it builds the reviewer link, so Slack/email links are clickable without an API-key login.
While a run is suspended, anyone with its session link can approve it. A completed run has no pending gate, so a shared completed-log link cannot approve anything. The view + approve conflation only matters during the approval window.
Experimental session / approval API
The API is experimental and mirrors the web session page contract. Use it to build custom review UIs or integrations. JSON endpoints live under the/api/* prefix and are always API-key gated on an exposed host. The HTML session page and its action subroutes carry their own capability auth (session token / API key / local), so a tokenized link works without a Bearer header.
List sessions as JSON (filter by agent, trigger, or time window with days):
?token=) or a Bearer
header; the current pending gate is resolved server-side, so you do not pass a
gate token:
suspended so the normal decision flow can run again:
Legacy approval routes.
GET /approvals/:id now redirects to /sessions/:id, and the older /approvals JSON list plus the /api/approvals/:id/{status,decision,continue} action endpoints remain available for backward compatibility. Those legacy action endpoints still take a gate resumeToken in the body. In-flight Slack links from before the upgrade keep working: the session page also accepts a valid gate resumeToken as a credential until those approvals expire. Prefer the /sessions routes and the session token for new integrations.Local Testing
For development or manual testing, you can resume a suspended session from the CLI:/approvals UI for normal review, Slack for reviewer alerts, the Approval API for custom review surfaces, and agentuse sessions resume for local testing.