Reference / Schema Specification
Defines the structured YAML format for Software Design Specifications (SDS) that enables deterministic translation to SEA-DSL while maintaining human readability. This format eliminates prose ambiguity and enables agents to author specifications that can be mechanically compiled into semantic models.
sds.schema.json before any downstream processing1
specs/<context>/<context>.sds.yaml
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
sds:
id: SDS-001
title: Orders Context SDS
bounded_context: orders
satisfies_prds: [PRD-010]
satisfies_adrs: [ADR-001]
version: 1.0.0
status: draft # draft|review|approved
owners: ["team@example.com"]
created: 2025-12-23
glossary:
- term: Order
type: entity
description: Customer purchase request tracked through fulfillment.
- term: PlaceOrder
type: command
description: Request to create an order.
- term: OrderPlaced
type: event
description: Emitted when an order is successfully placed.
types:
value_objects:
- name: OrderId
underlying: uuid
- name: Money
fields:
amount: decimal
currency: string # ISO-4217
enums:
- name: OrderStatus
values: [PENDING, CONFIRMED, CANCELLED]
domain:
aggregates:
- name: Order
root: true
identity: OrderId
fields:
id: OrderId
status: OrderStatus
total: Money
customer_id: uuid
invariants: [POL-001]
policies:
- id: POL-001
name: TotalMustBePositive
applies_to: Order
satisfies_reqs: [REQ-001]
rule:
op: ">"
left: { ref: "Order.total.amount" }
right: { const: 0 }
error:
code: ORDER_TOTAL_INVALID
message: "Order total must be > 0"
cqrs:
commands:
- id: CMD-001
name: PlaceOrder
satisfies_reqs: [REQ-001]
input:
customer_id: uuid
total: Money
transactional: true
idempotency:
enabled: true
key: header:X-Idempotency-Key
touches:
aggregates: [Order]
preconditions: [POL-001]
emits: [EVT-001]
queries:
- id: QRY-001
name: GetOrder
satisfies_reqs: [REQ-002]
input:
order_id: OrderId
output:
order_id: OrderId
status: OrderStatus
total: Money
consistency: strong # strong|eventual
read_model:
source: primary_db # primary_db|read_replica|projection
table: orders
events:
- id: EVT-001
name: OrderPlaced
satisfies_reqs: [REQ-001]
payload:
order_id: OrderId
customer_id: uuid
total: Money
publish:
topic: orders.order_placed.v1
delivery: at_least_once # at_least_once|exactly_once
outbox: required # required|optional
ports:
- id: PORT-001
name: OrderRepository
direction: outbound
used_by: [CMD-001, CMD-002]
methods:
- name: get
args: [order_id: OrderId]
returns: Order
- name: save
args: [order: Order]
returns: void
- id: PORT-002
name: UnitOfWork
direction: outbound
used_by: [CMD-001, CMD-002]
semantics:
transaction_per_handler: true
- id: PORT-003
name: MessageBus
direction: outbound
used_by: [EVT-001, EVT-002]
methods:
- name: publish
args: [event: Event]
returns: void
runtime:
api:
framework: fastapi
persistence:
kind: postgres
orm: sqlalchemy
migrations: alembic
messaging:
kind: kafka # kafka|nats|inmemory
outbox:
enabled: true
table: outbox_events
di:
bindings:
- port: OrderRepository
adapter: SqlAlchemyOrderRepository
lifetime: request
- port: UnitOfWork
adapter: SqlAlchemyUnitOfWork
lifetime: request
- port: MessageBus
adapter: KafkaMessageBus
lifetime: singleton
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | ✅ | Unique SDS identifier (pattern: ^SDS-\d{3,}$) |
title |
string | ✅ | Human-readable title |
bounded_context |
string | ✅ | DDD bounded context name |
satisfies_prds |
array | ✅ | PRD IDs this SDS implements |
satisfies_adrs |
array | ❌ | ADR IDs this SDS follows |
version |
string | ✅ | SDS version (semver) |
status |
enum | ✅ | draft, review, approved |
Prevents naming drift (a common source of agent hallucination):
| Field | Type | Required | Description |
|---|---|---|---|
term |
string | ✅ | Domain term |
type |
enum | ✅ | entity, vo, command, query, event, service |
description |
string | ✅ | Definition |
| Section | Description |
|---|---|
value_objects |
Immutable objects with underlying type or fields |
enums |
Enumeration types with allowed values |
| Field | Type | Description |
|---|---|---|
aggregates[].name |
string | Aggregate root name |
aggregates[].root |
boolean | Is aggregate root? |
aggregates[].identity |
string | Identity type |
aggregates[].fields |
object | Field name → type mappings |
aggregates[].invariants |
array | Policy IDs enforced on this aggregate |
| Field | Type | Description |
|---|---|---|
id |
string | Policy ID (pattern: ^POL-\d{3,}$) |
name |
string | Policy name |
applies_to |
string | Target entity/aggregate |
satisfies_reqs |
array | REQ-IDs from PRD |
rule |
object | Expression tree (structured, not prose) |
error.code |
string | Error code for violations |
error.message |
string | Human-readable error message |
| Field | Type | Description |
|---|---|---|
id |
string | Command ID (pattern: ^CMD-\d{3,}$) |
name |
string | Command name |
satisfies_reqs |
array | REQ-IDs |
input |
object | Input field → type mappings |
transactional |
boolean | Requires transaction? |
idempotency.enabled |
boolean | Idempotency support |
idempotency.key |
string | Idempotency key source |
touches.aggregates |
array | Aggregates modified |
preconditions |
array | Policy IDs checked before execution |
emits |
array | Event IDs published on success |
| Field | Type | Description |
|---|---|---|
id |
string | Query ID (pattern: ^QRY-\d{3,}$) |
name |
string | Query name |
input |
object | Input field → type mappings |
output |
object | Output field → type mappings |
consistency |
enum | strong or eventual |
read_model.source |
enum | primary_db, read_replica, projection |
read_model.table |
string | Table/view name |
| Field | Type | Description |
|---|---|---|
id |
string | Event ID (pattern: ^EVT-\d{3,}$) |
name |
string | Event name |
payload |
object | Payload field → type mappings |
publish.topic |
string | Topic/stream name |
publish.delivery |
enum | at_least_once, exactly_once |
publish.outbox |
enum | required or optional |
| Field | Type | Description |
|---|---|---|
id |
string | Port ID (pattern: ^PORT-\d{3,}$) |
name |
string | Port interface name |
direction |
enum | inbound or outbound |
used_by |
array | CMD/QRY/EVT IDs using this port |
methods |
array | Method signatures |
semantics |
object | Additional semantics (e.g., transaction behavior) |
Implementation/technology selections:
| Section | Purpose |
|---|---|
api.framework |
API framework (fastapi, express, etc.) |
persistence.kind |
Database type |
persistence.orm |
ORM/query builder |
messaging.kind |
Message broker |
messaging.outbox |
Outbox configuration |
| Field | Type | Description |
|---|---|---|
bindings[].port |
string | Port name |
bindings[].adapter |
string | Concrete adapter class |
bindings[].lifetime |
enum | singleton, request, transient |
The agent generates SEA-DSL strictly from SDS blocks:
| SDS Section | SEA-DSL Construct |
|---|---|
domain.aggregates |
Entity declaration |
types.value_objects |
Resource declaration |
policies |
Policy with expression tree |
cqrs.commands |
Resource (payload) + Flow with @cqrs { "kind": "command" } |
cqrs.queries |
Resource (payload) + Flow with @cqrs { "kind": "query" } |
events |
Resource (payload) + Flow with @cqrs { "kind": "event" } |
1
2
3
4
SDS YAML
↓ YAML → JSON conversion
↓ JSON Schema validation (sds.schema.json)
↓ [PASS/FAIL]
1
python tools/validate_sds.py specs/orders/orders.sds.yaml tools/schemas/sds.schema.json
| Format | Readability | Nesting | Comments | Verdict |
|---|---|---|---|---|
| YAML | ✅ Excellent | ✅ Native | ✅ Supported | Best for SDS |
| JSON | ❌ Verbose | ✅ Native | ❌ No comments | Best for manifest |
| TOML | ✅ Good | ❌ Awkward | ✅ Supported | Best for flat config |