Monorepo recipe
Drop-in setup for a pnpm / Turbo / Nx workspace. Scope flow + design to a single package or run them at the root.
Drop-in setup for a workspace. Two valid layouts depending on who owns what. Pick A unless you've already split into autonomous package teams.
Starting point: pnpm workspace, possibly Turbo or Nx on top. Multiple deployable apps and shared packages.
Two valid layouts
Option A. Root-level .ai/ (recommended for cross-package work).
my-monorepo/
├── .ai/ # one workspace covers everything
├── apps/
│ ├── web/ # Next.js app
│ └── api/ # Hono/Express service
├── packages/
│ ├── ui/ # shared component library
│ └── db/ # shared Drizzle schema
├── pnpm-workspace.yaml
└── turbo.jsonOption B. Per-package .ai/ (only if packages are owned by different teams with diverging conventions).
my-monorepo/
├── apps/
│ ├── web/
│ │ └── .ai/ # web team's workspace
│ └── api/
│ └── .ai/ # api team's workspace
└── packages/ui/
└── .ai/ # design-system team's workspaceMost teams want Option A. Pick B only if you've already split into autonomous package teams.
Option A setup
Install the CLI (required, skills use it):
npm i -g @1agh/maudeInside Claude Code at the repo root:
/plugin marketplace add 1aGh/maude
/plugin install flow@maude
/plugin install design@maude
/flow:init
/design:initYou'll end up with something like:
{
"name": "my-monorepo",
"stack": {
"language": "typescript",
"framework": "next.js",
"packageManager": "pnpm",
"buildTool": "turbo",
"monorepo": true,
"ci": "github-actions",
"tests": "vitest"
},
"boundaries": {
"api": ["openai"],
"db": ["postgres"],
"auth": ["clerk"]
}
}stack.monorepo: true and stack.buildTool: "turbo" flip flow into monorepo mode:
/flow:utils-verifyrunsturbo run lint test --filter=...changedinstead of running globally./flow:validaterunsturbo run buildand gates on it./flow:donehonors Turbo's affected-graph when deciding what tests to run.
Changeset releases
For a monorepo, the typical changelog provider is Changesets, scoped to specific publishable packages.
maude config set integrations.changelog.provider changesets
maude config set integrations.changelog.scope "@acme/web"/flow:release-changelog will then drop entries into .changeset/*.md and /flow:release will walk the changesets-flavored release runbook (auto-scaffolded into .ai/release-guide.md).
If you publish multiple packages, set scope to the most-frequently-released one. The others are still released, you just don't have to pass --filter every time.
Design plugin in a monorepo
If you've installed the design plugin, the canonical place for design canvases is .design/ at the repo root, with subdirectories per app or feature:
.design/
├── system/ # shared tokens
├── ui/ # shared component prototypes
├── web/ # canvases for apps/web
│ ├── home-hero/
│ └── pricing-table/
└── admin/ # canvases for apps/adminThe dev server resolves the design root via --root arg, then $CLAUDE_PROJECT_DIR, then cwd. From any package directory, set:
export CLAUDE_PROJECT_DIR=$(git rev-parse --show-toplevel)
maude design serve --port 4399...or boot it from the repo root.
Gotchas
- One
CLAUDE.mdat root plus per-package overrides. The rootCLAUDE.mdcovers cross-cutting concerns (commit conventions, branch model). Per-packageCLAUDE.md(placed inapps/web/,apps/api/, etc.) override or extend it. workflows.config.jsonis not hierarchical. Pick Option A or Option B, don't mix. The flow plugin reads exactly one config from the directory you invoke it in.- Turbo cache. Flow doesn't manage Turbo's cache. If
/flow:utils-verifyreports a stale failure,pnpm turbo run lint --forceand re-verify. - PR scopes. Conventional commits for monorepos benefit from a scope:
feat(web): ...,fix(ui): ..../flow:doneformats commits to matchconventions.commitsbut won't auto-pick the scope. Add it when prompted.