Agent Skill
2/7/2026

sea-generator-first

Enforces the generator-first workflow for SEA-Forge development. Activates when working in the SEA codebase and any intent to modify code, add features, fix bugs, or implement changes. Redirects code-editing intent to spec-first workflow and enforces that all generated code zones are never hand-written. Triggers for any attempts to edit libs or apps directories, generated code, feature implementation, bug fixes, or adding new entities, ports, or adapters.

G
godspeedai
1GitHub Stars
1Views
npx skills add GodSpeedAI/SEA

SKILL.md

Namesea-generator-first
DescriptionEnforces the generator-first workflow for SEA-Forge development. Activates when working in the SEA codebase and any intent to modify code, add features, fix bugs, or implement changes. Redirects code-editing intent to spec-first workflow and enforces that all generated code zones are never hand-written. Triggers for any attempts to edit libs or apps directories, generated code, feature implementation, bug fixes, or adding new entities, ports, or adapters.

name: sea-generator-first description: Use when implementing or fixing behavior in SEA-Forge, especially when generated outputs may change. Enforces spec-first regeneration and requires semantic fixture updates whenever libs//src/gen/ changes.

SEA-Forge Generator-First Guardrail

IRON RULE: Specifications are the source of truth. Code is generated from specs, never written by hand.

No-Technical-Debt Rule

This skill forbids placeholders of any kind. Do not introduce or suggest:

  • TODO/FIXME/XXX/HACK/STUB markers
  • Stubs, mocks-as-implementations, or empty handlers
  • raise NotImplementedError / throw new Error("not implemented")
  • pass, ..., or any placeholder logic

Exceptions (per technical-debt.instructions.md):

  • pass/... in @abstractmethod functions is allowed
  • pass/... in .pyi stub files is allowed
  • Abstract classes inheriting ABC or Protocol are allowed

If an issue blocks progress, request explicit user feedback with options and a recommendation. Never silently stub.

The Generator-First Contract

┌──────────────────────────────────────────────────────────────┐
│                    GENERATOR-FIRST CONTRACT                  │
├──────────────────────────────────────────────────────────────┤
│  1. Files in **/src/gen/** are NEVER hand-written            │
│  2. All structural changes start in .sea or .sds.yaml        │
│  3. Pipeline: spec → AST → IR → manifest → code             │
│  4. Regeneration produces identical output (determinism)     │
│  5. After pipeline, run gap-report; run last-mile only if gaps exist │
│  6. After code changes, always update semantic fixtures      │
│  7. Full CI (`just ci`) must pass — not just `just ci-quick` │
└──────────────────────────────────────────────────────────────┘

Forbidden Zones (Never Edit)

Path PatternWhyFix Instead
**/src/gen/**Generated from manifestEdit spec, run just pipeline <ctx>
docs/specs/**/*.ast*.jsonAST projectionEdit .sea file
docs/specs/**/*.ir.jsonIR projectionEdit .sea or .sds.yaml
docs/specs/**/*.manifest.jsonCompiled manifestEdit spec, re-run pipeline
docs/specs/**/fixtures/semantic/*.semantic.fixture.yamlGenerated fixture baselineAdd/update a separate *.fixture.yaml scenario file in the same folder
Files with @generated / Generated by / DO NOT EDIT in first 10 linesGenerated outputFix upstream spec or generator
Any file derived from a manifestGenerated outputFix upstream spec or generator
tsconfig.base.json path mappingsGenerator-ownedUpdate tools/nx/ templates and regenerate

Detecting Generated Code

Check the first 10 lines for banners:

  • Python: # @generated, # Generated by, # DO NOT EDIT
  • JS/TS: // @generated, // Generated by, // DO NOT EDIT

Partial generation uses begin/end markers:

  • Python: # BEGIN GENERATED / # END GENERATED
  • JS/TS: // BEGIN GENERATED / // END GENERATED

Safe Edit Zones

Path PatternWhat Goes Here
docs/specs/**/*.seaSEA-DSL domain specifications
docs/specs/**/*.sds.yamlSDS YAML specifications
docs/specs/**/*.mdADR, PRD documentation
docs/specs/**/fixtures/semantic/*.fixture.yamlHand-authored semantic intent fixtures required by CI guard
tools/codegen/Python codegen pipeline (gen.py, templates, validators)
tools/codegen/templates/*.jinja2Jinja2 code generation templates
generators/Nx generators and TypeScript templates
libs/<ctx>/adapters/src/ (non-gen)Handwritten integration adapters (must implement SDS port interfaces)
libs/<ctx>/**/tests/Unit and integration test files
tests/Top-level test files

