Blueprint Style Guide
Conventions for authoring high-quality FDL blueprints. Following these patterns produces blueprints that score well on the fitness scorer and pass the completeness checker cleanly.
Naming Conventions
| Element | Convention | Example | Enforced By |
|---|---|---|---|
| Feature name | kebab-case | password-reset | Schema regex ^[a-z][a-z0-9-]*$ |
| Field name | snake_case | first_name | Schema regex ^[a-z][a-z0-9_]*$ |
| Error code | UPPER_SNAKE_CASE | LOGIN_INVALID_CREDENTIALS | Schema regex ^[A-Z][A-Z0-9_]*$ |
| Event name | dot.notation | auth.login.success | Schema regex |
| Actor ID | snake_case | finance_manager | Schema regex ^[a-z][a-z0-9_]*$ |
| File name | {feature}.blueprint.yaml | login.blueprint.yaml | Convention |
Description
- Minimum 15 characters (enforced by completeness checker)
- Must not repeat the feature name verbatim
- Should explain what the feature does and who it serves
- Aim for 40-70 characters for best fitness score
# Bad
description: Login
# Good
description: Authenticate a user with email and password
Rules
Organize rules into categorized objects with at least 2 rules per category. Common categories:
| Category | Purpose |
|---|---|
security | OWASP-aligned security requirements |
validation | Input validation rules |
permissions | Authorization and access control |
rate_limiting | Rate limits and throttling |
business | Business logic constraints |
data | Data handling and storage rules |
audit | Logging and compliance requirements |
rules:
security:
- "Use constant-time comparison for password verification"
- "Never reveal whether an account exists"
validation:
- "Email must be a valid format"
- "Password must meet minimum length"
Outcomes
See Outcome Naming Conventions for naming patterns.
Structure
Every outcome should have:
given[]— conditions (structured preferred over plain text)then[]— side effects (structured actions preferred)result— human-readable description of what happenspriority— evaluation order (lower = checked first)
outcomes:
rate_limited:
priority: 0
error: LOGIN_RATE_LIMITED
given:
- field: request_count
source: system
operator: gt
value: 100
then:
- action: emit_event
event: auth.rate_limit.exceeded
payload: [ip_address, timestamp]
result: "Request rejected due to rate limiting"
successful:
priority: 10
given:
- field: email
source: db
operator: exists
then:
- action: set_field
target: failed_login_attempts
value: 0
- action: emit_event
event: auth.login.success
payload: [user_id, email, timestamp]
result: "User is authenticated and session created"
Outcomes vs Flows
| Use Case | Use outcomes | Use flows | Use Both |
|---|---|---|---|
| Technical features (login, CRUD) | Yes | No | - |
| Business processes (approvals) | Yes | Yes | Yes |
| Workflow documentation only | No | Yes | - |
Error Codes
- Define all errors in the
errors[]array - Bind every error code to at least one outcome using
error: - Include a user-facing
messagefor every error - Include an HTTP
statuscode
errors:
- code: LOGIN_INVALID_CREDENTIALS
status: 401
message: "Invalid email or password"
- code: LOGIN_ACCOUNT_LOCKED
status: 423
message: "Account temporarily locked"
Fields
- Every field needs
name,type, andrequired - Add
labelfor all user-facing fields - Add
validation[]rules — fields without validation are flagged
fields:
- name: email
type: email
required: true
label: "Email Address"
validation:
- type: required
message: "Email is required"
- type: email
message: "Please enter a valid email"
Relationships
- Use typed relationships with
reasonexplanations - Types:
required,recommended,optional,extends - Cross-references are validated —
requiredtargets must exist
related:
- feature: password-reset
type: recommended
reason: "Users who fail login may need to reset"
AGI Section
Expected by category:
| Category | Autonomy Level | Typical Goals |
|---|---|---|
| auth, security | supervised / human_in_loop | Identity verification, access control |
| data, infrastructure | semi_autonomous | Data processing, resource management |
| ai | fully_autonomous | ML inference, model management |
| payment | human_in_loop | Transaction processing |
| workflow | supervised | Process orchestration |
Include at minimum: goals, autonomy, verification (with invariants).
Fitness Score Targets
| Score Range | Quality | Action |
|---|---|---|
| 90-100 | Excellent | No action needed |
| 80-89 | Good | Minor improvements |
| 70-79 | Acceptable | Add missing outcomes or relationships |
| 60-69 | Needs work | Likely missing error paths or AGI section |
| Below 60 | Poor | Major sections missing |
Run node scripts/fitness.js blueprints/category/feature.blueprint.yaml to see a detailed breakdown.
Multi-File Generation Conventions
When AI generates code from a blueprint, it produces multiple files. This table documents the standard file roles and paths per framework:
File Roles by Framework
| Role | Next.js | Express | Python/FastAPI | Laravel |
|---|---|---|---|---|
| model | src/models/{feature}.ts | src/models/{feature}.ts | app/models/{feature}.py | app/Models/{Feature}.php |
| service | src/services/{feature}.ts | src/services/{feature}.ts | app/services/{feature}.py | app/Services/{Feature}Service.php |
| controller | src/app/api/{feature}/route.ts | src/routes/{feature}.ts | app/routers/{feature}.py | app/Http/Controllers/{Feature}Controller.php |
| page | src/app/{feature}/page.tsx | N/A | N/A | resources/views/{feature}/index.blade.php |
| component | src/components/{Feature}.tsx | N/A | N/A | N/A |
| test | __tests__/{feature}.test.ts | tests/{feature}.test.ts | tests/test_{feature}.py | tests/Feature/{Feature}Test.php |
| migration | prisma/migrations/ | prisma/migrations/ | alembic/versions/ | database/migrations/ |
| types | src/types/{feature}.ts | src/types/{feature}.ts | app/schemas/{feature}.py | N/A |
What Each Side Effect Action Generates
then[] Action | Files Generated |
|---|---|
create_record | Model file + database migration + service method |
emit_event | Event bus setup + event handler file |
transition_state | State machine logic in service layer |
notify | Notification service + message template |
call_service | External service client + interface/types |
set_field | Field update logic in service layer |
invalidate | Cache invalidation logic in service layer |
Outcome Prerequisites
Outcomes can include a prerequisites field — an array of strings explaining what state must exist before the outcome is evaluated. This helps AI understand evaluation order:
outcomes:
invalid_credentials:
priority: 4
prerequisites:
- "User record loaded from database by email"
- "Password hash computed from input"
given:
- field: user
source: db
operator: not_exists
Prerequisites are auto-generated by node scripts/propagate-prerequisites.js based on given[] data sources.
Event Payload Schema
Events can include a payload_schema alongside the plain payload array, providing typed field definitions with data sources:
events:
- name: auth.login.success
payload: [user_id, email, timestamp]
payload_schema:
- field: user_id
type: string
source: db.users
- field: email
type: email
source: input
- field: timestamp
type: datetime
source: system
This tells AI exactly where each payload field comes from, eliminating guesswork during code generation.