# ToolStatusIndicator

> Compact dot, label and state rows that report tool activity in the onboarding and meetings chats.

## Facts

- **Product**: Max
- **Family**: Agents
- **Global**: `window.DigitalCrew.ToolStatusIndicator`
- **Source**: `max-agent: src/features/onboarding-hermes/ui/parts/tool-call-indicator.tsx`
- **Import in the app**: `import { ToolStatusIndicator } from "@/features/onboarding-hermes/ui/parts/tool-call-indicator";`
- **Live preview**: /design/components/tool-status-indicator/preview.html
- **Page**: /design/components/tool-status-indicator

## Guidelines

This card covers `ToolStatusIndicator` and `DirectToolCallIndicator`, which share one row design.

**Use it for** stream parts that say a tool is connecting or a call is in flight, stacked in an `.ob-calls` column above the agent's text.

**What you provide**
- `ToolStatusIndicator`: `data: ToolStatusData`, which is `{ tool, status, message? }`.
- `DirectToolCallIndicator`: `data: DirectToolCallData`, which is `{ tool, action, status, message? }`. `tool` is `"notion"`, `"hubspot"`, `"gmail"` or `"claire_mcp"`.
- `status` is `"running"`, `"success"` or `"error"`.

**Anatomy** (`.ob-call*`)
- A flex row with an 8px gap, 12.5px text and line-height 1.4.
- A 7px dot: `#f59e0b` amber pulsing every 1.2s while running, `#10b981` green on success, `#ef4444` red on error.
- The label is set 500 in `--mx-ink` with `text-transform: capitalize`; underscores become spaces.
- Direct calls read "tool · action" and add a 10.5px pill badge labelled "direct".
- The state sits right-aligned at 11.5px: "connecting…", "connected" or "failed". On error, `message` replaces it.

**Setup**: the rows read the `mx-*` variables, so place them inside `.maxchat`. Muted text uses `--mx-ink-soft`, which falls back to `#6b7280`.

**Don't** use these rows for long results or payloads. A tool's details belong in [`ThinkingBox`](/design/components/thinking-box.md).

## API

```ts
export type CallStatus = "running" | "success" | "error";
export interface ToolStatusData {
    tool: string;
    status: CallStatus;
    message?: string | null;
}
export interface MaxApiCallData {
    service: "unipile" | "mcp";
    capability: string;
    status: CallStatus;
    message?: string | null;
}
export interface DirectToolCallData {
    tool: "notion" | "hubspot" | "gmail" | "claire_mcp";
    action: string;
    status: CallStatus;
    message?: string | null;
}
export declare function ToolStatusIndicator({ data }: {
    data: ToolStatusData;
}): any;
export declare function MaxApiCallIndicator({ data }: {
    data: MaxApiCallData;
}): any;
export declare function DirectToolCallIndicator({ data }: {
    data: DirectToolCallData;
}): any;
```

## Example

```html
<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  var STATUS = [
    { tool: "hubspot", status: "success" },
    { tool: "notion", status: "running" },
    { tool: "gmail", status: "error", message: "Access was denied" }
  ];
  var DIRECT = [
    { tool: "hubspot", action: "create_contact", status: "success" },
    { tool: "notion", action: "search_pages", status: "running" },
    { tool: "claire_mcp", action: "enrich_company", status: "error", message: "Timed out after 30s" }
  ];
  function Section(title, children) {
    return h("div", null,
      h("div", { className: "mb-2 flex items-baseline gap-2 text-[11px]" },
        h("code", { className: "font-mono font-semibold", style: { color: "var(--mx-ink-2)" } }, title[0]),
        h("span", { style: { color: "var(--mx-ink-3)" } }, title[1])),
      h("div", { className: "ob-calls" }, children));
  }
  function App() {
    return h("div", { className: "maxchat mx-auto max-w-[560px] gap-5 rounded-2xl border border-border/60 p-5", style: { height: "auto" } },
      Section(["ToolStatusIndicator", "data-tool-status part: a direct tool connecting"],
        STATUS.map(function (d, i) { return h(DC.ToolStatusIndicator, { key: "ts" + i, data: d }); })),
      Section(["DirectToolCallIndicator", "data-direct-tool-call part: a call made by the agent"],
        DIRECT.map(function (d, i) { return h(DC.DirectToolCallIndicator, { key: "dt" + i, data: d }); })));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>
```

## More in Agents

- [AgentAvatar](/design/components/agent-avatar.md): A Digital Worker's face as a muted, looping video in a rounded square, framed and glowing in the agent's brand colour, with an optional live dot.
- [AgentSkillTag](/design/components/agent-skill-tag.md): A tiny chip naming one of a Digital Worker's skills, tinted with that worker's colour.
- [AskMaxAction](/design/components/ask-max-action.md): A contextual "Ask Max" button.
- [CrewAgents](/design/components/crew-agents.md): The Digital Crew's eight agents, each one colour broken out of the ink: the palette ramp, the gradient, the role and the skills the public site gives them.
- [EquipmentBadge](/design/components/equipment-badge.md): A small chip showing one piece of a Digital Worker's desk equipment as an emoji, with or without its label.
- [MaxRoster](/design/components/max-roster.md): Max's 24 Digital Workers in their seven teams, each with its face (**AgentFace**) and accent dot.
- [OAuthRequestCard](/design/components/oauth-request-card.md): A "Connect HubSpot" or "Connect Notion" card that an agent drops into the chat.
- [ThinkingBox](/design/components/thinking-box.md): Max's thinking box: the running account of what he thought, which tools he called, what he sent and what came back.
