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
-
Start kanban-lite in a separate terminal
npx kanban-lite serve --port 3001The 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 -
Copy the example environment file
cp .env.example .envThe shipped
.env.exampledefines two values:OPENAI_API_KEYfor the default model router target andKANBAN_API_URL, which defaults tohttp://localhost:3001/api. -
Install the example dependencies
npm installRun this from
examples/mastra-agent-ops/. The example stays self-contained and is not wired into the root workspace build. -
Run the Next.js development server
npm run devThe app starts on http://localhost:3002. The browser UI talks to the local
/api/agentroute, which then streams Mastra output back as plain text. -
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.tscreates the Mastra registry and registers thecoordinatoragent.src/mastra/agents/coordinator.tsdefines the operating modes, approval rules, and tool access.src/mastra/tools/kanban.tswraps the kanban-lite REST API as Mastra tools.app/api/agent/route.tsaccepts chat history and streams text deltas fromagent.stream().app/page.tsxrenders the chat interface and turns proposal blocks into Approve / Reject buttons.
Supervisor and orchestration flow
- The browser sends the current chat history to
POST /api/agent. - The route resolves
mastra.getAgent("coordinator")and callsagent.stream(messages). - The Coordinator decides whether the user is asking for intake, planning, or reporting.
- To ground its response, it uses kanban-lite tools such as
listCardsorgetCardbefore proposing changes. - If the next step is a write, the agent must emit a formatted
PROPOSED ACTIONblock and pause for confirmation. - The UI detects that block and injects
approveorrejectas the next user message when the buttons are clicked. - Only after an
approvemessage does the Coordinator callcreateCard,updateCard, ormoveCard.
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.
listCards— survey the board, optionally by status, priority, or assigneegetCard— inspect one card in detail
createCard— create a new Markdown-backed kanban cardupdateCard— change content, priority, assignee, labels, or due datemoveCard— 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.tsonce 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.