← Use cases

AI agents: live steps, approvals and alerts

Show each step an agent takes as it works, hold risky tool calls in a live inbox until a person approves them, and send results to browsers and phones from agents, MCP clients and no-code flows.

An AI agent that works for a minute with nothing on screen looks stuck, and one that refunds an order without asking is worse. Hibira gives your agents the same realtime channels the rest of your app uses. Each step shows up as it finishes, a risky tool call waits in a live inbox until a person approves it, and the result reaches the right people in the browser or on their phone.

What your users get

  • Each step of the agent's work ("Looked up the order", "Drafted the reply") as it finishes, in every open tab.
  • Approval requests that appear in the inbox at once, with the other reviewers who are looking, so two people don't decide the same refund.
  • A push notification when the agent is done or needs a decision and nobody has the page open.
An agent run on the left and the approvals inbox on the right: the steps appear as they finish, the refund waits for a reviewer, and after Approve the agent carries on to the end.

Built with

  • Private channels per run, such as private-agent-run-42, for steps and results.
  • @hibira-io/approvals for the approval inbox: server helpers for the Vercel AI SDK, Mastra and LangGraph (JavaScript and Python), plus React and Vue components.
  • Presence channels, so reviewers see who else has a request open.
  • The MCP server tools publish_event, send_push and request_approval, for agents that run in Claude, Cursor or another MCP client.
  • Push notifications through the Beams-compatible API.

Steps and results

Your agentone event per step
trigger()
Hibira
WebSocket
The user's pagelive list of steps

A tool call that needs an OK

Your agentpauses the run
approvals.request()
Hibira
WebSocket
Reviewers' inboxapprove, edit or reject
The agent's steps reach the user, and a risky tool call waits for a person

Step 1: publish each step from the agent

With the Vercel AI SDK, onStepFinish runs after every step. Send the tool names, not their input, so events stay small and nothing sensitive crosses the socket:

import { generateText, stepCountIs } from 'ai';

const channel = `private-agent-run-${run.id}`;
const result = await generateText({
  model,
  tools,
  messages,
  stopWhen: stepCountIs(10),
  onStepFinish: async ({ toolCalls }) => {
    if (toolCalls.length) {
      await pusher.trigger(channel, 'step', { tools: toolCalls.map((c) => c.toolName) });
    }
  },
});
await saveRun(run.id, result.text);
await pusher.trigger(channel, 'done', { id: run.id });

In the browser, subscribe before the run starts and show a label for each tool. Your channel authorization route should allow private-agent-run-42 only for the user who started run 42:

const channel = pusher.subscribe(`private-agent-run-${runId}`);
channel.bind('step', ({ tools }) => tools.forEach((t) => steps.add(LABELS[t] ?? t)));
channel.bind('done', async ({ id }) => showResult(await fetch(`/runs/${id}`).then((r) => r.json())));

Other agent frameworks work the same way: call trigger() wherever a step ends.

Step 2: ask a person before a risky tool runs

Mark the tool with needsApproval. When the run stops on it, open a request: reviewers get an approval event on private-hibira-approvals.support.inbox at once.

import { tool } from 'ai';
import { createApprovals } from '@hibira-io/approvals';
import { approvalCalls } from '@hibira-io/approvals/ai-sdk';

export const approvals = createApprovals({ pusher, scope: 'support', resume });

const tools = {
  refund_order: tool({ inputSchema, needsApproval: true, execute: refund }),
};

const calls = approvalCalls(result);
if (calls.length) {
  await approvals.request({ agent: 'Support agent', title: 'Refund order #1042', calls, metadata: { chatId } });
}

Reviewers decide in the inbox component. It calls your backend through the routes of approvals.handler(), never through client events, and your resume(request) hands the answers back to the agent, once, even if two reviewers press Send together:

import { ApprovalInbox, createApprovalsClient } from '@hibira-io/approvals/react';
import '@hibira-io/approvals/styles.css';

const client = createApprovalsClient({ endpoint: '/api/approvals', pusher, scope: 'support' });

export function ApprovalsPage({ me }) {
  return <ApprovalInbox client={client} me={me.id} />;
}

The same package has helpers for Mastra (requireApproval and suspend()) and LangGraph (interrupt()). For Python, pip install "hibira-approvals[pusher,fastapi]" gives LangGraph Python the same requests and a FastAPI router for the inbox. Building on Laravel? Filament AI approvals puts the inbox in your Filament panel for agents built with the Laravel AI SDK.

Step 3: agents in Claude, Cursor and other MCP clients

An agent that runs in an MCP client can use Hibira without any code of yours. Add the MCP server and it can:

  • send progress and results to your channels with publish_event, so a dashboard or a teammate's browser follows the work,
  • send a push notification to an interest or a user with send_push when it finishes,
  • ask a person with request_approval: it returns a link to a hosted page where they choose an answer, and get_approval waits for it. Pass a channel and the request also appears in the inbox above.
claude mcp add --transport http hibira https://hibira.io/mcp

Step 4: no-code flows

The same events come from automation tools too. A flow can publish a step or a result to a channel, send a push notification, or start when something happens on a channel:

Tips

  • Keep events small: send IDs and short labels, and fetch the full result from your server. The size limit depends on the plan, see pricing.
  • Store every step and request in your database as well, so a page opened later shows the whole run.
  • For an agent that writes its answer token by token, see Progress for long jobs and streaming AI answers.
  • Approval requests carry no tool input over the socket. The inbox fetches it from your backend, which checks that the user may review.
  • When nobody is online to review, use the notify option of createApprovals() to send a push notification to the reviewers with the push notifications guide.