Integration Adapter Exception: Files in libs/<ctx>/adapters/src/ (outside src/gen/) are handwritten. They must implement the port interfaces defined by the SDS. This includes files like libs/documentation/adapters/src/handlebars-template.adapter.ts.

Mandatory Pre-Push Guard Parity

Always run the same guard used by CI before pushing changes that touch generated outputs.

GITHUB_BASE_REF=<base-branch> scripts/ci/spec_and_fixtures_guard.sh

Use your PR target for <base-branch> (dev, main, etc.).

If the guard reports:

  • Generated code changed, but no upstream specs changed
  • Generated code changed, but no semantic fixtures changed

then you must add/update at least one file under:

  • docs/specs/** and
  • docs/specs/<context>/fixtures/semantic/** (or docs/specs/shared/fixtures/semantic/**)

before pushing.

Intent Interception Workflow

Trigger Detection

Intercept when agent detects ANY of these intents:

  • "Add feature X" / "Fix bug in Y" / "Create entity Z"
  • "Implement port P" / "Add adapter A"
  • "Modify code in libs/" / "Edit code in apps/"
  • "Remove NotImplementedError" / "Implement handler"

Decision Tree

Request arrives
  │
  ├─ Does it target **/src/gen/** or a generated file?
  │   ├─ YES → ⚠️ Stop and ask (see below)
  │   └─ NO → Continue normally
  │
  ├─ Does it target tools/codegen/ or generators/?
  │   └─ YES → Edit allowed (generator is the correct upstream fix)
  │        └─ After fixing, regenerate affected contexts
  │
  ├─ Does it target libs/<ctx>/adapters/src/ (non-gen)?
  │   └─ YES → Edit allowed (handwritten adapter zone)
  │
  └─ Does it target docs/specs/**?
      └─ YES → Edit allowed (specs are source of truth)
           └─ After editing, validate and run pipeline

Stop and Ask if a Generated Zone Is Targeted

⚠️ **Implementation Gap Detected**

This request requires editing generated code or outputs, but:
- Generated outputs must be changed via specs and regeneration
- Handwritten edits in generated zones are forbidden
- [Reference gap from `docs/workdocs/code_archeology.md` if applicable]

**Options:**
1. **Spec-first path**: Update specs, run pipeline, regenerate (recommended)
2. **Generator fix**: Fix the codegen template or gen.py if the defect is in the pipeline
3. **Clarify requirements**: Provide missing spec details first

Which approach? I recommend option 1 unless the defect is in the generator itself.

Spec-First Workflow

Step 1: Check What Exists

ls docs/specs/<context>/*.sea docs/specs/<context>/*.sds.yaml 2>/dev/null

Step 2a: If Spec Exists — Edit, Validate, Generate

  1. Edit the spec file (.sea or .sds.yaml)

  2. Validate:

    just sds-validate docs/specs/<context>/<context>.sds.yaml
    just sea-validate docs/specs/<context>/<context>.sea
    
  3. Run full pipeline:

    just pipeline <context>
    

    This single command validates specs, parses SEA-DSL, builds AST/IR/manifest, and generates code. Do NOT run just codegen separately — just pipeline already invokes it.

  4. Check for missing adapters:

    just gap-report <context>
    
  5. If gaps exist, generate adapters:

    just last-mile <context>
    
  6. Run semantic validation:

    just semantic-check <context>
    
  7. Verify determinism:

    just regen-check docs/specs/<context>/<context>.manifest.json
    
  8. Run full CI:

    just ci
    

Step 2b: If Spec Does Not Exist

  1. Use spec-authoring skill to create ADR → PRD → SDS → SEA-DSL
  2. Ensure proper CQRS annotations: @cqrs, @tx, @outbox
  3. Then follow Step 2a

Step 3: Verify No Debt Markers

rg -n "NotImplementedError|TODO|FIXME|HACK|STUB|_execute_logic" \
  libs/<context>/**/src/gen/ 2>/dev/null

