β οΈ Work in progress β pre-release software. Pegasus is under active development and has not been published to npm. APIs, generated-code shape, schema syntax, and CLI flags can all change without notice. Don't use it for production projects yet; do try it, file issues, and read PLAN.md for what's stable vs. what's still moving.
YAML-driven full-stack app generator. Schemas β working app, with a visual editor, multiple framework adapters, and one-click GitHub export.
Pegasus reads YAML schema files describing your data models, fields,
relations, endpoints, and auth, and produces a runnable application β
database schema, ORM models, API routes, auth flows, frontend pages, and
project scaffolding (package.json, tsconfig.json, β¦) all included.
schemas (.pegasus/*.yml) βββ
β pegasus generate
config.yml ββββββββββββββββββββββββΊ production app
β (one of seven targets)
adapter selection βββββββββββ
# Prereqs: Node 20+, pnpm (via corepack)
corepack enable
pnpm install
pnpm build
# Try Pegasus Studio in seconds β creates a sandbox project + opens
# the browser UI at http://127.0.0.1:3031
pnpm studioOr hands-on with the CLI:
# 1. Scaffold a project
node packages/cli/bin/pegasus.js init my-app
cd my-app
# 2. Pick a backend adapter (any of: nextjs, express, fastapi, laravel)
node ../packages/cli/bin/pegasus.js adapters add @pegasus/adapter-nextjs
# 3. Generate
node ../packages/cli/bin/pegasus.js generate
# 4. Build the generated app
pnpm install
cp .env.example.generated .env # set DATABASE_URL + JWT_SECRET
pnpm db:migrate
pnpm dev # http://localhost:3000Once published to npm, the flow becomes the familiar npx @pegasus/cli init.
A pegasus generate against the bundled core schemas (10 base SaaS models)
and @pegasus/adapter-nextjs produces:
- Prisma schema β every model with FKs, indexes,
@@uniquecomposite indexes, soft-delete columns where declared - 20+ API route handlers β per-model CRUD with auth middleware, pagination (offset + cursor), owner-field scoping, admin-only field guards, hashed-field auto-hashing
- Full auth surface β
/api/auth/{login,register,refresh,logout,me,forgot-password,reset-password,verify-email,magic-link,oauth/[provider]} - Frontend pages β login, register, forgot/reset, magic-link,
verify-email, dashboard with a typed
<DataTable>component - Project scaffolding β
package.json(pinned next/react/prisma/argon2/zod),tsconfig.json(strict, Next-matched),next.config.mjs,README.md,.env.example.generated
pnpm install && pnpm build produces a Vercel-ready app.
pnpm studio (or pegasus studio from any project root) launches a
local browser UI at http://127.0.0.1:3031 for editing schemas without
touching YAML directly.
| Page | What it does |
|---|---|
/ |
Schema list with entry/partial tag chips |
/schemas/[stem] |
Visual form editor β field/relation/endpoint rows; round-trips losslessly with un-exposed attrs (hooks, indexes, admin_only, hashed, β¦) preserved |
/schemas/[stem]?view=yaml |
Raw YAML editor (the textarea, with rollback on validation failure) |
/new |
New-model wizard β create a schema from a form |
/project |
Visual .pegasus/config.yml editor with adapter dropdowns |
/generate |
Read-only diff preview β classifies each planned file as new/updated/edited/protected/orphan/unchanged |
/preview |
List of generated files currently on disk |
/export/github |
Push the project to a fresh GitHub repo via the REST API in 6 calls (form takes a PAT, used once, never stored) |
Loopback-only by default (127.0.0.1), CSP-clean, CSRF-guarded,
accessible (skip-link, focus rings, aria-current, breadcrumbs), light +
dark theme.
Backend (pick one):
| Package | Stack | Tests |
|---|---|---|
@pegasus/adapter-nextjs |
Next.js 14 App Router + Prisma + JWT (full-stack β bundles a frontend) | 101 |
@pegasus/adapter-express |
Express 4 + Prisma + JWT (pair with a frontend adapter) | 12 |
@pegasus/adapter-fastapi |
FastAPI + SQLAlchemy 2 (async) + Pydantic v2 + argon2 (Python) | 8 |
@pegasus/adapter-laravel |
Laravel 11: Eloquent + FormRequests + apiResource (PHP) | 7 |
Frontend (pair with a non-bundling backend):
| Package | Stack | Tests |
|---|---|---|
@pegasus/adapter-react |
Vite + React 18 SPA, react-router, typed API client | 7 |
@pegasus/adapter-vue |
Nuxt 3 + Vue 3 Composition API, typed useApi() / useAuth() |
6 |
Meta:
| Package | Output | Tests |
|---|---|---|
@pegasus/adapter-openapi |
OpenAPI 3.1 spec from schemas β feed to Swagger UI / Redoc / openapi-generator | 11 |
Discover community adapters with pegasus adapters search. Build your
own in ~300 lines using the contract documented in ADAPTERS.md;
@pegasus/adapter-openapi is the canonical reference implementation.
PostgreSQL Β· MySQL Β· SQLite β all three supported by the Next.js and
Express adapters via Prisma. SQLite needs no server (zero-setup dev:
DATABASE_URL="file:./dev.db"); enums and Json fall back to String
with the API-layer Zod validators still enforcing constraints. PostgreSQL
and MySQL get native enums and JSON columns.
Generated apps ship with:
- Email + password with argon2id hashing
- JWT access tokens (HS256, 15min default TTL, alg+typ header check)
- Opaque refresh tokens (random 48 bytes, hashed at rest, rotation + reuse detection that revokes every active token for the user on reuse)
- Forgot/reset password with purpose-bound JWTs (15min TTL, identical 200 response regardless of email existence β no enumeration oracle)
- Email verification (24h TTL, idempotent confirm)
- Magic-link sign-in (10min TTL, one-page form + auto-consume)
- OAuth2 (Google + GitHub) β authorization-code flow, signed state cookie + double-check, email-based account linking, no SDK dependency
- Per-IP rate limiting on login (10/min), register (20/min), forgot-password (5/min), magic-link (5/min) β in-memory LRU default, Upstash swap-in recipe in the file header
User-extensible via before/after_{create,update,delete} hooks β the
adapter generates non-overwritable stubs at src/hooks/<name>.ts.
pegasus/
βββ packages/
β βββ core/ # @pegasus/core β engine
β βββ core-schemas/ # @pegasus/core-schemas β 10 base SaaS schemas
β βββ cli/ # @pegasus/cli β the `pegasus` binary
β βββ studio/ # @pegasus/studio β browser UI
β βββ adapter-nextjs/
β βββ adapter-express/
β βββ adapter-fastapi/
β βββ adapter-laravel/
β βββ adapter-react/
β βββ adapter-vue/
β βββ adapter-openapi/
βββ scripts/
β βββ studio.mjs # `pnpm studio` launcher (sandbox project)
βββ ADAPTERS.md # Adapter-author guide
βββ CLOUD.md # Pegasus Cloud design sketch
βββ PLAN.md # Full design + roadmap
βββ turbo.json
βββ pnpm-workspace.yaml
βββ tsconfig.base.json
pegasus init <name> # scaffold a project
pegasus add model <name> # add a new model schema
pegasus validate # check schemas without generating
pegasus generate # write generated code
pegasus generate --extend # re-generate, preserving developer edits (via .pegasus/checksums.json)
pegasus generate --dry-run # preview without writing
pegasus diff # classify each planned file (new/updated/edited/protected/orphan)
pegasus doctor # health check (schemas + config + adapter resolvable)
pegasus adapters list # show first-party + configured adapters
pegasus adapters add <pkg> # wire an adapter into config.yml
pegasus adapters search [q] # discover community adapters via npm
pegasus studio [--port N] # launch the browser UIpnpm install
pnpm build # turbo β every package
pnpm test # vitest across the workspace
pnpm typecheck # strict TS across the workspace
pnpm lint
pnpm format
pnpm studio # bring up the UI against scripts/studio-sandbox/Single package:
pnpm --filter @pegasus/core test
pnpm --filter @pegasus/adapter-nextjs test:watchSecurity is a first-class concern. Highlights, by layer:
Engine (@pegasus/core)
- No YAML code execution β every
yaml.loadusesJSON_SCHEMA(blocks!!js/functionand custom tags) - Path traversal blocked at parse time + via
fs.realpathcontainment - Prototype-pollution defense: strict Zod schemas +
__proto__/constructor/prototypeblocklist in deep-merge - DoS bounds: file size 256 KB,
extendsdepth 16, files-per-dir 10 000
CLI (@pegasus/cli)
- Output paths validated via
assertProjectPathβ refuses anything escaping the project root or landing innode_modules/ pegasus adapters searchcaps registry response at 2 MB (stream-with-cap reader, not buffer-all)
Studio (@pegasus/studio)
- Loopback-bound by default; remote access is an explicit
--hostopt-in - Origin/Referer CSRF check on every state-changing request (works on Firefox via
Referrer-Policy: same-origin) - 64 KB body cap; stricter stem regex + node_modules refusal on every file write
- Strict CSP (
default-src 'self';'unsafe-inline'only for the design-token<style>block) - Server-side validation for every external API user input β including GitHub-export
owner/repo(regex-validated; client-sidepattern=is never the only check)
Generated apps (@pegasus/adapter-nextjs)
- argon2id password hashing
- HttpOnly + SameSite=Strict refresh cookie; refresh-token rotation with reuse detection that revokes every active token for the user
- Explicit
alg+typJWT header checks (alg-confusion defense) Cache-Control: no-storeon every auth response- Public
POST /userssuppressed on the JWT-owning schema (registration only via/auth/register); non-adminPATCHrejects bodies containingadmin_onlyfields - Per-IP rate limiting on login/register/forgot-password/magic-link with true LRU eviction (under sustained churn an attacker can't bypass by cycling IPs)
- OAuth2 same-origin returnTo validation at both
/startand/callback(open-redirect defense); Googleemail_verifiedenforcement - Email-flow purpose tokens cross-purpose refusal (a reset token can't be replayed as a verify token, etc.)
350 tests across 11 packages:
| Package | Tests |
|---|---|
@pegasus/core |
48 |
@pegasus/core-schemas |
10 |
@pegasus/cli |
80 |
@pegasus/studio |
60 |
@pegasus/adapter-nextjs |
101 |
@pegasus/adapter-express |
12 |
@pegasus/adapter-fastapi |
8 |
@pegasus/adapter-laravel |
7 |
@pegasus/adapter-react |
7 |
@pegasus/adapter-vue |
6 |
@pegasus/adapter-openapi |
11 |
CI runs typecheck Β· lint Β· format:check Β· build Β· test Β· pnpm audit --prod --audit-level high on ubuntu Β· macos Β· windows Γ Node 20 Β· 22.
The OSS roadmap is feature-complete. Every line item in PLAN.md
is [x] (done) or [~] with a documented deferred follow-up. Pegasus
Cloud is scoped as a separate hosted product in CLOUD.md.
What's deliberately not in scope:
- Hosting the generated app (deploy to whatever platform you already use)
- Owning user data (apps connect to customer-managed databases)
- Locking schemas in (
pegasus generateis the source of truth β your.pegasus/directory is portable, version-controllable, and works identically against the OSS CLI forever)
- PLAN.md β full design document + closeout roadmap
- ADAPTERS.md β
BackendAdaptercontract + author's guide - CLOUD.md β Pegasus Cloud (hosted) design sketch
- Each
packages/<name>/README.mdβ package-specific surface
MIT β see LICENSE.