Skip to content
Back to skills

Iblai Vibe Agent Billing

CSecurity

Add the agent Billing tab (LLM spend limits for the agent and per user, with usage bars, block/alert enforcement, and near-limit alert thresholds) to your Next.js app

  • 15 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 2, 2026
developmentgobashnextjsgitapibackend

Works with

  • cli
  • api
  • mcp

Security analysis

C67/100
  • criticalExfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 20, 2026

npx -y skills add iblai/vibe --skill iblai-vibe-agent-billing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Iblai Vibe Agent Billing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Iblai Vibe Agent Billing
[![Security: C — Skills Directory](https://www.skillsdirectory.com/api/skills/iblai-iblai-vibe-agent-billing/badge)](https://www.skillsdirectory.com/skills/iblai-iblai-vibe-agent-billing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: iblai-vibe-agent-billing
description: Add the agent Billing tab (LLM spend limits for the agent and per user, with usage bars, block/alert enforcement, and near-limit alert thresholds) to your Next.js app
globs:
alwaysApply: false
metadata:
  kind: ui
---

# /iblai-vibe-agent-billing

Add the agent **Billing tab** -- set LLM spend limits for this agent
and its users, and see how much has been used. Two sub-tabs match the
backend's agent-level scopes: **This Agent** (the agent's own spend
cap) and **Per User** (explicit per-user limits on this agent, with
the user picked through a platform-user search). Each limit has an
enable toggle, a usage bar (spent / % used / remaining), a spend
amount with a reset interval (day/week/month/year), an enforcement
mode (**Block Requests** or **Alert Only**), and comma-separated
alert thresholds at which admins get a near-limit alert. Enforcement
is server-side — a blocked request is refused with a `429` /
`spend_cap_exceeded` error until the period resets. This is one tab
in the wider agent-settings family. All tabs share the same
`AgentSettingsProvider` wrapper.

![Billing Tab — This Agent](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-vibe-agent-billing/iblai-vibe-agent-billing.png)

![Billing Tab — Per User](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-vibe-agent-billing/iblai-vibe-agent-billing-per-user.png)

![Per User — Row Actions (Edit / Delete)](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-vibe-agent-billing/iblai-vibe-agent-billing-actions.png)

![New User Limit Modal](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-vibe-agent-billing/iblai-vibe-agent-billing-new-user-limit.png)

![Edit User Limit Modal](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/skills/agents/iblai-vibe-agent-billing/iblai-vibe-agent-billing-edit-user-limit.png)

> **Common setup (brand, conventions, env files, verification):** see [docs/skill-setup.md](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/docs/skill-setup.md).

## Prerequisites

- Auth must be set up first (`/iblai-vibe-auth`)
- MCP server + skills configured (`@iblai/mcp` in `.mcp.json`)
- `AgentSettingsProvider` must wrap the route (see `/iblai-vibe-agent-setting`
  Step 2 if not already set up)
- Ask the user for a real `mentorId` (agent UUID). Do NOT invent one.
- The spend-cap endpoints are RBAC-gated admin endpoints — a user
  without access sees a friendly "no access" panel per sub-tab (403).

## Step 1: Check Environment

Before proceeding, check for an `iblai.env` in the project root. Look for
`PLATFORM`, `DOMAIN`, and `TOKEN` variables. If the file does not exist or
is missing these variables, tell the user:
"You need an `iblai.env` with your platform configuration. Download the
template and fill in your values:
`curl -o iblai.env https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/iblai.env`"

## Step 2: Mount `AgentSpendCapsTab`

```tsx
// app/(app)/agents/[mentorId]/billing/page.tsx
"use client";

import { AgentSpendCapsTab } from "@iblai/iblai-js/web-containers/next";

export default function AgentBillingPage() {
  return (
    <div className="flex h-full flex-col bg-white">
      <AgentSpendCapsTab />
    </div>
  );
}
```

`AgentSpendCapsTab` reads `tenantKey` and `mentorId` from
`AgentSettingsProvider`. No props are required for the standard mount.

## Step 3: Customize Labels (Optional)

```tsx
import { AgentSpendCapsTab } from "@iblai/iblai-js/web-containers/next";

<AgentSpendCapsTab
  labels={{
    header: { title: "Spend limits" },
    subTabs: { agent: "Agent limit", users: "User limits" },
  }}
/>;
```

## Step 4: Use MCP Tools for Customization

```
get_component_info("AgentSpendCapsTab")
get_component_info("SpendCapUsage")
get_component_info("AgentSettingsProvider")
```

## `<AgentSpendCapsTab>` Props

Import from `@iblai/iblai-js/web-containers/next`.

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `labels` | `DeepPartial<SpendCapsTabLabels>` | No | Override user-visible strings |
| `tenantKey` | `string` | No | Identity override; defaults to `AgentSettingsProvider` |
| `mentorId` | `string` | No | Identity override; defaults to `AgentSettingsProvider` |
| `headerClassName` | `string` | No | Extra classes on the tab header (wide-dialog hosts widen padding) |
| `bodyClassName` | `string` | No | Extra classes on the scrollable body |

## What the tab renders

- **Header** — "Billing" title and "Set spend limits for this agent
  and its users, and see how much has been used."
- **This Agent / Per User sub-tabs** — the two agent-level scopes. The
  tab ratchets its height so switching sub-tabs never shrinks the
  dialog it is hosted in.
- **No-access state** — when the current user lacks permission for a
  scope's endpoints (403), that sub-tab's content is replaced by a
  "no access" notice.

### Shared spend-cap editor (both scopes)

Both sub-tabs edit a cap through the same `SpendCapForm`:

- **Enable toggle** — "Put a ceiling on AI spend…" capability gate.
  While on, everything the limit covers counts toward the amount;
  fields collapse when toggled off. The flag rides along on save.
- **Usage strip** (saved caps only) — "Daily/Weekly/Monthly/Yearly
  Usage" with a progress bar (blue, amber at ≥80%, red when
  exceeded) and Spent / % of limit used / Remaining figures, plus
  Disabled / Alert only / Exceeded badges as applicable.
