Skip to content

mastra-ai/workshop-mastra-editor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mastra Editor Workshop

A small, self-contained Mastra project used to demo the Agent Editor in Studio: non-technical agent authoring, versioning, RBAC, dynamic behavior via requestContext, and programmatic control.

What's in here

src/
├── mastra/
│   ├── index.ts                       # Mastra entry — registers editor, MCP, Studio auth
│   ├── auth.ts                        # SimpleAuth tokens + MastraRBACStudio role mapping
│   ├── agents/
│   │   └── customer-support.ts        # The code-defined agent everyone overrides
│   ├── tools/
│   │   ├── lookup-order.ts            # Local `createTool` — code-defined tool
│   │   └── issue-credit.ts            # Local tool intentionally gated via the editor
│   └── mcp/
│       └── server.ts                  # In-process MCP server with a search-knowledge-base tool
└── scripts/
    ├── seed-prompt-blocks.ts          # Pre-creates the demo prompt blocks
    └── programmatic-block.ts          # "Studio is just a UI" — creates a block via code

The customer-support agent has:

  • A requestContextSchema with customerName, tier (free | premium), and userRole (user | admin) — the workshop demos how this drives prompt blocks and conditional tools.
  • Two local tools: lookup-order and issue-credit.
  • One MCP-served tool: search-knowledge-base.
  • An integration provider (Arcade) registered with the editor — so during the demo Alex can add e.g. Gmail or Slack tools from Studio without code.

One-time setup

pnpm install
cp .env.example .env
# Then edit .env and fill in OPENAI_API_KEY (required) plus optionally
# ARCADE_API_KEY.

pnpm seed creates the Tone of Voice and Premium-tier perks prompt blocks. Re-running it is safe — it skips ones that already exist.

Run modes

pnpm dev      # mastra dev — local Studio at http://localhost:4111
pnpm build    # bundles the project for production-style Studio
pnpm start    # runs the bundled output
pnpm seed     # seeds the demo prompt blocks
pnpm programmatic   # demos creating a block from code
pnpm typecheck
pnpm clean    # nukes mastra.db and .mastra

Studio auth + RBAC

The dev server runs SimpleAuth (from @mastra/core/server) so the workshop demos auth + RBAC locally with no WorkOS / shared-API setup. Three pre-baked tokens map to three roles:

Token Role What they can do
admin-token admin Everything (the developer hat)
editor-token editor Read + execute everything; create, edit, and publish drafts
viewer-token viewer Read-only across the app; can chat with agents but cannot save

Try it from the terminal:

# Viewer can list, but cannot delete:
curl -H "Authorization: Bearer viewer-token" http://localhost:4111/api/stored/agents
curl -X DELETE -H "Authorization: Bearer viewer-token" \
  http://localhost:4111/api/stored/agents/customer-support-agent
# → {"error":"Forbidden"}  (HTTP 403)

# Editor can:
curl -X DELETE -H "Authorization: Bearer editor-token" \
  http://localhost:4111/api/stored/agents/customer-support-agent

To use the tokens in Studio, set the mastra-token cookie via DevTools, or hit /api/auth/sign-in with the token as the password field. See src/mastra/auth.ts for the role → permission mapping.

Permissions come from @mastra/corestored-agents:write, stored:*, etc. Today the framework does not split publish from write: both save draft and activate version resolve to stored-agents:write, so the editor role can publish too. That's a teachable moment, not a bug.

For production, swap SimpleAuth for MastraAuthStudio (with WorkOS) — the MastraRBACStudio role mapping stays exactly the same.


Workshop runbook

The demo is split between two presenters:

  • Daniel — developer host. Drives the IDE, runs the deploy, narrates code.
  • Alex — non-technical user persona. Drives Studio, edits the agent.

0. Pre-show checklist

  1. pnpm install && pnpm seed
  2. pnpm dev (or deploy to Mastra Cloud and share the link)
  3. Studio loads at http://localhost:4111 — confirm:
    • The agent Customer Support Agent is visible
    • Under Prompts you see "Tone of Voice — Professional Customer Service" and "Premium-tier perks reminder"
    • The agent's Editor tab is reachable
  4. Two test accounts ready in your Mastra Cloud org:
    • alex+editor@… mapped to role editor
    • alex+viewer@… mapped to role viewer

1. Opening (3 min) — Daniel

Two audiences, two outcomes:

  • Non-technical users — control agent behavior, edit, publish safely.
  • Developers — set the project up and understand how to extend it.

Definition: the Agent Editor is a UI to edit, test, and deploy agents without code changes.

2. Live demo (10–12 min) — handoff in the middle

Daniel:

pnpm dev      # or `mastra deploy`
  • Open Studio. Show the agent. Send a quick message ("Where's my order A-1001?"). Note the response is fine but generic.
  • Hand the link to Alex.

Alex:

  1. Authenticate via Google.
  2. Open the agent → Editor tab.
  3. Edit the inline prompt. Add the Tone of Voice — Professional Customer Service block from the prompt picker.
  4. Click Save version — note "Draft" badge appears.
  5. Chat against the draft. Same question. Tone is now warmer and personalized.
  6. Click Publish.

