finos / finos/architecture-as-code
CLI: `calm derive` — derive a draft architecture from behaviour specifications
- Dominant language
- TypeScript
- Stars
- 399
- Forks
- 138
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 38
Description
## Feature Proposal
### Target Project:
`cli` — with the derivation engine in shared code (`shared` or `calm-models`) so CALM Studio and MCP tooling can reuse it rather than reimplement it (the same relationship `generate` has with its pattern-instantiation logic).
### Description of Feature:
A new CLI command that derives a draft business-level architecture, flows, and linking decorators from a behaviour document — and can optionally derive *into* an existing draft architecture, linking new flows to existing nodes and relationships where they already exist.
```
calm derive
--behaviour Behaviour document to derive from (file path or URL) [required]
--architecture Existing draft architecture to derive into / link against
--output Output directory for generated documents [default: .]
--mapping Pre-resolved actor→node mappings as JSON; skips interactive prompts
--new-revision Copy an accepted input architecture into a draft revision and derive into the copy
--dry-run Print the derivation report without writing files
--schemas / --calmhub-url / --url-to-local-file-mapping / --verbose (standard loader options)
```
Outputs: an architecture document (new, or the amended input), one flow document per scenario, one behaviour decorator document carrying the scenario-step ↔ transition anchors, and a **derivation report**.
This is the mechanism that makes "behaviour specs drive the design" concrete: scenarios imply a cast and a choreography, and `derive` makes the implication explicit — the first draft of the logical architecture is *computed from* the behaviour specs, honestly stamped `status: draft` throughout.
### User Stories:
As a business analyst, I want to describe a process as scenarios and have a candidate architecture proposed from them, so that I can contribute to architecture without authoring nodes and relationships by hand.
As an architect, I want new behaviour specifications derived into my existing draft architecture, reusing the nodes and relationships that already exist, so that incremental business requirements extend the design instead of forking it.
As an architect, I want everything `derive` creates to be marked draft and everything pre-existing left untouched, so that generated proposals are clearly separated from committed design.
### Current Limitations:
There is no path from a behaviour document to architecture: the cast and interactions implied by scenarios must be hand-transcribed into nodes, relationships, and flows, including all identifier glue — error-prone, and heavy enough to deter business-first authoring entirely.
### Proposed Implementation:
**Mode 1 — greenfield (no `--architecture`):** extract the cast and choreography from the behaviour document; emit actor/system nodes, `interacts` relationships, flows with transition `unique-id`s, and the glue decorator — every construct stamped `status: draft`, document root included. Stable, deterministic ids (slugified actor names; flow ids derived from scenario ids) so output is diffable and re-derivable.
**Mode 2 — derive into an existing draft architecture (`--architecture`):**
1. **Match** each implied actor against existing nodes: exact name match, then declared aliases (a small `aliases` metadata convention on nodes), then unresolved actors go to the user.
2. **Resolve ambiguity** the way `generate` already does: interactive prompt per unresolved actor ("'Warehouse' — link to existing node `wms-core`, or create new draft node?"), with `--mapping mappings.json` to pre-answer for scripted runs. Accepted answers are written into the report in `--mapping`-compatible form, so an interactive first run produces the file that makes subsequent runs non-interactive.
3. **Reuse before create:** if a matched actor pair already has a relationship covering the interaction, the new flow's transition binds to it — one scenario step can ride an existing relationship while the next creates a draft one.
4. **Append-only draft:** every node and relationship `derive` adds carries `status: draft`; matched existing constructs are never modified.
**Promotion-guard interplay:** appending draft constructs to an *accepted* document would violate the `no-draft-constructs-in-accepted-document` rule, so `derive` refuses accepted input architectures with guidance. The legitimate "new behaviour over existing estate" case uses `--new-revision`, which copies the input, sets the root status to draft, and derives into the copy — promotion of the revision then goes back through the guard like anything else.
**Determinism — AI stays at the edge:** `derive` is a deterministic transformation, not an LLM call. Behaviour-document steps optionally carry structured participants (`source-actor` / `destination-actor`), filled in at authoring time (the calm-ai capture skill is having that conversation anyway). Steps without annotations fall back to exact-name matching against the document's actor vocabulary; anything unresolvable is listed in the report as a gap, never guessed.
**Re-derivation:** behaviour documents evolve, so `derive` is safe to run again:
- **Provenance metadata** on every derived construct (`derived-from: /`). On re-run, existing derived constructs are updated in place, new scenarios produce new constructs, and constructs whose source scenario has vanished are flagged as **orphans** in the report — flagged, not deleted, since an architect may have refined them since.
- **Stable id generation** — re-derive never churns ids, so flows, decorator anchors, and architect work layered on top survive.
**The derivation report:** printed always, written alongside the outputs, and the entire output of `--dry-run`: actors matched (and to what), constructs created, relationships reused, ambiguities resolved (and how), annotation gaps, orphans. This is the artefact the BA and architect discuss — the architecture diff in business language.
**Dependencies:** the lifecycle-status schema change (#2620), finos/calm-schema#19's transition `unique-id`, and the behaviour document type (#2621). All draft `2026-03` — this command develops against the drafts and doubles as their integration test before any release.
### Alternatives Considered:
- **LLM-based extraction in the CLI** — rejected: non-deterministic, requires network/keys, untestable. Structured step participants put the interpretation where a human is in the loop.
- **Generation without provenance** — rejected: re-running would duplicate constructs or destroy architect refinements; provenance + stable ids make derive idempotent.
- **Silently demoting accepted architectures to draft** — rejected in favour of explicit `--new-revision`; derive must never change the commitment status of someone's approved architecture as a side effect.
### Testing Strategy:
- Unit tests on the shared engine: extraction, matching precedence (exact → alias → prompt), reuse-before-create, append-only invariants, provenance, orphan detection, id stability across re-runs.
- CLI e2e tests following the existing `cli.e2e.spec.ts` pattern: greenfield, link mode with `--mapping`, accepted-input refusal, `--new-revision`, `--dry-run`.
- Fixture set: behaviour documents at varying annotation completeness; draft and accepted target architectures.
### Documentation Requirements:
- CLI reference entry for `derive` (help text framing both directions: "derive a draft logical architecture from behaviour specifications, or link behaviour into an existing draft architecture").
- An end-to-end tutorial covering the journey: capture scenarios → derive → refine → promote.
### Implementation Checklist:
- [ ] Design reviewed and approved
- [ ] Implementation completed
- [ ] Tests written and passing
- [ ] Documentation updated
- [ ] Relevant workflows updated (if needed)
- [ ] Performance impact assessed
### Additional Context:
Part of the behaviour-driven architecture work — see the tracking issue finos/architecture-as-code#2627. The engine should live in shared code from day one: CALM Studio's "propose architecture" action and the MCP tooling call the same engine.
Contributor guide
Assessment
This issue has not been assessed yet.