Skip to main content

Example: Mastra Agent Ops

Build a supervisor-style Mastra coordinator that triages, plans, and reports on a kanban-lite board with approval-aware write actions.

The runnable source for this guide lives in examples/mastra-agent-ops/. The app is a small Next.js UI backed by a single Mastra Coordinator agent and a thin kanban-lite REST tool layer.

What you will build

A TypeScript app that keeps the orchestration story intentionally simple and concrete:

  • A single Coordinator agent that switches between intake, planning, and reporting modes
  • A streaming chat route that sends user messages to Mastra and streams text back to the browser
  • Approval-aware card writes: create, update, and move actions require an explicit confirmation step
  • A self-contained integration seam that talks to kanban-lite only through the standalone REST API

Before you start

  • Node.js 20 or later
  • npm (the example uses npm commands directly)
  • A running kanban-lite server on port 3001
  • An OpenAI API key for the shipped default model configuration
  1. Start kanban-lite in a separate terminal

    npx kanban-lite serve --port 3001

    The Mastra example does not import kanban-lite internals. It expects the standalone API to be reachable at http://localhost:3001/api.

    If you do not already have a board, initialize one first and then start the server:

    npx kanban-lite init
    npx kanban-lite serve --port 3001
  2. Copy the example environment file

    cp .env.example .env

    The shipped .env.example defines two values: OPENAI_API_KEY for the default model router target and KANBAN_API_URL, which defaults to http://localhost:3001/api.

  3. Install the example dependencies

    npm install

    Run this from examples/mastra-agent-ops/. The example stays self-contained and is not wired into the root workspace build.

  4. Run the Next.js development server

    npm run dev

    The app starts on http://localhost:3002. The browser UI talks to the local /api/agent route, which then streams Mastra output back as plain text.

  5. Drive the coordinator through its three modes

    Show current board status
    Intake: add a new bug report
    Plan: organize backlog by priority
    Report: what is currently in progress?

    These example prompts map directly to the Coordinator instructions in src/mastra/agents/coordinator.ts.

How the app is structured

examples/mastra-agent-ops/
├── app/
│   ├── api/agent/route.ts
│   ├── globals.css
│   ├── layout.tsx
│   └── page.tsx
├── src/mastra/
│   ├── index.ts
│   ├── agents/coordinator.ts
│   └── tools/kanban.ts
├── .env.example
├── next.config.ts
├── package.json
└── tsconfig.json
  • src/mastra/index.ts creates the Mastra registry and registers the coordinator agent.
  • src/mastra/agents/coordinator.ts defines the operating modes, approval rules, and tool access.
  • src/mastra/tools/kanban.ts wraps the kanban-lite REST API as Mastra tools.
  • app/api/agent/route.ts accepts chat history and streams text deltas from agent.stream().
  • app/page.tsx renders the chat interface and turns proposal blocks into Approve / Reject buttons.

Supervisor and orchestration flow

  1. The browser sends the current chat history to POST /api/agent.
  2. The route resolves mastra.getAgent("coordinator") and calls agent.stream(messages).
  3. The Coordinator decides whether the user is asking for intake, planning, or reporting.
  4. To ground its response, it uses kanban-lite tools such as listCards or getCard before proposing changes.
  5. If the next step is a write, the agent must emit a formatted PROPOSED ACTION block and pause for confirmation.
  6. The UI detects that block and injects approve or reject as the next user message when the buttons are clicked.
  7. Only after an approve message does the Coordinator call createCard, updateCard, or moveCard.

This is why the example is described as supervisor-style: one coordinator stays in control of the board-wide picture and decides when to read, propose, and write, rather than letting tools mutate state immediately.

Approval-aware actions

The approval split is encoded in both the Coordinator instructions and the UI behavior.

Read immediately
  • listCards — survey the board, optionally by status, priority, or assignee
  • getCard — inspect one card in detail
Require approval
  • createCard — create a new Markdown-backed kanban card
  • updateCard — change content, priority, assignee, labels, or due date
  • moveCard — transition a card to another status column

In practice, this means the user gets a human-readable explanation before anything mutates the board. The example is useful when you want agent help with prioritization or triage, but still want a person to stay in the approval loop.

Key code

The Coordinator is a single Mastra Agent with kanban-lite REST tools and an approval-aware instruction set. Here is the condensed definition from src/mastra/agents/coordinator.ts:

// src/mastra/agents/coordinator.ts
import { Agent } from "@mastra/core/agent";
import {
  listCardsTool, getCardTool,
  createCardTool, updateCardTool, moveCardTool,
} from "../tools/kanban";

export const coordinatorAgent = new Agent({
  id: "coordinator",
  name: "coordinator",
  instructions: INSTRUCTIONS, // intake, planning, reporting modes
  model: "openai/gpt-4o-mini",
  tools: {
    listCards: listCardsTool,   // read — no approval needed
    getCard: getCardTool,       // read — no approval needed
    createCard: createCardTool, // write — requires approval
    updateCard: updateCardTool, // write — requires approval
    moveCard: moveCardTool,     // write — requires approval
  },
});

The INSTRUCTIONS constant above defines three operational modes (intake, planning, reporting) and enforces a two-step approval gate for every write operation.

kanban-lite integration seam

The only integration surface is the kanban-lite standalone REST API. The shared fetch helper in src/mastra/tools/kanban.ts reads KANBAN_API_URL and calls the default board endpoints under that base URL.

GET    /tasks
GET    /tasks/:id
POST   /tasks
PUT    /tasks/:id
PATCH  /tasks/:id/move

That separation is intentional: you can run this example against any kanban-lite server started with npx kanban-lite serve, whether the board data lives in markdown or a different supported storage backend.

Changing the model or provider

The shipped configuration uses model: "openai/gpt-4o-mini" in src/mastra/agents/coordinator.ts. If you want a different provider, change that model string and add the matching AI SDK provider package to this example before setting its API key in .env.

Extension ideas

  • Add more agents or workflows in src/mastra/index.ts once the single-coordinator flow feels too narrow.
  • Persist memory or session state so reporting can compare the current board with prior runs.
  • Add richer board-aware prompts, such as stale-card detection or SLA checks, before moving work.
  • Replace the minimal plain-text stream UI with richer streaming or tool-state visualization.
  • Introduce auth or policy checks at the kanban-lite server layer when approvals need to map to real user permissions.