Local Development
Three ways to run the stack locally — pick the one that matches what you're doing
Three Modes
Your project ships with three local-dev entry points. Pick based on what you're doing right now.
| Command | Services | Public URLs | Use when |
|---|---|---|---|
pnpm dev:min | web, api, mastra | localhost only | Fast iteration on UI, APIs, agent prompts — no external callbacks needed |
pnpm dev:tunnel | web, api, mastra + Cloudflare Tunnel | local-{slug}-{service}.mastrakit.dev | OAuth logins, webhooks (Stripe, etc.), MCP clients reaching your laptop |
pnpm dev | all 5 services (adds auth, metering) | localhost only | Working on auth or metering, or parity with full-stack behavior |
All three run services natively on your host (no containers). Auth and metering, when not running locally, are reached via whatever URLs your env files point at — typically your CF dev deploys.
Individual app dev is also available: pnpm dev:web, pnpm dev:api, pnpm dev:mastra, pnpm dev:auth, pnpm dev:metering.
When to Use Tunnel Mode
Tunnel mode gives each service a stable public URL on mastrakit.dev. Reach for it when:
- Google/GitHub OAuth — the callback URL must be publicly reachable
- Stripe webhooks — Stripe posts events to a public HTTPS endpoint
- MCP from ChatGPT or Claude Desktop — external clients need a URL to connect to your local agent
- Collaborating — sharing a live preview with a teammate
For everything else, dev:min is faster — no Cloudflare round-trip.
Tunnel URL Pattern
URLs are derived from your current git branch:
local-{slug}-web.mastrakit.dev → localhost:3000
local-{slug}-api.mastrakit.dev → localhost:3001
local-{slug}-mastra.mastrakit.dev → localhost:4111The slug is your branch name, lowercased and sanitized (e.g. feat/MAK-33-foo → feat-mak-33-foo). This matches the slug used by deployed Cloudflare Workers — see Deploy — but tunnel hosts are prefixed with local- so they don't collide.
Every workspace/branch gets its own isolated tunnel. No more sharing one zyme-* tunnel across everything.
First-Time Tunnel Setup
The tunnel script auto-provisions everything on first run, but you need cloudflared installed and authenticated to your Cloudflare account:
# Install (macOS)
brew install cloudflared
# Authenticate once
cloudflared loginThen in any workspace:
pnpm dev:tunnelOn first run for a given branch the script will:
- Create a named tunnel
local-{slug} - Register DNS routes for the three hostnames above
- Write a per-workspace config to
.conductor-tunnel-config.yml(gitignored) - Start web, api, mastra, and the tunnel
Subsequent runs skip the provisioning and go straight to starting services.
OAuth & Webhook Registration
Because each workspace has its own tunnel URLs, external services need to know about them:
- Google OAuth / GitHub OAuth — add
https://local-{slug}-web.mastrakit.dev/api/auth/callback/{provider}to the authorized redirect URIs in your provider's console. Add a new entry whenever you start working on a new long-lived branch. - Stripe webhooks — point your test-mode webhook endpoint at
https://local-{slug}-api.mastrakit.dev/webhooks/stripe.
For quick one-off Stripe testing without a tunnel, the Stripe CLI forwards webhooks directly to localhost:
stripe listen --forward-to localhost:3001/webhooks/stripeShort-lived branches don't need external OAuth — use dev:min and an email/password login instead.
Other Useful Commands
pnpm dev:status # Show which services are running and on which ports
pnpm dev:stop # Kill all local dev processes (web, api, mastra, tunnel)Running Multiple Workspaces at Once
Cloudflare side is fully isolated — each workspace has its own tunnel, its own URLs, its own DNS records. Localhost is not isolated — ports 3000/3001/4111 collide if you run dev:tunnel or dev:min in two workspaces simultaneously. Work in one workspace at a time, or stop services before switching.
Archiving a Workspace
Tunnels and DNS records created by dev:tunnel persist in your Cloudflare account until deleted. When you're done with a branch, clean them up:
cloudflared tunnel delete local-{slug}
# DNS records under *.mastrakit.dev may need manual cleanup in the CF dashboardTroubleshooting
"Tunnel creation failed" — run cloudflared login and retry.
"Could not derive workspace slug" — you're in detached HEAD. Check out a branch first.
Services start but URLs return 404 — the tunnel is still starting. Wait ~10 seconds and retry. If it persists, check /tmp/tunnel.log.
Something's broken in localhost-only mode — confirm your .env.local / .dev.vars reference the services you're actually running. If dev:min skips auth/metering, those env vars should point at your CF dev deploys, not localhost.