- **Spend Limit (USD)** — positive decimal; sent as a 2-decimal
  string.
- **Resets Every** — Day / Week / Month / Year.
- **When the Limit Is Reached** — `Block Requests` (new chat and
  training requests are refused until the period resets) or
  `Alert Only` (requests continue; admins are alerted).
- **Alert At (% of Limit)** — comma-separated percentages (default
  `80, 95`) at which admins get a near-limit alert.
- **Delete Limit** (saved caps only) — confirmation dialog before
  removal. **Save** creates the cap on first save and updates it
  after (the PUT is an upsert).
- Until a cap exists the form shows "No spend limit configured yet —
  set an amount and save to create one."

### This Agent sub-tab

The agent's own singleton spend cap — everything spent on this agent
by anyone counts toward it.

### Per User sub-tab

Explicit (user, agent) limits — "Limit what specific users can spend
on this agent."

- **Table** — User (email-first, linked to the same profile viewer as
  the Management tab; clicking the row opens it too), Limit
  (`$2.00 / Week`), Status (direct enable toggle that saves
  immediately, plus Exceeded / Alert-only badges), and a per-row
  actions menu (**Edit** / **Delete**).
- **Add User Limit** — opens the New User Limit modal: pick the user
  through a debounced platform-user search (min 2 characters,
  email-only options — no free-text usernames), then fill the same
  spend-cap form. Edit mode skips the picker and goes straight to
  the form for the cap's user.
- **Delete** — confirmation dialog showing the user's email.

## Related Exports

From `@iblai/iblai-js/web-containers/next`:

