CLI Spec 21 — create-patties: Modular Monolith Default
Amends CLI Spec 18. Drops the ProjectType prompt (frontend / backend / fullstack) and makes the modular monolith the default scaffold for every new Patties app. Every project becomes full-stack by default.
Status: Draft
Depends on Framework Spec 28 for the modulesDirs config key and scanner changes. Everything in CLI Spec 18 not contradicted here carries over unchanged.
What's dropped from Spec 18
| Removed | Replacement / reason |
|---|---|
--type frontend | backend | fullstack | Deleted. Every app is full-stack by default. |
_backend/ template overlay | Deleted. API-only work is an api/ module inside a full-stack app. |
Monorepo gated on type=fullstack | Monorepo is now asked unconditionally for all projects. |
Patties UI gated on type ∈ {frontend, fullstack} | Patties UI is always offered — all apps can have UI. |
container excluded from non-fullstack | All deploy targets available to every app. |
{{type}} template variable | Removed from templating pass. |
Flat app/routes/ in default template | Replaced by modular monolith layout. |
Warning
Passing --type is now a hard error with a clear message: "--type was removed; every patties app is full-stack by default."
Updated interactive flow
Four prompts instead of five. The project-type prompt and its sub-gates are gone.
- 1. Project namePositional arg or prompt. Default
my-patties-app. Validation:/^[a-z0-9][a-z0-9_-]*$/. - 2. Coding agent"Which coding agent are you using?" → Claude (default) / Codex / old school. Flag:
--agent claude|codex|none. - 3. Patties UI"Do you want a styled UI? (Patties UI)" → Yes (default) / No. Flag:
--ui/--no-ui. Always asked — not gated. - 4. Monorepo"Do you want a Bun workspace structure (multiple apps)?" → No (default) / Yes. Flag:
--monorepo/--no-monorepo. Always asked. - 5. Deploy target"Where will you deploy?" → bun (default) / worker/edge / container/docker. Flag:
--target bun|edge|container. Edge shows optional deploy-plugin sub-prompt.
The --yes profile
agent=claude, ui=yes, monorepo=no, target=bun. Deterministic, no prompts.
New scaffold template structure
Replaces the flat templates/default/app/ layout. Demonstrates two modules out of the box.
Directory tree
templates/default/
├── app/
│ ├── modules/
│ │ ├── home/
│ │ │ ├── routes/
│ │ │ │ └── index.tsx # GET / — demo landing page
│ │ │ └── islands/
│ │ │ └── Counter.tsx # interactive island
│ │ └── api/
│ │ └── routes/
│ │ └── api/
│ │ └── health.ts # GET /api/health → { ok: true }
│ ├── _shared/
│ │ └── .gitkeep
│ └── middleware.ts
├── patties.config.ts
├── tsconfig.json
├── package.json
└── README-template.md
Landing page
// app/modules/home/routes/index.tsx
import { Island } from "patties/render"
export default function Home() {
return (
<main>
<h1>{{name}}</h1>
<Island name="home/Counter" />
</main>
)
}
// When --ui yes: imports <Button> and <Card> from stamped Patties UI components.
Health route
// app/modules/api/routes/api/health.ts
import type { Handler } from "patties"
export const GET: Handler = (_, ctx) => ctx.json({ ok: true })
// Demonstrates the API module pattern — no UI needed to test.
patties.config.ts
// patties.config.ts (generated with modulesDirs pre-filled)
import { defineConfig } from "patties/config"
export default defineConfig({
target: "{{target}}", // bun | edge
modulesDirs: ["app/modules"], // ← always present in scaffold
server: { port: 3000 },
})
Monorepo (Bun workspace)
No longer gated on project type. When chosen, each app in the workspace is itself a modular monolith.
<name>/
package.json // private, "workspaces": ["apps/*", "packages/*"]
biome.json
apps/
<app_name>/
app/
modules/ // modular monolith layout per app
home/
api/
middleware.ts
patties.config.ts // modulesDirs: ["app/modules"]
package.json
packages/ // shared libraries (empty with README)
<agent overlay>
Note
Bun workspaces only — no Turborepo/Nx. Polyglot (Python/Go) deferred. Prerequisite: framework/26-monorepo-react-resolution must ship before this flag is released (hoisted node_modules can otherwise load two React copies and crash SSR).
Agent overlay updates
The _claude/ overlay gains the new rule file from Spec 28. The /patties-init command is updated to scaffold features as modules.
- New file
.claude/rules/patties-modular-monolith.md— the LLM rules from Spec 28 §9. Ships in all--agent claudescaffolds. - /patties-init updateCommand text updated: "When adding a new feature, create
app/modules/<domain>/with the relevant subdirectories. Never add files directly to the top-levelapp/unless they are global (middleware.ts) or shared (_shared/)." - Codex overlay
.codex/rules/patties-patterns.mdgets the same modular monolith rules appended.
--agent | Files scaffolded | New in Spec 21 |
|---|---|---|
claude (default) |
CLAUDE.md, .claude/rules/patties-patterns.md, .claude/rules/patties-modular-monolith.md, .claude/skills/patties/, .claude/commands/patties-init.md |
patties-modular-monolith.md rule, updated patties-init.md |
codex |
AGENTS.md, .codex/rules/patties-patterns.md |
Modular monolith rules appended to patterns file |
none (old school) |
— | No change |
Flags (non-interactive)
bunx create-patties [name]
--agent claude | codex | none (default claude)
--ui | --no-ui (default yes)
--monorepo | --no-monorepo (default no)
--target bun | edge | container (default bun)
--deploy cloudflare | vercel | deno | netlify | none (edge only)
--theme neutral | slate | stone | zinc (ui only, default neutral)
--yes, -y
--no-install
--git
# Removed
# --type REMOVED — hard error with clear message if passed
# --template still an alias for --agent (spec 09/18 back-compat)
Scaffold behavior (ordered steps)
- Resolve options: flags → prompts (TTY) → defaults. Hard error on
--type. - Validate name; refuse non-empty target directory.
- Copy
templates/default/(modular monolith layout). - Run templating pass:
{{name}},{{target}},{{app_name}},{{ui}}. ({{type}}no longer emitted.) - Patch
package.json(+patties-uiwhenui=yes) andpatties.config.ts(target,modulesDirs). - Apply agent overlay for
claude/codex(including new modular monolith rule). - If
ui=yes:patties ui init --theme <theme>+ stamp starter set (button,card,input,label). - If
target=container: emitDockerfile+.dockerignore. - If
monorepo=yes: apply_monorepo/overlay; moveapp/intoapps/<app_name>/. - Unless
--no-install: runbun install. - Print next-steps output.
Next-steps output (claude, default)
✓ Created my-app (modular monolith · bun target)
cd my-app
bun dev → http://localhost:3000
Modules live under app/modules/. Want to scaffold a feature?
Open a NEW terminal in this project and run:
claude --permission-mode plan "/patties-init"
That starts an interactive, plan-mode session that scaffolds domain
modules with you before writing any files.
Tests
--yes⇒app/modules/home/routes/index.tsxandapp/modules/api/routes/api/health.tsexist;patties.config.tscontainsmodulesDirs.--no-ui⇒ noapp/components/ui/; demo page uses plain markup.--monorepo⇒apps/<name>/app/modules/exists; rootpackage.jsonhasworkspaces.--target container⇒Dockerfilepresent;target: "bun"in config.--agent none⇒ no.claude/or.codex/directories.--agent claude⇒.claude/rules/patties-modular-monolith.mdexists.- No test references
--type. Passing--typeexits with non-zero and prints the removal message. - Remove existing tests that assert flat
app/routes//app/islands/output. - CI scaffold-smoke: scaffold →
bun install→bun dev→ curl/and/api/health→ both 200.
Acceptance criteria
bunx create-pattieshas no project-type prompt. Every scaffolded app uses the modular monolith layout./and/api/healthboth return 200 from a freshly scaffolded app afterbun install && bun dev.patties.config.tsin every scaffold includesmodulesDirs: ["app/modules"].--ui yesyields components under the initial app's module directory, with the stamped Patties UI starter set.--monorepo yeswraps the initial app insideapps/<name>/with a Bun workspace root.--agent claudescaffolds include.claude/rules/patties-modular-monolith.md.- Passing
--typeexits with a clear removal message and non-zero exit code.