Expected: zero matches. If debt markers appear in generated output, the defect is in the Jinja2 template, not the spec.

Quick Reference: Just Recipes

RecipePurpose
just pipeline <ctx>Full spec → code pipeline (validate + parse + AST + IR + manifest + codegen)
just sds-validate <file>Validate SDS YAML against schema
just sea-validate <file>Validate SEA-DSL syntax
just sds-compile <file>Compile SDS YAML to manifest.json
just codegen <manifest>Generate code from manifest (prefer just pipeline instead)
just gap-report <ctx>Show missing adapters for a context
just last-mile <ctx>Generate all missing adapters and tests
just last-mile-allRun last-mile for all contexts
just semantic-check <ctx>Governance validation (runs semantic-fixtures-ctx first)
just semantic-fixturesValidate all semantic fixture files
just regen-check <manifest>Verify regeneration produces identical output
just spec-guardValidate all specs with cross-check
just flow-lintFlow annotation compliance check
just ciFull local CI (lint + spec + test + determinism)
just ci-quickFast check (lint + specs only — insufficient for PRs)

Common Patterns

Adding a New Entity

  1. Edit domain .sea or .sds.yaml to add entity definition
  2. Run just pipeline <context>
  3. Entity appears in libs/<context>/domain/src/gen/
  4. Run just gap-report <context> to check for cascading gaps

Adding a New Command or Query

  1. Add command/query definition to .sds.yaml under cqrs.commands or cqrs.queries
  2. Specify input fields, output type (for queries), and touches.aggregates (for commands)
  3. Run just pipeline <context>
  4. Handler appears in libs/<context>/application/src/gen/commands/ or queries/
  5. Update semantic fixtures with scenarios for the new handler

Adding a New Port

  1. Edit .sds.yaml ports section
  2. Run just pipeline <context>
  3. Port interface appears in libs/<context>/ports/src/gen/
  4. Run just gap-report <context> to see missing adapter implementations
  5. Run just last-mile <context> to generate adapter templates

Fixing a Bug in Generated Code