- `AGENT_SPEND_CAPS_TAB_LABELS` -- the default label bundle.
- `SpendCapsTabLabels` -- type for the full label bundle.
- `AgentSpendCapsTabProps` -- props type for the tab.
- `SPEND_CAPS_SUB_TABS` -- the sub-tab keys (`agent`, `users`).
- `useSpendCaps` -- the tab's data hook (caps + save/delete per
  scope), for custom UI on the same endpoints.
- `SpendCapUsage`, `SpendCapUsageProps` -- **learner-safe** usage
  indicator for chat surfaces: renders progress zones and percentages
  only (never dollar amounts), a warning banner near a limit, and a
  blocked banner once a hard-block cap is exceeded. Renders nothing
  while everything is in the "ok" zone unless `showWhenOk` is set.

From `@iblai/iblai-js/data-layer` -- the RTK Query hooks and types the
tab uses, for custom UI built on the same endpoints:

- Agent cap: `useGetAgentSpendCapQuery`,
  `useUpsertAgentSpendCapMutation`, `useDeleteAgentSpendCapMutation`
- Per-user caps: `useListAgentUserSpendCapsQuery`,
  `useGetUserSpendCapQuery`, `useUpsertUserSpendCapMutation`,
  `useDeleteUserSpendCapMutation`
- Organization cap (workspace-wide singleton):
  `useGetTenantSpendCapQuery`, `useUpsertTenantSpendCapMutation`,
  `useDeleteTenantSpendCapMutation`
- Organization-wide agent-cap list: `useListAgentSpendCapsQuery`
  (optional `mentor` filter)
- User-safe status: `useGetSpendCapStatusQuery`
- Types: `SpendCap`, `SpendCapUpsertRequest`, `SpendCapIntervalType`,
  `SpendCapEnforcement`, `SpendCapScope`, `SpendCapStatusSummary`,
  `SpendCapStatusItem`, `SpendCapStatusZone`,
  `SpendCapExceededErrorBody`
- `SPEND_CAP_EXCEEDED_ERROR_CODE` -- the `spend_cap_exceeded` error
  code carried by blocked requests (HTTP 429 body / WebSocket frame),
  distinguishing a spend-cap block from a genuine provider rate limit.

## Step 5: Verify

Run `/iblai-vibe-ops-test` before telling the user the work is ready:

1. `pnpm build` -- must pass with zero errors
2. `pnpm test` -- vitest must pass
3. Start dev server and touch test:
   ```bash
   pnpm dev &
   npx playwright screenshot http://localhost:3000/agents/<id>/billing /tmp/agent-billing.png
   ```

## Important Notes

- **Redux store**: Must include `mentorReducer` and `mentorMiddleware`
- **`initializeDataLayer()`**: 5 args (v1.2+)
- **`@reduxjs/toolkit`**: Deduplicated via webpack aliases in `next.config.ts`
- **Peer deps**: `sonner` and `@iblai/iblai-web-mentor` must be installed
  (`pnpm add sonner @iblai/iblai-web-mentor`)
- **Shared provider**: `AgentSettingsProvider` must wrap the route at a
  layout level. See `/iblai-vibe-agent-setting` Step 2 for the full snippet.
- **First-run 404 is normal**: the singleton GETs 404 until a cap is
  first saved — that is the documented "no cap configured" state, not
  an error. The first Save creates the row.
- **Counters are read-only**: `current_spend_usd`, `remaining_usd`,
  and `is_exceeded` are reconciled server-side and only rendered —
  never submitted. Admins write `interval_type`, `max_cost_usd`
  (decimal **string**), `enforcement`, `alert_thresholds`, `enabled`.
- **PUT is an upsert**: the status toggles in the tables save
  immediately by re-submitting the cap's current fields with the
  flipped `enabled` flag.
- **Username key, email display**: per-user caps are keyed by
  `username` in the API; the UI deliberately shows the email
  everywhere. The user is picked via search — no free-text usernames.
  A cap read echoes `username`, `email` and `user_full_name`, so the
  table renders the person without a second request.
