Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
3.8 KiB
Phase 2 — Resource model (entities → resources / types)
Turn the app description into a list of entities, their relationships, and the actions on them. This is the second and last typed phase — the user types a short entity list in 2a, then one click in 2b locks the shape.
2a — Ask for entities + relationships (typed)
Emit a regular message (NOT AskUserQuestion):
List the core entities (one per line) with an optional
owns→arrow for relationships. Example:User Invoice owns→ InvoiceItem Customer owns→ Invoice Tag Invoice many-to-many→ TagKeep it to ≤10 entities. Anything beyond core can be added after launch.
Store the parsed list as RESOURCES. Each entry is
{name, owns: [child...], many_to_many: [peer...]}. If parsing fails,
re-ask with the exact syntax rules shown above.
2b — Shape click (AskUserQuestion, single-select)
Reference: _blocks/api-rest-conventions.md (REST resources),
_blocks/api-graphql.md (types + connections).
{
"questions": [
{
"question": "How should the resources surface?",
"header": "Shape",
"multiSelect": false,
"options": [
{"label": "Flat REST (one resource per entity, ≤2 levels nesting)",
"description": "`/invoices`, `/invoices/{id}/items`. Deeper nesting flattened via query filters. Default for REST."},
{"label": "REST + sub-resources for every owns→ relation",
"description": "`/customers/{id}/invoices`, `/invoices/{id}/items`. Readable, curl-friendly; nesting budget 2 levels."},
{"label": "GraphQL types + Relay Connections",
"description": "Each entity → `type Foo { ... }`, each list → `FooConnection` with cursor pagination. See api-graphql.md"},
{"label": "GraphQL federation (subgraph per entity cluster)",
"description": "Apollo Federation 2 @key directives. ONLY pick when you truly have multiple teams / subgraphs."},
{"label": "Mixed: REST for public CRUD, GraphQL for dashboards",
"description": "Record both — this skill will generate primary surface; rerun for secondary."}
]
}
]
}
Store as SHAPE. Gate on STYLE from Phase 1:
STYLE = REST→ accept Flat REST or sub-resource REST; reject GraphQL options (re-ask).STYLE = GraphQL→ accept GraphQL types or federation.STYLE = tRPC / gRPC→ SHAPE defaults to "flat" (procedures per entity); skip the click, recordSHAPE = flat-procedures.STYLE = Hybrid→ emit a warning that both shapes will be skeleton'd in Phase 3.
2c — Emit resource-to-action matrix (inline, no AskUserQuestion)
Print a table the user can tweak before Phase 3 generates the contract. Example for a notes + tags API:
| Entity | Create | Read | Update | Delete | List | Search |
|---------------|:------:|:----:|:------:|:------:|:----:|:------:|
| User | - | ✓ | ✓ | - | ✓ | ✓ |
| Note | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Tag | ✓ | ✓ | - | ✓ | ✓ | - |
| NoteTag (m2m) | ✓ | - | - | ✓ | - | - |
- Rows = entries from
RESOURCES. - Columns = CRUD + List + Search (drop columns that don't apply per entity).
- Cells =
✓(endpoint exists) /-(intentionally absent). - Admin-only actions marked
admin✓.
User ackowledges the table (no click — implicit); Phase 3 uses it as input.
Verify-criterion
RESOURCEShas ≥1 entry; parsed shape{name, owns, many_to_many}valid.SHAPEis compatible withSTYLE(gate above).- Resource-to-action matrix printed with every entity as a row.
- Non-trivial m2m relations surfaced as explicit join entities OR GraphQL edge types — no implicit joins hidden in handlers.