Human-in-the-loop for CrewAI

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

Replace the console human_input prompt with a Pushary custom tool. Run pip install pushary, wrap client.decisions.ask() in a CrewAI BaseTool, and give that tool to your agent. When the agent reaches an approval or a question, decisions.ask blocks fail-closed until a real person answers on their phone, then returns the decision. Connect each end-user's phone once with a one-tap link keyed to your own externalId. There is no @pushary/crewai package, because CrewAI is Python, so you use pip install pushary.

pip install pusharytwo calls
import os
from crewai.tools import BaseTool
from pushary import PusharyServer

px = PusharyServer(api_key=os.environ["PUSHARY_API_KEY"])

class AskHuman(BaseTool):
    name: str = "ask_human"
    description: str = "Ask a person to approve before acting."

    def _run(self, question: str) -> str:
        d = px.decisions.ask(question=question, external_id="user_123", type="confirm")
        return "approved" if d["approved"] else f"not approved ({d['status']})"

# agent = Agent(role="...", tools=[AskHuman()])

Why you need it

CrewAI pauses the agent. Pushary reaches the human.

CrewAI's built-in human_input=True only prompts on stdin, so nothing happens unless someone is watching the terminal. Pushary moves that approval to the person's phone: decisions.ask() blocks fail-closed until they answer, delivers to the device they carry, and logs every answer. Each of your end-users approves their own decision.

How it works

From ask to resume

Connect the phone once, then ask a human from the tool or step that guards the action. The waiting, the delivery, and the record are handled for you.

  1. 01

    Install the Python SDK

    Run pip install pushary and set your API key.

  2. 02

    Connect the phone

    Call client.enroll(external_id) once per end-user to connect their phone with a keyless one-tap link.

  3. 03

    Wrap decisions.ask in a tool

    Subclass BaseTool and call px.decisions.ask() in _run. Give the tool to Agent(tools=[...]) and drop human_input=True.

  4. 04

    Keep it fail-closed

    Treat anything that is not an explicit approval as a stop. A declined, expired, or unanswered decision means the agent does not act.

A decision is a yes or no confirm, a multiple-choice select, or a free-text input. Every one is stored with its outcome and kept in the audit log.

For your users

Your agent asks your users, not just you

Ship the agent to real users and let each of them approve their own decisions from their phone, under your brand.

Your users answer on their own phones

The externalId is your own id for the end-user. Connect their phone once with a keyless one-tap link, and every approval lands with the right person. No account, no app, no key on their side.

Durable, fail-closed waits

The agent stays open on a durable wait backed by a decisions ledger. If nobody answers in the window you set, the decision comes back denied, so a timeout or a restart never turns into an unapproved action.

Phone-first delivery

Pushary reaches the person on the device they carry: native app push first, then PWA push notifications, then Slack if you route it there. You do not build a delivery pipeline.

Signed webhooks and an audit trail

Every decision is written to a durable ledger you can query and export, and resolved decisions post a signed webhook to your callback URL. You have the record of who approved what and when.

FAQ

Questions, answered

Human-in-the-loop for other frameworks

Let your CrewAI agent ask a human.

Connect a user with one tap, ask a human with one call, and act on a fail-closed decision. The durable store and the audit log come with it.

Partner plan, $99 a month. Your users never see a Pushary login or bill.