plugins/mcp-companion/skills/code-generation/SKILL.md
Generate production-ready code from a Qlerify domain model. Use when the user asks to "generate code from the model", "implement the workflow", "scaffold from Qlerify", "build the aggregate", "code up the domain model", "create the app from the model", or after a workflow has been modeled or extracted and the next step is producing runnable code on a target tech stack. Pairs with the workflow-creation skill (which produces the model) and the sync skill (which keeps model and code aligned over time).
npx skillsauth add qlerify/qlerify-plugins code-generationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate production-ready code from a Qlerify workflow. The model is the source of truth — entities, value objects, commands, read models, domain events, bounded contexts, invariants on attributes, and Given-When-Then acceptance criteria on events all map to code on a chosen tech stack.
This skill produces a working, tested application. The model lives in version control alongside the code, and future changes flow in both directions: re-running this skill applies model-side changes to the code; the sync skill applies code-side drift back into the model.
Lean toward iterating silently. Ask the user only when proceeding without an answer would commit you to a hard-to-reverse choice. Specifically:
If the workflow hasn't been downloaded locally yet, invoke the download skill — it bypasses MCP processing and is much faster for large specs. Otherwise call get_workflow once and cache the result.
Save the spec at <output-dir>/.qlerify/workflow.json (output dir is chosen in Phase 2) so the model travels with the code.
Read the $schema URL from the spec (e.g. https://app.qlerify.com/schemas/domain-model/v1.json) and fetch it if you need to verify field types, allowed values, or relationship structure. Treat it as authoritative for what the model can express.
Before generating any code, scan the model for issues that will produce broken or surprising code. Print a short report; ask the user only on hard blockers.
Hard blockers — ask before proceeding:
$ref doesn't exist in the specid field or an entity has no id field in the modelquantity: 0 is valid, attribute has min: 1)Soft signals — note and proceed:
.qlerify/codegen.json present) — generate in place; match the recorded stack.package.json, go.mod, etc.) — almost always legacy. Ask once: extend in place (rare, same-stack only) or generate into a sibling directory (default — ../{workflowName}-new). With the sibling option, the model file and .qlerify/codegen.json go there too.Record the chosen stack in .qlerify/codegen.json (created if absent) so subsequent generation runs stay consistent.
The model gives types, ownership, and dependencies — never storage. The agent chooses how to persist, guided by these principles:
*Id field pointing at another bounded context's aggregate carries no integrity constraint and no cascade across that boundary.Translation examples — pick the idiomatic one for the chosen stack:
version integer.Record any non-derivable persistence decisions in .qlerify/codegen.json — e.g. "Address VO embedded inline in Order" vs "Address VO stored as its own collection because the UI picker needs to list saved addresses" — so the sync skill and future generations can interpret the code.
Generate in this order so each step has the foundation it needs.
Initialize the project, install dependencies, configure the test runner, set up the storage connection.
Translate entities and value objects into the persistence layer using the Phase 3 mapping. If the stack uses schema migrations, generate one per generation run, named after the model version hash so future deltas are traceable. For schema-less stores, the hash recorded in .qlerify/codegen.json is enough.
Generate one module per aggregate (typically: one folder per bounded context, one module per aggregate root inside it).
Each module contains:
A command's argument structure mirrors the aggregate's nested entity/VO structure (as enforced by workflow-creation Phase 3 Step 5). The generated handler should accept that exact shape — don't flatten or rename.
One handler per command, mounted at an HTTP endpoint (or RPC method, per stack). Each handler:
Authorization is auth-ready, not auth-stubbed. The role check runs through a pluggable auth middleware (Fastify hook, Express middleware, NestJS Guard — stack-specific); its default implementation reads the role from an env var or request header so the server can be run and tested immediately. Swap in real auth (JWT, OAuth, session store) by replacing the middleware — handler code doesn't change. Flag the current wiring in the final report so the user knows what to replace before deploying.
A read model can be a direct read against the write side, a database view, or a precomputed projection — pick what's idiomatic for the chosen stack. Default to direct reads; reach for precomputed projections only with a concrete reason (cross-BC reads, measured perf needs, event sourcing).
The entity link names what to read from, isFilter: true fields are query parameters, and the rest are response fields.
Default to an in-process event bus. Each handler emits its event synchronously after a successful command. Subscribers are registered at startup.
Cross-bounded-context events: keep them in-process while the system is a single deployable. When the bounded contexts split into separate services, promote those events to an external broker (Kafka, RabbitMQ, NATS) — flag candidates in the final report.
Do not generate a state machine that enforces event ordering. Two different sequences of events may both be legal — the model doesn't always pin them down. Invariants on commands are what gate "illegal" transitions; the diagram is one valid path, not the only one.
For every event with acceptanceCriteria, generate one test per Given-When-Then string. Each test:
Place tests structurally: one test file per aggregate, one describe per command, one it per GWT. Predictable paths let future delta-apply find existing tests to update.
After generating, run the full suite (Phase 5).
Build a polished, demo-ready frontend with an explicit action surface: every command is reachable from a primary button or equivalent affordance in the view it belongs to, state changes are visible, and operational feedback (in-flight, success, error) is lightweight but present — without slipping back into debug-console territory. Drive layout from the model:
isFilter: true fields are filters/search, not raw query-string boxes.Cart aggregate gets a product grid with images and add-to-cart buttons; an Order aggregate gets a status timeline; a Subscription aggregate gets plan-picker cards. Avoid debug-console tells: no JSON dumps, no raw IDs in URLs, no "click to test command" buttons.exampleData verbatim. For a cart, invent a small catalog of plausible products (real-sounding names, sensible prices, images from a placeholder service like picsum.photos or placehold.co). For an order history, generate believable past orders across statuses. For subscriptions, named tiers with realistic pricing. The model's exampleData is the floor, not the ceiling, and it never belongs as pre-filled form values — that reads as a demo.Apply a polished styling baseline — Tailwind + small components, or Pico.css when avoiding a build step. Typography, spacing, and visual hierarchy do most of the work; bare HTML is most of what makes a generated UI feel like a test tool. For non-default stacks, ask once whether to include a frontend; the user may already have one or prefer a separate API client.
.skip(), don't change inputs to match the implementation. A failing test means either the code is wrong or the model is wrong — both warrant escalation, not silencing.Write .qlerify/codegen.json with:
workflowId and workflowNamemodelHash — content hash of the canonical JSON form of the spec, so a future run can compute a diffstack — the platform choices from Phase 2aggregates — names generated so far (merge with any prior list), so a later run knows what's done and what's pendingpersistenceDecisions — anything from Phase 3 that isn't directly derivable from the model (e.g., "VO Address stored inline on Order", "VO LineItem.discount stored as separate table with synthetic id")generatedAt — ISO timestampThis anchor lets a future invocation add a new aggregate or apply a model delta to existing ones as a targeted patch, instead of regenerating from scratch. Code-side drift (developer-added fields, renamed handlers, etc.) flows back through the sync skill — this skill is model → code; sync is code → model.
Anchor by structure, not by markers:
src/{boundedContext}/)src/{boundedContext}/{aggregate}/)types.ts, invariants.ts, commands.ts, handlers.ts, queries.ts{aggregate}.test.ts), structured describe(command) → it(gwt)Predictable paths let a delta-apply locate existing code without comment markers polluting the file. Only fall back to // qlerify: <ref> markers if the structure-only approach genuinely can't disambiguate (rare).
The default — load the full aggregate, mutate, save — is safe and matches the mental model. For performance-sensitive commands, an advanced user may opt into partial loads. Only do this when both are true:
If either condition fails, fall back to full-aggregate load. Saving a query isn't worth a silent invariant violation.
The skill is done when:
.qlerify/codegen.json is writtenworkflow-creation Phase 0sync skillworkflow-creation Step 7 is opt-in). For default state-based applications, the in-process bus from 4.6 is sufficient.tools
Create, extend, validate, and improve Qlerify workflow diagrams and domain models, including domain events, roles, read models, commands, policies, aggregates, entities, value objects, attributes, given-when-then scenarios, bounded contexts, and invariants. Use when the task involves event storming, event modeling, domain-driven design (DDD), specification-driven development (SDD), model-driven development (MDD), software modeling, domain modeling, process modeling, legacy modernization, reverse-engineering code into a model, generating code from a model, or any direct use of the Qlerify modeling tools.
development
This skill should be used when the user asks to "sync domain model", "update Qlerify", "push changes to Qlerify", "sync schemas", "sync entities", "sync domain events", or after implementing features that add or change entities, API endpoints, domain events, database schemas, migrations, or Prisma/GraphQL types. For brownfield/legacy codebases with unclear boundaries, isolate one aggregate at a time before running broad sync operations (the workflow-creation skill's Phase 0 covers aggregate extraction). Syncs the local codebase's domain model with Qlerify.
development
This skill should be used for planning when the user asks to create a workflow or domain model from an existing or legacy codebase, including requests like "reverse engineer the codebase", "document or model a legacy application", or "build a workflow from this code". Recommend isolating one DDD aggregate at a time, using one Qlerify workflow per aggregate, and following this skill's steps when PLANNING the work. This is a planning/preparation skill that should usually run BEFORE workflow-creation or sync in reverse-engineering scenarios. Produces a standalone aggregate plan (root entity, related entities, value objects, commands, optional domain events, read models, attributes, invariants, external references) for review before modeling in Qlerify.
tools
This skill should be used when the user asks to "save to file", "download", "export", "store in file", or any request that involves getting data from Qlerify and saving it locally. Bypasses AI processing and is ~100x faster than MCP tools for large data exports.