{"slug": "i-built-a-cli-that-scaffolds-the-boring-parts-of-an-ai-saas-here-s-what-it", "title": "I built a CLI that scaffolds the boring parts of an AI SaaS — here's what it actually generates", "summary": "A developer built @chimerai/cli, a command-line tool that scaffolds the boilerplate for AI SaaS projects, generating Next.js app routes, a Prisma schema with feature-gated models, AES-256 encrypted provider API key storage, and resource:action RBAC checks. The CLI resolves feature dependencies automatically (admin-dashboard requires RBAC, rag requires model-providers) and splits the stack between TypeScript for user-facing code and a Python LLM orchestration service reached via AI_SERVICE_URL. It supports SQLite or PostgreSQL 16 plus Redis 7 via Docker Compose, and requires Next.js 15+ for its async route handler params.", "body_md": "Every AI SaaS project starts with the same two days of nothing-interesting: auth, a users\n\ntable, an encrypted place to store provider API keys, a Prisma schema. Then you finally get to\n\nthe part you actually wanted to build.\n\nI've been working on a CLI (`@chimerai/cli`) that scaffolds exactly that prefix. This post is\n\nabout what it *actually writes to disk* — not what a landing page would claim — because that's\n\nthe only thing that matters when you decide whether to adopt a generator.\n\n```\nnpx @chimerai/cli create my-ai-app\n```\n\nInteractive feature selector. Defaults are auth + RBAC + admin dashboard + analytics; AI\n\nfeatures are opt-in. Flags worth knowing:\n\n```\nchimerai create my-ai-app --yes              # no prompts, defaults\nchimerai create my-ai-app --sqlite           # no Docker needed, DATABASE_URL=file:./dev.db\nchimerai create my-ai-app --yes --install    # + npm install\n```\n\n`--sqlite` is the one I'd start with if you just want to look at the code. Without it you get\n\na `docker-compose.yml` for PostgreSQL 16 + Redis 7.\n\n```\nmy-ai-app/\n├── app/\n│   ├── layout.tsx\n│   ├── page.tsx\n│   ├── api/auth/          # NextAuth routes (if auth selected)\n│   └── admin/             # admin pages (if selected)\n├── components/ui/         # shadcn/ui components\n├── lib/\n│   ├── prisma.ts          # PrismaClient singleton\n│   ├── auth.ts            # auth config\n│   └── encryption.ts      # API key encryption\n├── prisma/schema.prisma   # only models for selected features\n├── .env\n├── docker-compose.yml\n└── package.json\n```\n\nThe generated Prisma schema is additive per feature, which is the part I check first in any\n\nscaffolding tool — if it gives me six models when I asked for two, I stop trusting it:\n\n| Selected | Models added | \n|---|---|\n| Auth | `User` ,`Account` ,`Session` ,`VerificationToken` | \n| RBAC | `Role` ,`Permission` | \n| Providers | `ModelProvider` | \n| Prompts | `PromptTemplate` | \n| Analytics | `ApiUsage` | \n\nFeature dependencies are resolved by the CLI rather than left to you: `admin-dashboard`\n\nrequires RBAC, `model-providers` requires auth (the encryption key lives in the auth config),\n\n`chat-ui` requires `model-providers`, `rag` requires `model-providers`.\n\nThe split is deliberate: the LLM orchestration layer is Python because that's where the\n\necosystem lives (LangChain, FAISS, spaCy), and everything type-safe and user-facing stays\n\nTypeScript. The Next.js side proxies to `AI_SERVICE_URL` (default `http://localhost:8002`).\n\nProvider management with encrypted keys, which is the thing everyone re-implements badly:\n\n``` js\nconst response = await fetch('/api/providers', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    name: 'OpenAI GPT-4',\n    provider: 'openai',      // | 'anthropic' | 'ollama' | 'custom'\n    apiKey: 'sk-...',\n    isActive: true,\n  }),\n});\n```\n\nKeys are stored AES-256 encrypted at rest using `ENCRYPTION_KEY` from `.env`, never in the\n\ndatabase in plaintext. `provider: 'custom'` takes any OpenAI-compatible `baseURL`, which is how\n\nyou wire up a self-hosted vLLM or an OpenRouter-style gateway without the core knowing about it.\n\nYou can also add providers through the admin UI and test the connection before using it — small\n\nthing, saves an annoying debugging loop.\n\nRBAC uses `resource:action` permission strings, checked in API routes:\n\n``` js\nimport { requirePermission } from '@/lib/auth/require-permission';\n\nexport async function GET(req: NextRequest) {\n  const permissionError = await requirePermission('posts:read');\n  if (permissionError) return permissionError;\n  // ...\n}\n```\n\n`admin:*` is a wildcard. Roles carry permission lists; there's a seeded admin\n\n(`admin@example.com` / `admin123` — remove it, obviously).\n\n`@chimerai/model-providers`, `@chimerai/admin-ui` etc. exist\nin the monorepo. `chimerai create` therefore generates `chimerai add` requires Next.js 15+ (generated route handlers use the async `params` API).\nThe CLI detects the version and warns below 15. Standalone `create` output runs on port 3001\nby default to avoid colliding with another dev server.`create-next-app` plus a library like\nLangChain is a perfectly reasonable starting point — pick the generator that matches the\nproblem.\nYou don't have to start from a generated project:\n\n```\ncd my-nextjs-app\nnpx chimerai add auth\nnpx chimerai add model-providers\nnpx chimerai add chat-ui\npnpm install\nnpx prisma db push && npx prisma db seed\npnpm dev\n```\n\nThe CLI finds the project root by walking up for a `.chimerai` marker, then falls back to a\n\nregistry in `~/.chimerai/projects.json`, then `--dir`. In a monorepo, point `--dir` at the\n\nNext.js app (`apps/frontend`), not the workspace root — the root has no `app/` and no `prisma/`.\n\n`chimerai doctor` runs health checks on env vars, DB connectivity, and installed components,\n\nwhich is mostly there because I forgot to set `ENCRYPTION_KEY` often enough to be embarrassing.\n\n`chimerai add rag` — FAISS index, chunking, and the `/api/rag/query` round trip\nRepo: `github.com/armbur19-collab/chimerai-kickstart` · site: chimerai.dev", "url": "https://wpnews.pro/news/i-built-a-cli-that-scaffolds-the-boring-parts-of-an-ai-saas-here-s-what-it", "canonical_source": "https://dev.to/armin_burger_ab136b2f8bb1/i-built-a-cli-that-scaffolds-the-boring-parts-of-an-ai-saas-heres-what-it-actually-generates-248f", "published_at": "2026-09-24 09:56:07+00:00", "updated_at": "2026-09-24 10:01:51.652626+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-products", "large-language-models"], "entities": ["@chimerai/cli", "Next.js", "Prisma", "NextAuth", "LangChain", "FAISS", "OpenAI", "Anthropic"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/i-built-a-cli-that-scaffolds-the-boring-parts-of-an-ai-saas-here-s-what-it", "markdown": "https://wpnews.pro/news/i-built-a-cli-that-scaffolds-the-boring-parts-of-an-ai-saas-here-s-what-it.md", "text": "https://wpnews.pro/news/i-built-a-cli-that-scaffolds-the-boring-parts-of-an-ai-saas-here-s-what-it.txt", "jsonld": "https://wpnews.pro/news/i-built-a-cli-that-scaffolds-the-boring-parts-of-an-ai-saas-here-s-what-it.jsonld"}}