Risky ops wait for a person.

Risky operations escalate to a person for one-off approval. The agent holds on the wire with the exact statement attached, then continues the moment someone decides.

Pass and block are not enough.

The expensive cases sit in between: a cleanup that is right on Tuesday and a disaster on Friday.

Most operations are obviously fine or obviously not, and a rule handles those. The rest look like a migration that has to run or a backfill on a live table. Block them and the agent cannot do the work you gave it. Allow them and you trust a model with a decision nobody signed off on.

Who decides
  • Obviously fineA rule passes it
  • In betweenA person decides
  • Obviously notA rule blocks it

Most operations never reach a person.

The operation stops and waits.

Nothing reaches your resource while the agent waits for an answer. The statement sits in the sidecar, where it was intercepted, until a person approves it or turns it down.

  1. One operation, one decision

    An approval covers this statement, this time. It does not open a window, grant a role, or widen access for anything that comes after it.

  2. The statement is attached

    The approver reads the exact operation, not a ticket describing it. No paraphrase to check and nothing to reconstruct later.

  3. The agent waits on the wire

    The connection stays open. Nothing queues for a retry and no work is thrown away, so the agent resumes where it stopped.

  4. The record writes itself

    Who asked, what they asked for, who decided, and when. The evidence comes out of the decision, not out of a reconstruction for an auditor.

The agent waits.

Send one risky write through the sidecar. Hold it, then decide, and read what the agent sees at each step.

Nothing reaches the database. The connection stays open.

agent-07 → prod-db:5432 · task: close shipped orders
UPDATE orders SET status = 'delivered';
NOTICE:  held by hoop for approval
DETAIL:  write against a production table, no WHERE clause
REQUEST: sent to the approver, statement attached
WAITING:  · connection open
SCOPE:   this statement, this time

agent-07 waits on the open connection
nothing has run, no retry is queued

A hold is not a failure.

The agent is not told no. It is told to wait, and the connection stays open while it does. When the approval lands, the statement runs and the agent carries on with the work it was doing.

That is the difference between a control that governs an agent and one that just stops it.

Four controls, one sidecar.

Decide what needs a person.

Everything else passes or gets refused on its own. Free and open source under MIT.

Ask an assistant how Human in the Loop works: Claude, ChatGPT, Grok, Gemini, Perplexity, Copilot.

# config.yaml
analyzer:
  provider: anthropic
  model: claude-sonnet-4-5
  credentials_file: /run/secrets/anthropic-key

listeners:
  - name: localdb
    protocol: postgres
    listen: 127.0.0.1:15432
    upstream: 127.0.0.1:5432
    analyzer:
      trigger: {operations: [update, delete]}
      high: require_review   # the person at the terminal decides

$ hoop start sidecar --config config.yaml
sidecar running