Three possible root causes — diagnose before fixing:

  1. Stale generated code (spec changed but pipeline wasn't re-run):

    • Run just pipeline <context> to regenerate
  2. Spec defect (spec defines wrong structure):

    • Fix the .sds.yaml or .sea file
    • Run just pipeline <context>
  3. Generator defect (template or gen.py produces wrong output):

    • Fix the Jinja2 template in tools/codegen/templates/ or tools/codegen/gen.py
    • Add regression test in tools/tests/test_codegen_templates.py
    • Regenerate all affected contexts: just pipeline <context>
    • Use debugging-codegen-pipeline skill for systematic triage

NEVER edit src/gen/ files. Trace backward: generated code → manifest → IR → AST → spec.

Known Generator Pitfalls

These are real defects that have occurred in the codegen pipeline. Watch for them:

PitfallSymptomRoot CauseFix Location
Dict-style query output not unwrappedNoneReadRepositoryPort, List["None"] in generated querygen.py receives {"type": "Foo"} but expects stringtools/codegen/gen.py
Command prefix not in _build_entity guard_execute_logic referenced but never definedcommand.py.jinja2 prefix whitelist incompletetools/codegen/templates/command.py.jinja2
'result_entity' in dir() runtime guardMasks variable assignment bugs at runtimeOld template artifacttools/codegen/templates/command.py.jinja2
Filesystem import path in generated codefrom libs.ctx.domain.src.gen.types import ...Template uses filesystem path instead of package pathtools/codegen/templates/command.py.jinja2
Bare except ExceptionSwallows KeyboardInterrupt, SystemExitTemplate catches too broadlyTemplate handlers
sea CLI not found (exit code 127)just sea-parse or just sea-validate failsNo console_scripts entry in sea_dsl packageUse the Manual Pipeline Fallback (Graph.parse_to_ast_json()) or install sea_dsl with proper console_scripts so CLI wrappers resolve
expected EOI / Parse error in SEA parseSEA-DSL file uses # commentsPEG parser only supports // commentsReplace all # comments with //
SDS ports format error ('str' has no attribute 'get')ir_to_manifest.py crashes on ports sectionSDS ports: is a dict instead of a list of dictsUse list format: ports:\n - name: PortName\n id: PORT-001

Manual Pipeline Fallback

When just pipeline <ctx> fails due to environment issues (broken venv, missing CLI), run each step individually:

# Step 1: Parse SEA → AST (uses Python API directly)
.venv/bin/python -c "
from sea_dsl.sea_dsl import Graph
with open('docs/specs/<ctx>/<ctx>.sea') as f:
    source = f.read()
ast_json = Graph.parse_to_ast_json(source)
with open('docs/specs/<ctx>/<ctx>.ast.json', 'w') as f:
    f.write(ast_json)
"

# Step 2: AST → IR
.venv/bin/python tools/ast_to_ir.py docs/specs/<ctx>/<ctx>.ast.json docs/specs/<ctx>/<ctx>.ir.json

# Step 3: IR → Manifest
.venv/bin/python tools/ir_to_manifest.py docs/specs/<ctx>/<ctx>.ir.json docs/specs/<ctx>/<ctx>.manifest.json

# Step 4: Manifest → Code
.venv/bin/python tools/codegen/gen.py docs/specs/<ctx>/<ctx>.manifest.json

Note: For the shared context, the files are named kernel.sea, kernel.sds.yaml, etc.

Creating a New Bounded Context

  1. Use Nx generator: nx g @workspace/scaffolding:bounded-context
  2. Create .sds.yaml in docs/specs/<context>/
  3. Run just pipeline <context>
  4. Run just gap-report <context> and just last-mile <context>

CI Sync Workflow

"Generated outputs are out of sync"

just pipeline <context>
git add docs/specs/<context>/*.ast.json docs/specs/<context>/*.ir.json \
  docs/specs/<context>/*.manifest.json libs/<context>/**/src/gen/

If libs/<context>/**/src/gen/ changed, also add/update a non-generated semantic fixture file: docs/specs/<context>/fixtures/semantic/*.fixture.yaml

"Generated code changed, but no semantic fixtures changed"

Add or update a non-generated fixture file, for example: docs/specs/<context>/fixtures/semantic/<context>-gen-surface.fixture.yaml

Do not hand-edit <context>.semantic.fixture.yaml because it is generator-managed.

  1. Add new scenarios with required fields:
- id: "ISSUE-CONTEXT-HANDLER-001"
  title: "Handler does something specific"
  classification: happy_path  # or: edge_case, error_case, feature, security
  requirement_ref: "SDS-XXX:CMD-YYY-001"
  cycle_ref: "374"
  given: "Precondition state"
  when: "Action performed"
  then: "Expected outcome"
  1. Add to expected_invariants if the scenario defines system invariants
  2. Add to traceability section linking to issue/PRD/SDS/ADR
  3. Validate context first: just semantic-fixtures-ctx <context>
  4. Optionally validate all fixtures: just semantic-fixtures

"Generated code changed, but no upstream specs changed"

This is blocked by scripts/ci/spec_and_fixtures_guard.sh.

  1. If generated diffs were accidental drift, revert generated outputs.
  2. If generated diffs are intentional, add/update upstream spec evidence under docs/specs/**.
  3. Add/update semantic fixtures under docs/specs/<context>/fixtures/semantic/**.
  4. Re-run:
GITHUB_BASE_REF=<base-branch> scripts/ci/spec_and_fixtures_guard.sh

"Debt markers found in generated code"

Per technical-debt.instructions.md, debt markers are absolutely prohibited. Fix the generator template so it produces complete code (no stubs). If blocked, ask the user for guidance — do not introduce placeholders.

Commit Checklist

Before pushing, verify:

  • No hand-edits to **/src/gen/** or other generated zones
  • just pipeline <context> ran after spec changes
  • just gap-report <context> shows no unresolved gaps (or just last-mile was run)
  • just regen-check <manifest> passes (determinism)
  • just semantic-check <context> passes (governance)
  • If libs/**/src/gen/** changed, add/update docs/specs/**/fixtures/semantic/*.fixture.yaml in the affected context
  • GITHUB_BASE_REF=<base-branch> scripts/ci/spec_and_fixtures_guard.sh passes locally
  • just ci passes (full CI, not ci-quick)
  • git status --porcelain shows only intended changes

Related Skills

Skills Info
Original Name:sea-generator-firstAuthor:godspeedai