# Human-in-the-loop
```python
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
model="claude-sonnet-4-6",
tools=[send_email],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={"send_email": {"allowed_decisions": ["approve", "edit", "reject"]}}
)
],
checkpointer=InMemorySaver(),
)
```
## The flow
1. The agent calls a gated tool. Execution pauses with an interrupt instead of running it.
2. Your UI presents the proposed call and collects approve, edit, or reject.
3. Resume the graph with the decision. Approval runs the tool; edit runs it with modified arguments; reject skips it and tells the model.
## Rules
- Interrupts require a checkpointer. Without one you get MISSING_CHECKPOINTER at the worst possible moment.
- Resume with the same thread id. A new thread id starts a new conversation and orphans the paused one.
- Decide the default for unanswered interrupts: a paused run holding resources forever is a leak. Time them out or surface them in an ops view.
- Test all three decisions. Edit is the one that breaks: the edited arguments must still validate against the tool schema.