# 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.

Source: https://hibira.io/use-cases/ai-agents

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.](https://hibira.io/portal/articles/demo-ai-agents-en.mp4)

## Built with

- **Private channels** per run, such as `private-agent-run-42`, for steps and results.
- **[@hibira-io/approvals](https://github.com/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](https://hibira.io/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.

```text
flow: The agent's steps reach the user, and a risky tool call waits for a person
== Steps and results
Your agent|one event per step --`trigger()`--> *Hibira --WebSocket--> The user's page|live list of steps
== A tool call that needs an OK
Your agent|pauses the run --`approvals.request()`--> *Hibira --WebSocket--> Reviewers' inbox|approve, edit or reject
```

## 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:

```js
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:

```js
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.

```js
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:

```jsx
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](https://hibira.io/guides/filament-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](https://hibira.io/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.

```sh
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:

- [n8n](https://hibira.io/guides/n8n), whose Hibira node also works as a tool for n8n AI agents
- [Make](https://hibira.io/guides/make)
- [Node-RED](https://hibira.io/guides/node-red)
- [Activepieces](https://hibira.io/guides/activepieces)

## 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](https://hibira.io/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](https://hibira.io/use-cases/job-progress).
- 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](https://hibira.io/guides/push-notifications).