- **Enforcement is server-side**: with `block`, an exceeded cap makes
  chat/training requests fail with HTTP 429 (or a WebSocket error
  frame) whose body carries `error_code: "spend_cap_exceeded"`.
  Handle it in custom chat UI, or mount `SpendCapUsage` to warn users
  before they hit it.
- **Three scopes**: organization (workspace-wide), agent, and per-user-per-
  agent — the tightest applicable cap governs. This tab manages the
  two agent-level scopes; the workspace-wide limit belongs to the
  organization settings Billing surface (`/iblai-vibe-billing`, which also
  lists every agent's cap in one place).
- **RBAC**: each scope's endpoints are gated separately; a 403 renders
  the denied panel for that sub-tab only.
- **Brand guidelines**: [BRAND.md](https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/BRAND.md)

## Spend Caps REST API

For custom UI beyond the tab. All endpoints are prefixed with
`${dmUrl}/api/ai-mentor/orgs/{org}/` where `dmUrl` is
`NEXT_PUBLIC_API_BASE_URL`. Auth: `Authorization: Token <token>`.
Use the canonical `agents/` spelling — `mentors/` is a deprecated
alias.

### Agent spend cap (singleton per agent)

| Method | Path | Purpose |
|---|---|---|
| GET | `agents/{mentor_unique_id}/spend-cap/` | Read (404 = no cap configured) |
| PUT | `agents/{mentor_unique_id}/spend-cap/` | Upsert — create or update |
| DELETE | `agents/{mentor_unique_id}/spend-cap/` | Remove the cap |

**Upsert body:**

```json
{
  "interval_type": "day",
  "max_cost_usd": "10.00",
  "enforcement": "block",
  "alert_thresholds": [80, 95],
  "enabled": true
}
```

`interval_type`: `day` | `week` | `month` | `year`.
`enforcement`: `block` | `alert_only`. `max_cost_usd` is a decimal
string. Responses add the read-only counters (`current_spend_usd`,
`remaining_usd`, `is_exceeded`, `period_started_at`,
`last_reconciled_at`).

### Per-user limits on an agent

| Method | Path | Purpose |
|---|---|---|
| GET | `agents/{mentor_unique_id}/spend-caps/users/` | List this agent's user caps |
| GET | `agents/{mentor_unique_id}/spend-caps/users/{username}/` | Read one (404 = none) |
| PUT | `agents/{mentor_unique_id}/spend-caps/users/{username}/` | Upsert (same body as above) |
| DELETE | `agents/{mentor_unique_id}/spend-caps/users/{username}/` | Remove |

The list may come back as a bare array or a DRF limit/offset
envelope depending on deployment — the SDK slice normalizes both.

### Organization scope + organization-wide listing

| Method | Path | Purpose |
|---|---|---|
| GET/PUT/DELETE | `spend-caps/tenant/` | Workspace-wide singleton cap |
| GET | `spend-caps/agents/` | Every configured agent cap in the organization (`?mentor=<uuid>` filter) |

### User-safe status

| Method | Path | Purpose |
|---|---|---|
| GET | `spend-caps/status/{user_id}/` | Zones + fill percentages for the caps covering this user (`?mentor=<uuid>` to include an agent's caps) — never dollar amounts. Non-admins may only read their own |

### Enforcement error

A hard-block cap that is exceeded makes chat/training requests fail
with HTTP 429 (or a WebSocket error frame):

```json
{
  "error_code": "spend_cap_exceeded",
  "error": "...",
  "message": "...",
  "details": { "scope": "agent", "interval_type": "day", "mentor_unique_id": "..." }
}
```

Match on `error_code === "spend_cap_exceeded"`
(`SPEND_CAP_EXCEEDED_ERROR_CODE`) — a genuine provider rate limit
also uses status 429.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.