> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ctrlrun.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# CTRLRun and framework human-in-the-loop

> A framework interrupt is where a human says yes. It does not bind that yes to the arguments that execute, or refuse a retry after a lost reply. Use both.

A framework's human-in-the-loop primitive is the right place for a human to answer, and CTRLRun
uses it rather than replacing it. What it does not do is bind that answer to the exact action
that executes, notice that the same effect already happened, or leave evidence outside the
framework's own run state. Those are different jobs, and an adapter joins them.

## What a framework interrupt is good at

LangGraph's `interrupt()` and the OpenAI Agents SDK's tool-approval interruption both stop a run
at exactly the right moment, carry the pending call to whatever console your operators use, and
resume the run where it stopped. They are integrated with the framework's state, its
checkpointing and its streaming, and they are what your users already know. Nothing here
replaces that; the adapters exist so a human keeps answering there.

## What it does not do

|                                        | A framework interrupt                                               | CTRLRun                                                                                                     |
| -------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Where the yes is given                 | in the framework's own console                                      | the same place, through an adapter                                                                          |
| What the yes authorizes                | a tool call, identified by the framework's id                       | one canonical action, identified by a SHA-256 over its name, arguments, resource, principal and environment |
| A second, different call after the yes | usually still approved: the record is keyed to the tool or the call | refused, unless it hashes the same                                                                          |
| The same effect twice                  | not its question                                                    | refused: one effect key, reserved atomically across processes and hosts                                     |
| A lost reply                           | an error the loop may retry                                         | `AMBIGUOUS`; a blind retry is refused until a human or a hook resolves it                                   |
| Evidence afterwards                    | the run's own trace, in the framework's format                      | a portable JSON receipt, chained, readable without the framework                                            |
| Coverage                               | that framework's tool calls                                         | anything in the process, plus anything behind an MCP server, in any language                                |

## When to use both

If your agent runs on LangGraph or the Agents SDK and your operators answer there, install the
adapter: `@protect(wait=True)` sends the approval out through the framework's interrupt, the
answer comes back, and one core provider writes the grant through the same calls
`ctrlrun approve` makes. Two places to say yes would be one place nobody is watching, so there
is only ever one.

If your framework has no such primitive, you need no adapter. `@protect` covers the call
anyway, and `ApprovalRequired` is raised for your own code to handle.

## The distinction that matters

A framework binds an approval to *a call it is about to make*. CTRLRun binds it to *what that
call would do*. Where the framework's resumption carries the arguments the human saw, an
adapter hands them back and CTRLRun re-checks the hash: prevention. Where it carries only a
verdict, CTRLRun records who answered and cannot re-check what about: attribution. Each
adapter's page says which it is, in that word.

## Next

* [Three ways in](/get-started/three-ways-in): when an adapter is the answer and when it is not.
* [Use the LangGraph adapter](/guides/langgraph-adapter) · [Use the OpenAI Agents SDK adapter](/guides/openai-agents-adapter).
* [Get started](/get-started/quickstart) · [Why](/why).


## Related topics

- [CTRLRun](/index.md)
- [FrameworkInterrupt](/reference/api/FrameworkInterrupt.md)
- [Three ways in](/get-started/three-ways-in.md)
- [Adapters](/adapters.md)
- [Choosing between them](/get-started/choosing.md)
