Orient yourself first
npm run crm -- app inspect --json
Read valid, then problems[], then limitations[], in that order. Every problem is fixed or reported before anything is built on top of it, and every limitation is a hard boundary on what you may claim. Then read packages[], capabilities[], resources[], actions[], policies[] and providers[]: that list is what exists. A capability absent from the report does not exist, whatever a record name, a label or a document suggests.
If the repository documents this skill names are absent, you are in a project built from this framework rather than in the framework itself. The inspection report is then the source of truth and those documents are optional background — do not guess at their contents, and do not assume a path exists because this skill names it.
modules[] is where you check whether the record you are about to create already exists, which package owns it, its checked-in revision and its declared fields — read it before writing a manifest, not after.
Preferred path — module factory (manifest-driven):
- Background, where they exist:
ARCHITECTURE.md, DECISIONS.md, docs/MODULE_MANIFEST.md
and docs/MODULE_FACTORY.md. The commands in the steps below carry the contract
themselves — module validate refuses a manifest these documents would have
refused — so read them for the reasoning, and proceed without them if they are
not in this project.
- Write a manifest (see
examples/modules/partner.module.json); validate it:
npm run crm -- module validate <manifest.json>.
- Inspect the deterministic plan (always read-only):
npm run crm -- module plan <manifest.json>.
- Generate the runnable module (dry-run first, then explicit apply):
npm run crm -- module create <manifest.json> then --apply.
Apply writes service, migration, module definition, tests and registers the
module automatically — no manual MIGRATIONS or create-app edits. The module
is then served at /api/modules/<name>/…, discoverable via GET /api/schema
(generatedModules), usable via client.module('<name>') in the SDK, and
shown automatically in the Admin under "Generated modules" (list/create/
detail/edit, no page code — see docs/ADMIN.md).
- Reference fields (many-to-one to another generated module) are supported:
{"type":"reference","references":"<target-table>"}. Apply the target module
first; the generated service validates the target at runtime via the
application reference resolver (ADR-010) and the Admin renders a target
selector. Generated-to-core references are not supported yet.
- For a lifecycle step that is more than a field edit (qualify, close,
approve), do not hand-roll it in the service: define a record action
(
docs/ACTIONS.md, ADR-011). Mark the fields the action owns
"writable": "managed" in the manifest so generic CRUD cannot reach that
state, and write the managed fields from execute via ctx.managed. The
runtime supplies one atomic transaction, events released only after commit,
and an automatic trace; it does not deduplicate, so express idempotency in
data (a unique key), as in
examples/starters/b2b-lead-qualification/.
- Edit the generated service to add domain rules; keep validation, actor
context, audit and events on every mutation.
- Run
npm run verify.
Manual path (custom shapes the factory does not cover):
- Study one existing module under
packages/modules/.
- Add schema migration, module service, metadata and validation by hand.
- Expose mutations only through the service; never execute SQL from API or MCP handlers.
- Record actor context and audit on every mutation.
- Add API/MCP exposure only after the service contract is tested.
- Run
npm run verify and update docs.
Evolving a module that already exists (ADR-019)
- A generated module's schema can grow, but only additively and only with an explicit
"revision" bump — one step at a time. Edit the manifest, set "revision": <previous + 1>, and re-run module create … --apply; the factory appends one new migration and the next boot applies it.
- Supported: add an optional field, widen an enum's values, add or remove a non-unique index, and change
writable or default (a metadata evolution — the revision advances, the source is regenerated, no migration is emitted). Refused before any write: removing or renaming a field, changing a type, narrowing an enum, adding a required or unique field, changing unique, changing a reference target, renaming the table — and a rebuild while another table holds a foreign key into this one.
- Never edit
packages/modules/<name>/module.state.json. It is the checked-in source of truth for the next evolution, and a hand edit is refused by fingerprint and per-migration checksum.
- Never edit an applied migration. The create migration keeps its identity forever; changes are appended to
migrations[].
- Generated source at revision 2 with a database still at revision 1 is normal — the next boot catches up. Rolling the source back after a migration has applied is not supported; publish a forward change.
- Enum values are bounded: printable, at most 64 characters. They end up inside a SQL
CHECK and are re-emitted by every rebuild.
Full guide: docs/MODULE_EVOLUTION.md.
1---2name: create-crm-module3description: Create or extend an Accordo domain module. Use for new CRM objects, fields, service operations, module metadata, API exposure and tests. Do not use for cross-module business processes; use create-crm-workflow instead.4---56## Orient yourself first78```bash9npm run crm -- app inspect --json10```1112Read `valid`, then `problems[]`, then `limitations[]`, in that order. Every problem is fixed or reported before anything is built on top of it, and **every limitation is a hard boundary on what you may claim.** Then read `packages[]`, `capabilities[]`, `resources[]`, `actions[]`, `policies[]` and `providers[]`: that list is what exists. A capability absent from the report does not exist, whatever a record name, a label or a document suggests.1314If the repository documents this skill names are absent, you are in a project built from this framework rather than in the framework itself. The inspection report is then the source of truth and those documents are optional background — do not guess at their contents, and do not assume a path exists because this skill names it.1516`modules[]` is where you check whether the record you are about to create already exists, which package owns it, its checked-in `revision` and its declared fields — read it before writing a manifest, not after.1718Preferred path — module factory (manifest-driven):19201. Background, where they exist: `ARCHITECTURE.md`, `DECISIONS.md`, `docs/MODULE_MANIFEST.md`21 and `docs/MODULE_FACTORY.md`. The commands in the steps below carry the contract22 themselves — `module validate` refuses a manifest these documents would have23 refused — so read them for the reasoning, and proceed without them if they are24 not in this project.252. Write a manifest (see `examples/modules/partner.module.json`); validate it:26 `npm run crm -- module validate <manifest.json>`.273. Inspect the deterministic plan (always read-only):28 `npm run crm -- module plan <manifest.json>`.294. Generate the runnable module (dry-run first, then explicit apply):30 `npm run crm -- module create <manifest.json>` then `--apply`.31 Apply writes service, migration, module definition, tests and registers the32 module automatically — no manual MIGRATIONS or create-app edits. The module33 is then served at `/api/modules/<name>/…`, discoverable via `GET /api/schema`34 (`generatedModules`), usable via `client.module('<name>')` in the SDK, and35 shown automatically in the Admin under "Generated modules" (list/create/36 detail/edit, no page code — see `docs/ADMIN.md`).375. Reference fields (many-to-one to another generated module) are supported:38 `{"type":"reference","references":"<target-table>"}`. Apply the target module39 first; the generated service validates the target at runtime via the40 application reference resolver (ADR-010) and the Admin renders a target41 selector. Generated-to-core references are not supported yet.426. For a lifecycle step that is more than a field edit (qualify, close,43 approve), do **not** hand-roll it in the service: define a record action44 (`docs/ACTIONS.md`, ADR-011). Mark the fields the action owns45 `"writable": "managed"` in the manifest so generic CRUD cannot reach that46 state, and write the managed fields from `execute` via `ctx.managed`. The47 runtime supplies one atomic transaction, events released only after commit,48 and an automatic trace; it does not deduplicate, so express idempotency in49 data (a unique key), as in50 `examples/starters/b2b-lead-qualification/`.517. Edit the generated service to add domain rules; keep validation, actor52 context, audit and events on every mutation.538. Run `npm run verify`.5455Manual path (custom shapes the factory does not cover):56571. Study one existing module under `packages/modules/`.582. Add schema migration, module service, metadata and validation by hand.593. Expose mutations only through the service; never execute SQL from API or MCP handlers.604. Record actor context and audit on every mutation.615. Add API/MCP exposure only after the service contract is tested.626. Run `npm run verify` and update docs.6364## Evolving a module that already exists (ADR-019)65661. A generated module's schema can grow, but only additively and only with an explicit `"revision"` bump — one step at a time. Edit the manifest, set `"revision": <previous + 1>`, and re-run `module create … --apply`; the factory appends one new migration and the next boot applies it.672. **Supported:** add an optional field, widen an enum's values, add or remove a non-unique index, and change `writable` or `default` (a `metadata` evolution — the revision advances, the source is regenerated, no migration is emitted). **Refused before any write:** removing or renaming a field, changing a type, narrowing an enum, adding a required or unique field, changing `unique`, changing a reference target, **renaming the table** — and a rebuild while another table holds a foreign key into this one.683. Never edit `packages/modules/<name>/module.state.json`. It is the checked-in source of truth for the next evolution, and a hand edit is refused by fingerprint and per-migration checksum.694. Never edit an applied migration. The create migration keeps its identity forever; changes are appended to `migrations[]`.705. Generated source at revision 2 with a database still at revision 1 is normal — the next boot catches up. Rolling the source back after a migration has applied is not supported; publish a forward change.716. Enum values are bounded: printable, at most 64 characters. They end up inside a SQL `CHECK` and are re-emitted by every rebuild.7273Full guide: `docs/MODULE_EVOLUTION.md`.