Daniel: prove the new version is live for production traffic:

curl -s http://localhost:4111/api/agents/customer-support-agent/chat \
  -H 'Content-Type: application/json' \
  -d '{
    "messages": [{"role":"user","content":"Where is my order A-1001?"}],
    "requestContext": {"customerName":"Sam","tier":"free","userRole":"user"}
  }' | jq

Emphasis: versioning = no risk. Publishing = controlled release.

3. Tools (15–20 min) — Daniel + Alex

Demonstrate, in Studio's Editor tab → Tools:

  1. Add the local issue-credit tool. Save version.
  2. Remove lookup-order, save, chat — agent now refuses to look up orders. Re-add it, save again.
  3. Override lookup-order's description to: "Look up an order. Always confirm the order ID with the customer before answering." Save, chat, notice the new behavior.
  4. Add an MCP tool — pick search-knowledge-base from the support-knowledge-base server.
  5. Add an Arcade tool (e.g. Gmail send_email or Slack send_message). Requires ARCADE_API_KEY in .env.

4. Dynamic behavior (10–12 min) — Alex (with the slide deck)

Slide intro: explain requestContext — values that flow in with every request and are visible to instructions, prompt blocks, tools, and rules.

In Studio:

  1. Make issue-credit conditional on tier == 'premium'. Save, publish.

  2. Add the Premium-tier perks reminder prompt block. It's already conditional on tier == 'premium' (see seed-prompt-blocks.ts).

  3. Test from Studio's chat with two requestContext values:

    { "customerName": "Sam", "tier": "free", "userRole": "user" }
    { "customerName": "Sam", "tier": "premium", "userRole": "user" }

    Premium gets perks mentioned and issue-credit available; free does not.

5. Prompt blocks recap (3–5 min) — Alex

Open Studio → Prompts. Show the same blocks live there as standalone, reusable, versioned content. Show {{customerName}} resolving from the agent's request context.

6. Setup — developer-focused (12–15 min) — Daniel

Walk through:

  • package.json@mastra/editor, @mastra/auth-studio, Arcade dep
  • src/mastra/index.ts:
    • new MastraEditor({ toolProviders: { arcade: ... } })
    • The same LibSQLStore powers the agent's memory and the editor — no extra storage to wire up.
  • src/mastra/agents/customer-support.ts:
    • requestContextSchema (drives Studio forms and rule operators)
    • Tools object — both inline createTool and MCP-served tools
  • Frame: the editor is a stateful layer on top of source code, not a replacement. applyStoredOverrides forks the agent and overlays instructions and tools. Code-only fields (id, name, model, requestContextSchema, memory) are never overridden.

7. Access control (5–7 min) — Daniel

Open src/mastra/auth.ts. Walk through SimpleAuth (three pre-baked tokens) and the MastraRBACStudio role mapping table.

Run the viewer-can't-edit demo from the terminal:

# Viewer can read…
curl -s -o /dev/null -w "%{http_code}\n" \
  -H 'Authorization: Bearer viewer-token' \
  http://localhost:4111/api/stored/agents
# → 200

# …but cannot delete:
curl -s -o /dev/null -w "%{http_code}\n" \
  -X DELETE -H 'Authorization: Bearer viewer-token' \
  http://localhost:4111/api/stored/agents/customer-support-agent
# → 403

# Editor can:
curl -s -o /dev/null -w "%{http_code}\n" \
  -X DELETE -H 'Authorization: Bearer editor-token' \
  http://localhost:4111/api/stored/agents/customer-support-agent
# → 404 (record didn't exist — but RBAC let us through)

Frame: in production you'd swap SimpleAuth for MastraAuthStudio (Google SSO via WorkOS); the role mapping stays the same.

8. Programmatic control (5–7 min) — Daniel

pnpm programmatic

Refresh Studio → the new block is in Prompts. The point: Studio is the UI on top of mastra.getEditor(). The same API is available to scripts, jobs, and CI.

9. Closing (3–5 min)

Three takeaways:

  1. Non-technical control — Alex never opened a terminal and shipped a prompt change to production.
  2. Dynamic via request context — the same agent, instructions, and tool list adapt per request. No new code paths.
  3. Code/UI parity — anything in Studio is a method call. Anything you build in code shows up in Studio.

Troubleshooting

  • Studio shows no prompt blocks → run pnpm seed.
  • MASTRA_EDITOR_REQUIRED_FOR_VERSIONED_AGENT_LOOKUP → editor is not registered. Check src/mastra/index.ts and that the editor is being passed into new Mastra({ ... }).
  • Arcade tool provider missing in StudioARCADE_API_KEY not set. The provider only registers when the env var is present.
  • Agent overrides don't apply → call mastra.getAgentById('customer-support-agent') (not mastra.agents['customer-support-agent']). The editor only applies overrides via getAgentById.

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors