Human-in-the-loop for CrewAI

Human-in-the-loop for CrewAI agents, on a phone.

Swap CrewAI's console human_input for a phone approval. Your agent waits for your user to tap Approve or Deny.

What CrewAI gives you

human_input=True on a task

Set human_input=True on a task and the crew stops after the agent drafts its output, prints it, and waits for someone to type feedback on stdin. It is useful while you develop: you see the draft and push back before the next agent picks it up.

native
task = Task(
    description="Draft the reply to the customer",
    agent=support_agent,
    human_input=True,   # blocks on input() at the terminal
)

Where it stops

  • It reads stdin. A container, cron job or queue worker has none, so it hangs or throws.
  • It stops the whole crew, and every other agent sits idle behind it.
  • The feedback is a string fed back to the model. Nothing records that a person reviewed it.
  • Only the person at that terminal can answer, never the user the action affects.

The fix

Pushary gets your user's answer.

human_input waits at a terminal. Pushary sends the question to your user's phone instead, waits for Approve or Deny, and saves every answer. Anything but a yes tells the agent not to proceed.

connect() returns the link your user opens once. make_ask_human_tool gives the agent a ready-made CrewAI tool bound to that user, so a prompt-injected model cannot ask someone else. The agent calls it and waits for the answer. A no, or no answer, means stop.

bash
pip install pushary-crewai
two calls
from crewai import Agent, Task, Crew
from pushary_crewai import connect, make_ask_human_tool

# Once per user: show them this link.
link = connect("user_123")

agent = Agent(
    role="Ops",
    goal="Ship safely",
    backstory="Careful operator.",
    tools=[make_ask_human_tool("user_123")],  # asks this user only; no answer means no
)

To block a risky action, ask inside its own code

The agent decides when to call make_ask_human_tool, so the tool is optional. A task that says “ask first” does not stop a refund. Call ask_human in the code that does the risky thing, and run it only when approved is true.

inside the risky action
from pushary_crewai import ask_human

d = ask_human("Approve this refund?", external_id="user_123", type="confirm")
if d["approved"]:
    issue_refund()

How it works

From install to the first answer

Connect your user once. Put the approval on the risky step. Pushary sends the question, waits for the answer and saves it.

  1. 01

    Install the adapter

    Run pip install pushary-crewai and put your API key in PUSHARY_API_KEY.

  2. 02

    Connect your user once

    connect() with your own user id returns a link. Your user opens it once on their phone and installs the free Pushary app. No account, no payment.

  3. 03

    Give the agent the tool

    Add make_ask_human_tool(user_id) to the agent's tools and drop human_input=True. For a refund or a delete, call ask_human inside that action's own code.

  4. 04

    Act on the answer

    Only an explicit Approve counts. A no, an expired request or no answer all tell the agent not to proceed.

A question can be a yes or no, a choice from a list, or a typed answer. Every answer is saved.

Before you ship

Things that bite on CrewAI

It works locally and hangs in production
This is the single most common CrewAI support thread. human_input=True is fine on a laptop and hangs without a sound the first time the crew runs with no terminal attached. If your crew stopped producing output after you deployed it, this is usually why.
Kickoff for many inputs asks about every item
kickoff_for_each with a human_input task prompts for every single item, one after another, at the terminal. Ten inputs means ten prompts nobody is there to answer.
Review is not the same as approval
human_input hands the agent feedback text to work in. It does not stop the task from finishing. If the action must not run without a yes, you need an Approve or Deny answer where no answer means no.

The Partner plan

Your agent asks your users, not just you

Ship your agent to your users. Each of them approves its risky actions from their phone, under your brand.

$99/ month, every framework included
Start free

Your users never make a Pushary account or pay us.

Your users answer on their own phones

Connect each user once with a link. They install the free Pushary app and answer from the lock screen, with no account of their own.

No answer means no

Run the action only after an explicit Approve. A request that is still waiting, expired or cancelled never counts as a yes. Pushary keeps every request, so your code can pick it up again after a restart.

Reaches them on their phone

The app comes first, because only the app puts Approve and Deny on the lock screen. Browser notifications come next. You build no delivery system.

Every answer saved

Every answer is saved with who answered and when. You can search and export it, and with a callback URL, each answer is also sent to your server as a signed webhook.

FAQ

Questions, answered

Does CrewAI have built-in human-in-the-loop?
Yes, for someone at the terminal. human_input=True on a task prompts on stdin, and Flows have @human_feedback. To reach your user on their phone instead, use make_ask_human_tool from pushary-crewai, or its Flow example, which plugs Pushary into @human_feedback and resumes the Flow when the answer arrives.
Is there a CrewAI package for Pushary?
Yes. pip install pushary-crewai gives you connect(), make_ask_human_tool(), a ready-made CrewAI BaseTool bound to one user, and ask_human() for use inside your own code. Add the tool for questions. To block a refund, call ask_human() inside the refund code.
How do I make a CrewAI approval fail-closed?
It already is. make_ask_human_tool and ask_human count only an explicit Approve as a yes. A no, an expired request or no answer all come back as not approved.
Can each of my end-users get approvals on their own phone?
Yes. Pass your own user id when you build the tool. Each user installs the free Pushary app and opens your connect link once, with no Pushary account. From then on each user answers for their own actions, instead of everything going to whoever launched the crew.
What can a human answer beyond yes and no?
A choice from a list, or a typed answer. Call ask_human() with type="select" and options, or type="input". The ready-made tool asks a yes or no question or for typed text. Choices and typed answers open the Pushary app on the phone. Treat a choice or text as data, never as permission to act.
Why does human_input hang when my crew runs in production?
Because it reads stdin, and production has no terminal. In a container, a cron job or a queue worker, the call either blocks forever or throws. This is the most common CrewAI surprise after deploying. Send the question to a phone instead, and a missing answer becomes a no instead of an endless hang.

Let your CrewAI agent ask before it acts.

Connect a user once, ask with one call, and run the action only on a yes. Every answer is saved.

Start free

Partner plan, $99 a month. Your users never make a Pushary account or pay us.