Software Engineering Guide for SEA-Forge™
The spec-first, generator-driven workflow for the SEA™ monorepo.
This guide explains the actual development workflow for this repository—every step is grounded in the real tooling and configuration.
SEA-DSL Language Reference:
- docs/reference/sea_dsl_language_idioms.yml
- docs/reference/sea_dsl_language_reference.yml
- docs/reference/sea_dsl_language_tool_use.yml
- docs/reference/ast-v3.schema.json
Prerequisites
| Requirement |
How to Check |
Install/Fix |
| Node.js (via mise) |
node --version |
mise install |
| pnpm 10.x |
pnpm --version |
corepack enable |
| Python 3.13+ |
python3 --version |
mise install |
| Docker |
docker --version |
Install Docker Desktop |
| just |
just --version |
Install via cargo or mise |
Quick setup:
1
2
| just setup # Installs Node + Python deps, creates .venv
just doctor # Validates environment health
|
Repository Structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| SEA™/
├── apps/ # Application shells (minimal, mostly placeholder)
├── libs/
│ ├── sea/ # Core SEA™ bounded context
│ │ ├── domain/ # Domain entities, value objects
│ │ └── ports/ # Port interfaces (hexagonal)
│ └── shared/ # Cross-cutting libraries
│ ├── contracts/ # API/event schemas (Zod)
│ ├── config/ # Configuration validation
│ ├── feature-flags/ # OpenFeature + Flipt integration
│ ├── observability/ # OpenTelemetry instrumentation
│ └── testing/ # Test utilities and fakes
├── docs/
│ ├── specs/ # ⭐ All specifications live here
│ │ ├── shared/ # Shared ADRs, PRDs, SDS templates
│ │ ├── semantic-core/ # SEA™ DSL, Knowledge Graph specs
│ │ ├── cognitive-extension/ # AI agents, CADSL specs
│ │ ├── architectural-governance/ # CALM, compliance specs
│ │ └── developer-tooling/ # Flow linter, scaffolder specs
│ ├── howto/ # This guide and others
│ ├── playbooks/ # SOP documents (ENGINEERING.SOP.md, etc.)
│ └── reference/ # SEA-DSL language references
├── generators/ # Nx generators (sea:bounded-context, etc.)
├── tools/
│ ├── schemas/ # JSON schemas for validation
│ │ ├── ast-v3.schema.json
│ │ ├── sds.schema.json
│ │ ├── sea_ir.schema.json
│ │ └── manifest.schema.json
│ ├── ast_to_ir.py # AST → IR compiler
│ ├── ir_to_manifest.py # IR → Manifest compiler
│ ├── validate_sds.py # SDS schema validation
│ ├── regen_check.py # Determinism verification
│ ├── flow_lint.py # Flow annotation linter
│ └── sea_new_context.py # Context scaffolding script
├── infra/ # Docker Compose, Flipt config, OTel
├── schemas/ # Additional JSON schemas for contracts
└── justfile # All canonical commands
|
Core Principles
1. Specs Are Source of Truth
Never handwrite runtime code. Runtime code is generated from specs/SEA™/manifest via generators.
All application logic originates from:
- ADRs → Architectural decisions and constraints
- PRDs → Requirements (with EARS notation)
- SDS (YAML) → Machine-readable design specifications
- SEA-DSL → Domain model and flows
2. Allowed Edits Only
Per AGENTS.md, agents and humans may only modify:
| Path |
Purpose |
docs/specs/** |
ADR, PRD, SDS, SEA™ files |
.github/** |
Copilot customization |
tools/** |
Compilers, linters, generators |
.vscode/**, .githooks/** |
IDE/workflow config |
**/src/gen/** |
Generated output (read-only to humans) |
3. Just-First Workflow
All commands go through just. Discover available commands with:
1
2
| just # Shows all available recipes
just --list # Same as above
|
4. Agent Workflows
AI agents can use slash commands for common tasks:
| Command |
Purpose |
/spec |
Create new ADR, PRD, SDS, or SEA-DSL spec |
/feature |
Implement feature end-to-end from spec to code |
/cycle |
Execute a TDD cycle using worktrees |
/debug |
Systematic debugging with observability |
/review |
Review PR against spec-first standards |
/migrate-plan |
Migrate old plan to current template |
Workflows are defined in .agent/workflows/. Example:
1
2
3
| /spec adr 035 event-sourcing-strategy
/feature docs/plans/15_OrderManagement.plan.md
/cycle start 9 1 A order-entity
|
The Spec-to-Code Pipeline
Step 0: Pre-Flight Checks (Critical)
Lesson Learned: Infrastructure issues commonly derail implementation. Always verify before coding.
1
2
3
4
5
6
7
8
9
| # 1. Verify generators compile and list them
just generator-check
# 2. Check for SEA-DSL annotation compliance
just flow-lint
# 3. Ensure dependencies are current
just setup
just doctor
|
Fallback (if just recipes aren’t available):
1
2
| pnpm nx run generators:build
pnpm install
|
Common Generator Issues:
- If generators fail to build, check
generators/*/generator.ts for TypeScript errors
- Use literal union types (
'http' | 'postgres') not string for narrowed parameters
- Ensure
generators/tsconfig.json has "types": ["node"]
Step 1: Create a Bounded Context
1
2
3
4
5
6
7
8
| # Scaffold a new bounded context (preferred)
just generator-bc orders
# Or with explicit scope and language
just generator-bc orders sea typescript
# Fallback: Direct Nx invocation
pnpm nx g @sea/generators:bounded-context orders --scope=sea
|
This creates the hexagonal architecture structure in libs/orders/.
Post-Generator Checklist:
Step 2: Write the ADR
The ADR documents decisions, not requirements:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # ADR-XXX: Orders Bounded Context
## Context
What problem this context solves.
## Decision
- Use DDD + Hexagonal Architecture
- Use CQRS with flow annotations
- Use SEA™ pipeline for code generation
- Enforce module boundaries via Nx
## Constraints
- MUST use Nx generators
- MUST generate all runtime code from manifests
- MUST pass determinism checks
## Consequences
Increased file count, requires discipline, but guarantees consistency.
|
Step 3: Write the PRD
Requirements in EARS notation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # PRD-XXX: Orders Domain
Satisfies: ADR-XXX
## Requirements
### REQ-001 (functional)
When a customer checks out, the system shall create an order.
### REQ-002 (nonfunctional)
The API shall respond within 200ms P95 for GetOrder.
### REQ-003 (constraint)
The system must publish OrderPlaced events at-least-once.
|
Step 4: Write the SDS (YAML)
The machine-readable design spec:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # orders.sds.yaml
metadata:
namespace: orders
satisfies:
- PRD-XXX
entities:
Order:
properties:
- name: orderId
type: UUID
required: true
- name: status
type: enum[pending, confirmed, shipped]
flows:
PlaceOrder:
type: command
input: PlaceOrderCommand
output: Order
emits: [OrderPlaced]
|
Validate it:
1
| just sds-validate docs/specs/orders/orders.sds.yaml
|
Step 5: Write the SEA-DSL
Create the domain model with flow annotations:
// orders.sea
namespace orders;
entity Order {
orderId: UUID;
status: OrderStatus;
}
enum OrderStatus { pending, confirmed, shipped }
resource PlaceOrderCommand {
customerId: UUID;
items: List<LineItem>;
}
event OrderPlaced {
orderId: UUID;
timestamp: DateTime;
}
/**
* @cqrs { "kind": "command" }
* @tx { "transactional": true }
* @idempotency { "enabled": true, "key": "customerId+items" }
*/
flow PlaceOrder(cmd: PlaceOrderCommand) -> Order {
// Flow logic here
}
Validate and parse:
1
2
| just sea-validate docs/specs/orders/orders.sea
just sea-parse docs/specs/orders/orders.sea
|
Step 6: Run the Full Pipeline
Individual steps:
1
2
3
4
5
6
7
8
9
10
11
| # Compile AST → IR
just ast-ir docs/specs/orders/orders.ast.json
# Compile IR → Manifest
just ir-manifest docs/specs/orders/orders.ir.json
# Generate code
just codegen docs/specs/orders/orders.manifest.json
# Verify determinism
just regen-check docs/specs/orders/orders.manifest.json
|
Or run the entire pipeline at once:
Or use Nx targets:
1
| just nx-run specs-orders all
|
Just Commands Reference
The justfile is the canonical command interface. Run just to see all commands.
🚀 Getting Started
1
2
3
| just setup # Install all dependencies
just doctor # Health check
just env-enter # Enter Devbox shell
|
🧪 Testing
1
2
3
4
5
6
7
8
9
| just test # Full test suite (specs + python + typescript)
just test-specs # Spec validation only
just test-python # Python tests via pytest
just test-ts # TypeScript tests via Vitest (affected)
just test-ts-project <name> # Test specific project
just test-ts-coverage # Tests with coverage
just test-e2e # E2E tests via Playwright
just test-e2e-headed # E2E with visible browser
just playwright-install # Install browser binaries
|
📋 Spec Validation & Linting
1
2
3
4
5
| just spec-guard # Full validation suite
just spec-check # Cross-check specs
just spec-check-strict # Strict mode
just spec-index # Generate spec index JSON
just flow-lint # Lint flow annotations
|
🔄 CI Mirror (Run CI Locally)
Run the same checks locally that GitHub Actions CI runs. Diagnose issues before pushing.
1
2
3
4
5
6
7
| just ci # Full CI check (lint + specs + tests + determinism)
just ci-quick # Fast check (lint + specs only)
just ci-lint # Lint affected projects
just ci-spec # Spec validation + flow lint
just ci-test # TypeScript + Python tests
just ci-determinism # Check repo clean after codegen
just pre-push # Same as ci-quick (for git hook)
|
Recommended workflow:
1
2
3
4
5
| # Before pushing, run quick check
just ci-quick
# Before opening PR, run full check
just ci
|
⚙️ SEA™ Compiler Pipeline
1
2
3
4
5
6
7
8
| just sds-validate <file> # Validate SDS YAML
just sea-validate <file> # Validate SEA-DSL syntax
just sea-parse <file> # Parse SEA™ → AST JSON
just ast-ir <file> # Compile AST → IR
just ir-manifest <file> # Compile IR → Manifest
just codegen <manifest> # Generate code from manifest
just regen-check <manifest> # Verify determinism
just pipeline <ctx> # Run full pipeline for context
|
🔧 Nx Workspace Utilities
1
2
3
4
5
6
| just nx-show <project> # Show project details
just nx-graph # Visualize dependencies
just nx-run <project> <target> # Run target on project
just nx-affected <target> # Run on affected projects
just nx-all <target> # Run on all projects
just nx-list # List all projects
|
🏗️ Generators
1
2
3
4
5
| just generator-list # List available generators
just generator-bc <name> # Create bounded context
just generator-bc <name> <scope> <lang> # With options
just generator-adapter <name> <ctx> # Create adapter pair
just generator-api <name> <ctx> # Create API surface
|
🐳 Development Services
1
2
3
4
5
| just dev # Run spec guard (primary workflow)
just dev-up # Start PostgreSQL, Redis
just dev-down # Stop services
just dev-reset # Destroy volumes and reset
just dev-seed # Seed initial data
|
🚩 Feature Flags & Observability
1
2
3
4
| just flags-up # Start Flipt server
just flags-down # Stop Flipt
just otel-up # Start OTel Collector
just otel-down # Stop OTel Collector
|
� Walking Skeleton Runtime
Local development stack for RAG pipeline: embeddings, vector search, RDF, policy engine.
1
2
3
4
5
| just skeleton-up # Start pgvector + Oxigraph + OPA
just skeleton-down # Stop all skeleton services
just skeleton-reset # Destroy volumes and reset
just skeleton-tune # Auto-tune for your machine resources
just skeleton-status # Check health of all services
|
Services started by skeleton-up:
| Service |
Port |
Purpose |
| PostgreSQL + pgvector |
5432 |
Vector embeddings storage (384-dim) |
| Oxigraph |
7878 |
RDF triple store + SPARQL queries |
| OPA |
8181 |
Policy engine for governance |
Testing the skeleton:
1
2
| python3 tests/skeleton/test_walking_skeleton_runtime.py # E2E tests
python3 tests/skeleton/test_llm_integration.py # LLM tests (requires Ollama)
|
�🧹 Maintenance
1
2
| just clean # Clean build artifacts
just clean-all # Deep clean (removes node_modules, .venv)
|
🔐 Secrets
1
| just sops-rotate RECIPIENT='age1...' # Rotate encryption keys
|
🔄 TDD & Git Workflow
Full guide: TDD Cycles with Worktrees
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Cycle lifecycle (worktree-first)
just cycle-start <phase> <cycle> <agent> <slug> # Create branch + worktree
just cycle-complete <phase> <cycle> <agent> # Push, prepare for PR
just cycle-worktree-remove <phase> <cycle> <agent> # Remove worktree
# Worktree management
just worktrees # List active worktrees
just worktrees-status # Show merge status of each
just worktrees-clean # Remove merged worktrees
just worktrees-clean-all # Remove ALL worktrees (nuclear)
# Branch promotions
just promote-stage # Promote dev → stage
just promote-main # Promote stage → main
just release <ver> # Create release tag
just hotfix-forward # Forward-merge hotfix
|
Flow Annotation Contract
Every Flow in SEA-DSL must include CQRS annotation:
/**
* @cqrs { "kind": "command" | "query" | "event" }
*/
Recommended additional annotations:
| Annotation |
When to Use |
Example |
@tx |
Transactional commands |
@tx { "transactional": true } |
@idempotency |
Idempotent commands |
@idempotency { "enabled": true, "key": "orderId" } |
@outbox |
Event publishing |
@outbox { "mode": "required" } |
@read_model |
Query projections |
@read_model { "name": "OrderSummary" } |
Hard rule: Use nested JSON inside annotations (no dotted keys).
CI/CD Gates
Gate A: Allowed File Changes
PRs fail if changes touch files outside allowed paths (see AGENTS.md).
Gate B: Schema Validation
Every artifact must pass schema validation:
- SDS →
sds.schema.json
- AST →
ast-v3.schema.json
- IR →
sea_ir.schema.json
- Manifest →
manifest.schema.json
Gate C: Determinism
1
2
| just regen-check docs/specs/<ctx>/<ctx>.manifest.json
git diff --exit-code # Must be clean
|
PR Checklist
Testing Harness
| Tool |
Purpose |
Command |
| Vitest |
Unit/integration tests (TS) |
just test-ts |
| pytest |
Python tests |
just test-python |
| Playwright |
E2E browser tests |
just test-e2e |
| Testcontainers |
Integration tests with real infra |
Via Vitest/pytest |
| MSW |
API mocking |
Import from @msw/server |
Running Tests
1
2
3
4
5
6
7
8
9
10
11
12
| # All affected TypeScript tests
just nx-affected test
# Specific project
just test-ts-project shared-contracts
# With coverage
just test-ts-coverage
# E2E (after installing browsers)
just playwright-install
just test-e2e
|
Where AI Agents Fit
GitHub Copilot and other agents are useful for:
- Drafting specs (ADR/PRD/SDS boilerplate)
- Writing SEA-DSL from design specs
- Updating generators and templates
- Writing Nx target configurations
Safety is maintained by:
- Schema validation at every step
- Determinism checks
- Allowed-files-only CI gates
- Flow annotation linting
Quick Reference Cards
New Feature Workflow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # 1. Create bounded context
just generator-bc orders
# 2. Write specs in docs/specs/orders/
# - orders.adr.md (decisions)
# - orders.prd.md (requirements)
# - orders.sds.yaml (design)
# - orders.sea (domain model)
# 3. Run the pipeline
just pipeline orders
# 4. Verify
just spec-guard
git diff --exit-code
|
Debugging Failures
| Error |
Likely Cause |
Fix |
| SDS validation fails |
YAML syntax or missing fields |
just sds-validate <file> shows errors |
| SEA™ parse fails |
Invalid DSL syntax |
just sea-validate <file> shows line/column |
| AST→IR fails |
Missing namespace or invalid refs |
Ensure metadata.namespace is set |
| Regen check fails |
Non-deterministic output |
Review generator templates |
| Generator build fails |
TypeScript type errors |
Use literal unions not string |
| Cannot find module |
Missing path mapping |
Add to tsconfig.base.json |
| Flow lint fails |
Missing @cqrs annotation |
Add annotations to all flows |
| Python import error |
Service not installed |
Run pip install -e . in service dir |
Generator Troubleshooting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # Symptom: "Cannot find generator 'sea:adapter'"
# Fix: Use just recipe (preferred) or correct Nx prefix
just generator-adapter myname myctx http
# Fallback: Direct Nx invocation
pnpm nx g @sea/generators:adapter myname --context=myctx --backend=http
# Symptom: Generator TypeScript errors
# Fix: Build generators first
just generator-build
# Fallback: Direct Nx build
pnpm nx run generators:build
# Symptom: Don't know what generators exist
just generator-list
# Common type fix - use literal unions:
# BAD: backend: string
# GOOD: backend: 'http' | 'postgres' | 'redis' | 'memory'
|
Polyglot Development (Python + TypeScript)
For bounded contexts requiring both languages (e.g., LLM providers):
Directory Structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| libs/<context>/
├── domain/
│ └── src/
│ ├── lib/types.ts # TypeScript domain types
│ └── gen/types.py # Python domain types
├── ports/
│ └── src/
│ ├── lib/*.port.ts # TypeScript port interfaces
│ └── gen/ports.py # Python port interfaces
└── adapters/
└── src/
└── lib/
├── fake.adapter.ts # Fake for testing
└── http.adapter.ts # HTTP client to Python service
services/<context>/
├── pyproject.toml # Python dependencies
├── Dockerfile # Container build
├── main.py # FastAPI entry point
└── src/
├── api/routes.py # HTTP endpoints
├── adapters/<name>.py # Real Python adapter
└── config/settings.py # Pydantic settings
|
Development Pattern
- Define domain types in both languages - keep them synchronized
- Python service exposes HTTP API (OpenAI-compatible for LLM)
- TypeScript adapter calls Python service via HTTP
- Fake adapter enables TS-only testing without Python running
Fake-First Testing
Lesson Learned: Create fakes before real adapters to enable parallel development.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // 1. Port interface
export interface LlmProviderPort {
completeChat(request: ChatRequest): Promise<ChatCompletion>;
}
// 2. Fake adapter (implements port, deterministic responses)
export class FakeLlmAdapter implements LlmProviderPort {
async completeChat(request: ChatRequest): Promise<ChatCompletion> {
return { id: `fake-${Date.now()}`, content: 'Echo: ' + request.messages[0]?.content };
}
}
// 3. Tests use fake (no external deps)
// 4. Real adapter implements same interface, calls Python service
|