Human Approval Gates

Which actions require human sign-off: agent hiring, strategic pivots, agent termination, budget increases. The approvals table schema and how pending approvals block execution.

Approval Gates: Human-in-the-Loop Control

What you'll learn

The four default approval triggers, the approvals table schema, and how to configure custom approval policies for your organization.

What Are Approval Gates?

Approval gates are moments where autonomous agent action is paused and a human (or higher-authority agent) must sign off before execution continues. They are the safety mechanism that lets you run autonomous agents while keeping critical decisions under human control.

The Four Default Triggers

Paperclip ships with four built-in approval triggers that cannot be bypassed:

Trigger What requires approval
hire_agent Creating a new agent in the company
terminate_agent Setting an agent status to terminated
budget_increase Raising monthly_budget_usd above current value
strategy_change Modifying core company settings (webhook URLs, heartbeat schedule)

These protect against runaway agents attempting to self-modify the company configuration.

The approvals Table

CREATE TABLE public.approvals (
  id                    uuid        PRIMARY KEY DEFAULT gen_random_uuid(),
  company_id            uuid        NOT NULL REFERENCES companies(id),
  trigger               text        NOT NULL,
  status                text        NOT NULL DEFAULT 'pending'
                                    CHECK (status IN ('pending','approved','rejected','expired')),
  requesting_agent_id   uuid        REFERENCES agents(id),
  reviewer_agent_id     uuid        REFERENCES agents(id),
  human_reviewer_email  text,
  details               jsonb,       -- what is being approved
  decision_note         text,        -- reviewer's comment
  created_at            timestamptz NOT NULL DEFAULT now(),
  expires_at            timestamptz,
  decided_at            timestamptz
);

Creating a Custom Approval Policy

In Company Settings → Approval Policies → Add Policy:

{
  "trigger": "publish_content",
  "condition": {
    "field": "word_count",
    "operator": "gt",
    "value": 1000
  },
  "required_approver": "human_editor",
  "expiry_hours": 48,
  "on_expire": "reject"
}

When a Writer agent finishes a 1200-word article, Paperclip:
1. Sets the issue to status = 'escalated' (not resolved)
2. Creates an approvals row with trigger = 'publish_content'
3. Notifies human_editor via webhook/email
4. If no decision within 48 hours, auto-rejects

Querying Pending Approvals

SELECT
  ap.id,
  ap.trigger,
  ap.status,
  req.name   AS requested_by,
  ap.details,
  ap.created_at,
  ap.expires_at
FROM approvals ap
LEFT JOIN agents req ON req.id = ap.requesting_agent_id
WHERE ap.company_id = 'your-company-id'
  AND ap.status = 'pending'
ORDER BY ap.created_at ASC;

Approving / Rejecting via API

# Approve
curl -X POST http://localhost:3100/api/companies/${COMPANY_ID}/approvals/${APPROVAL_ID}/approve \
  -d '{"note": "Looks good, content quality is acceptable"}'

# Reject
curl -X POST http://localhost:3100/api/companies/${COMPANY_ID}/approvals/${APPROVAL_ID}/reject \
  -d '{"note": "Title is misleading, needs rework"}'

On approval: the original action proceeds (issue resolved, agent hired, budget raised).
On rejection: the action is cancelled and the requesting agent receives the rejection note.

Checkpoint ✓

Sign in for progress tracking & Q&A →