create-restforge-skills 0.3.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@ description: >
10
10
  active for the codegen_*, designer_*, setup_*, runtime_* MCP tools and the
11
11
  @restforgejs/platform / @restforgejs/mcp-server packages. Defines the canonical
12
12
  operation order for the backend track (setup → schema → payload → codegen →
13
- runtime) and the frontend track (init → udf → validate → generate), the
13
+ runtime) and the frontend track (migrate RDF → udf → validate → generate), the
14
14
  grounding-first catalog rules, decision branches, and destructive-operation
15
15
  guardrails. Active whenever working on a RESTForge project, not only when the
16
16
  word "skill" is mentioned.
@@ -56,8 +56,10 @@ The platform exposes its capabilities as MCP tools grouped by domain: `health_*`
56
56
 
57
57
  Verify readiness before planning or producing anything:
58
58
 
59
- 1. **Are the RESTForge MCP tools present?** If `codegen_*` / `designer_*` are not
60
- in your available tools, the MCP server is **not active**. Stop and tell the
59
+ 1. **Are the RESTForge MCP tools present?** Look for `codegen_*` / `designer_*`,
60
+ including client-prefixed names such as `mcp__restforge__codegen_*`. If the
61
+ client supports deferred tool discovery, search for RESTForge tools first.
62
+ If they remain unavailable, the MCP server is **not active**. Stop and tell the
61
63
  user to register the RESTForge MCP server and restart the client. Do **not**
62
64
  finish the task by hand-reading the bundled `references/` — that bypasses the
63
65
  generator and yields slower, non-deterministic output.
@@ -146,6 +148,11 @@ earlier steps that already succeeded.
146
148
 
147
149
  8. codegen_dbschema_validate
148
150
  Validate SDF before any DDL is generated. Catch errors here, not at migrate.
151
+ File-only by default. With 'config' it also compares every model with the
152
+ database and gives one verdict per table: [OK], [DRIFT], or [ERROR] with
153
+ category table-missing or sdf-invalid. Exit code 1 in that mode is a
154
+ result (drift or error found), not a tool failure. SQLite is not
155
+ supported by the database mode.
149
156
  codegen_dbschema_models (optional) lists the models already defined in the
150
157
  SDF files with field count, primary key kind, indexes, uniques, relations.
151
158
 
@@ -166,19 +173,22 @@ earlier steps that already succeeded.
166
173
  Check the SELECT / WITH statement against the live database (EXPLAIN, no
167
174
  rows executed) BEFORE pasting it into the payload: syntax, column
168
175
  references, function existence, type compatibility, JOIN resolution.
169
- Needs a platform that provides the 'query validate' sub-command
170
- (confirmed present in 5.5.5).
171
176
 
172
177
  13. codegen_generate_payload
173
178
  Generate payload JSON from a table. Foundation for all subsequent
174
- codegen operations.
179
+ codegen operations. 'detail' (a detail table name) also writes the
180
+ masterDetail block, the detail query file, and the composite actions.
181
+ Re-running it on an existing payload keeps the customisations made to
182
+ generator-owned keys; commit payload/.meta/<name>.json together with the
183
+ payload (see Decision Points § RDF Payload).
175
184
 
176
185
  14. codegen_validate_payload
177
186
  Validate the payload before codegen. Catch errors here.
178
187
 
179
188
  15. codegen_diff_payload (when a payload exists and the DB schema has changed)
180
- → codegen_sync_payload (sync payload to the current DB state — non-breaking)
181
- → codegen_migrate_payload (when the payload has breaking changes)
189
+ → codegen_sync_payload (apply the schema drift to the payload)
190
+ 'expandFk' (with 'table') also writes query/<table>-join.sql so
191
+ datatablesQuery (and viewQuery) show columns of referenced tables.
182
192
 
183
193
  16a. codegen_create_endpoint (standard CRUD module)
184
194
  Leave 'database' UNSET unless the user named a database: the CLI then
@@ -186,16 +196,17 @@ earlier steps that already succeeded.
186
196
  MySQL/Oracle/SQLite project generates for its own dialect. 'config'
187
197
  selects that .env explicitly. createDemo (default true) writes the
188
198
  curl / Postman / Insomnia examples. force defaults to true — an existing
189
- module is overwritten and the previous version archived as .archive.NNN;
190
- force=false stops without writing anything when the module exists, which
191
- is the closest thing to a conflict dry run.
199
+ module is overwritten and the previous files are moved to
200
+ .restforge/archive/<run>/<original relative path> (the 5 most recent runs
201
+ are kept); force=false stops without writing anything when the module
202
+ exists, which is the closest thing to a conflict dry run.
192
203
  16b. codegen_get_dashboard_catalog
193
204
  → codegen_validate_dashboard_payload
194
205
  ── GATE ── structural check of a dashboard payload; writes nothing.
195
- Needs a platform NEWER than 5.5.5 ('dashboard create --validate-only').
196
- On an older platform the tool answers with an upgrade suggestion instead
197
- of a validation result — then let the generator itself validate, since it
198
- runs the same validator before it writes.
206
+ On a platform without 'dashboard create --validate-only' the tool
207
+ answers with an upgrade suggestion instead of a validation result — then
208
+ let the generator itself validate, since it runs the same validator
209
+ before it writes.
199
210
  → codegen_create_dashboard (analytic dashboard with SQL widgets)
200
211
  No database auto-detection here: the dashboard command uses 'database'
201
212
  when given and plain postgres otherwise, so pass it whenever the project
@@ -269,34 +280,47 @@ frontend can be defined and generated without the backend live.
269
280
 
270
281
  ```
271
282
  1. designer_list_plugins
272
- ── GROUNDING ── list available output plugins before initializing.
273
- Built-in: vanilla-js-basic (no auth), vanilla-js-auth (JWT auth).
283
+ ── GROUNDING ── list available output plugins before creating the UDF.
284
+ Built-in: vanilla-js-basic (no auth), vanilla-js-auth and
285
+ vanilla-js-custom (JWT auth + RBAC).
274
286
  → references/udf-catalog.md § Plugins
275
287
 
276
- 2. designer_init_project
277
- Scaffold a new frontend project from a plugin. Creates the project folder,
278
- the initial UDF payload (payload.json), and plugin assets.
288
+ 2a. codegen_migrate_payload ── PRIMARY ── when a backend RDF payload exists
289
+ Convert the RDF into a split UDF set in the output folder (default
290
+ frontend/payload/): app-config.json, pages/<pageId>.json, the aggregator
291
+ <appCode>.json, and snapshots in .meta/pages/. Run it once per RDF with
292
+ the same output folder to add pages to one app. It derives fields, types,
293
+ lookups, details[], status filters, and the date patterns from the
294
+ backend, so start here instead of writing pages by hand.
295
+ Needs a license and the backend config (like every codegen_* tool).
296
+ 2b. [hand-write the UDF] only when there is no RDF to migrate from
297
+ Ground every key with designer_get_udf_catalog first.
298
+ designer_init_project (optional) scaffold a project folder with the
299
+ assets of an auth-capable plugin (vanilla-js-auth / vanilla-js-custom).
300
+ It writes no UDF payload file.
279
301
 
280
302
  3. designer_get_udf_catalog
281
- ── GROUNDING ── call before defining or editing any UDF payload.
282
- Returns valid field types, page anatomy, features, data-source formats,
283
- and validation rules for the installed plugin version.
303
+ ── GROUNDING ── call before editing any UDF page.
304
+ Returns valid field types, enums, limits, and validation constants for
305
+ the installed designer version.
284
306
  → references/udf-catalog.md
285
307
 
286
- 4. [define / edit UDF payload JSON]
287
- Edit payload.json: appConfig, pages[], navigation[], homepage.
288
- One page entry = one CRUD page or one dashboard page.
308
+ 4. [edit the UDF pages]
309
+ Edit pages/<pageId>.json (labels, layout, features, workflowActions) and
310
+ the aggregator (navigation, homepage). One page entry = one CRUD page or
311
+ one dashboard page. Re-running migrate later merges RDF changes into
312
+ these files without losing the edits (Decision Points § Frontend UDF).
289
313
 
290
314
  5. designer_validate_payload
291
- ── GATE ── validate the UDF payload. Catches structural errors before
292
- generation. Run before preview or generate, every time.
315
+ ── GATE ── validate the UDF (the aggregator file). Catches structural
316
+ errors before generation. Run before preview or generate, every time.
293
317
 
294
318
  6. designer_preview_files
295
319
  Dry-run: list files that would be generated, without writing to disk.
296
320
  Use to verify scope before an overwrite.
297
321
 
298
322
  7. designer_generate
299
- Generate frontend HTML/JS/CSS from the UDF payload. Writes output files.
323
+ Generate frontend HTML/JS/CSS from the aggregator. Writes output files.
300
324
  The agent STOPS here — the user opens the output in a browser.
301
325
  ```
302
326
 
@@ -314,7 +338,8 @@ not serve or deploy).
314
338
 
315
339
  Licensing note: the Designer tools (`designer_preview_files`, `designer_generate`,
316
340
  etc.) do **not** require a RESTForge license, unlike the `codegen_*`, `runtime_*`,
317
- and `setup_validate_config` tools on the backend track.
341
+ and `setup_validate_config` tools. `codegen_migrate_payload` is a `codegen_*`
342
+ tool, so step 2a runs in the backend project folder.
318
343
 
319
344
  ---
320
345
 
@@ -407,6 +432,7 @@ definition content from memory.
407
432
  | Defining `fieldValidation` in an RDF payload | `codegen_get_field_validation_catalog` | references/field-validation.md |
408
433
  | Defining queries in an RDF payload | `codegen_get_query_declarative_catalog` | — |
409
434
  | Defining a dashboard payload | `codegen_get_dashboard_catalog` | — |
435
+ | Defining `/aggregate` joins or requests | — (no catalog tool yet) | references/rdf-advanced.md § Aggregate Config |
410
436
  | Defining UDF (frontend) | `designer_get_udf_catalog` | references/udf-catalog.md |
411
437
  | Listing available frontend plugins | `designer_list_plugins` | references/udf-catalog.md § Plugins |
412
438
  | Setting `db-connection.env` parameters | `setup_get_config_schema` | references/config-schema.md |
@@ -457,19 +483,41 @@ branch still obeys the Grounding-First Rules above.
457
483
  the SDF, and run `codegen_dbschema_validate`. The design shows presentation,
458
484
  not storage — do not turn every visible label into a column.
459
485
  → references/design-to-sdf.md
460
- - **DB exists with drift** → `codegen_dbschema_diff` to review, then
461
- `codegen_dbschema_apply`. Not `codegen_dbschema_migrate` — that is for empty
462
- DBs only.
486
+ - **"Is my schema valid and in sync with the database?"** →
487
+ `codegen_dbschema_validate` with `config` (optionally `table`): one verdict per
488
+ table, `[OK]`, `[DRIFT]`, or `[ERROR]` (`table-missing` → migrate/apply fixes
489
+ it; `sdf-invalid` → fix the file). Exit code 1 means drift or an error was
490
+ found, not that the tool failed. Not available for SQLite.
491
+ - **DB exists with drift** → `codegen_dbschema_diff` to review the per-column
492
+ differences, then `codegen_dbschema_apply`. Not `codegen_dbschema_migrate` —
493
+ that is for empty DBs only.
463
494
 
464
495
  ### RDF Payload
465
496
 
466
497
  - **No payload yet** → `codegen_generate_payload`.
467
498
  - **Payload exists, edit is API-layer only** (e.g. add/adjust `fieldValidation`,
468
499
  messages, or a query — no column added or dropped) → ground via the matching
469
- catalog, edit `payload.json`, run `codegen_validate_payload`, then regenerate
500
+ catalog, edit `payload/<name>.json`, run `codegen_validate_payload`, then regenerate
470
501
  with `codegen_create_endpoint`. No DB migration: the schema (SDF) is unchanged.
471
502
  - **Payload exists, DB schema changed** → `codegen_diff_payload` first, then
472
- `codegen_sync_payload` (non-breaking) or `codegen_migrate_payload` (breaking).
503
+ `codegen_sync_payload`. Turning the RDF into a frontend UDF is a separate
504
+ frontend step (Frontend Pipeline step 2a), not part of this branch.
505
+ - **Customisations survive regeneration.** `codegen_generate_payload` and
506
+ `codegen_sync_payload` keep edits made to generator-owned keys (`action`,
507
+ `fieldValidation`, inline SQL, `auditColumns`, the datatables query file).
508
+ A column deliberately removed from `fieldName` stays removed because generate
509
+ records the known columns in `payload/.meta/<name>.json`; commit that snapshot
510
+ with the payload and never edit it.
511
+ - **Show columns of a referenced table in the list** (e.g. `supplier_name` next
512
+ to `supplier_id`) → `codegen_sync_payload` with `table` and `expandFk`
513
+ (`"both"`, or `"datatables-only"` to leave a custom `viewQuery` alone). It
514
+ writes `query/<table>-join.sql` and points `datatablesQuery` (and `viewQuery`)
515
+ at it; `FK_AUTO_JOIN` picks LEFT or INNER JOIN. The display column per FK is
516
+ chosen automatically and is never the primary key. Use `fkColumns`
517
+ (`ref_table.column`, or `local_fk:ref_table.column`) to override it and
518
+ `expandFkSkip` to leave a relation out. When the CLI reports "No natural
519
+ display column found", **ask the user** which column to show or whether to
520
+ skip that relation — do not pick one yourself.
473
521
  - **Custom query needed** → ground via `codegen_get_query_declarative_catalog`,
474
522
  check the statement with `codegen_validate_sql` against the live database, then
475
523
  set `datatablesQuery`, `viewQuery`, or `exportQuery` in the payload. External
@@ -500,21 +548,36 @@ branch still obeys the Grounding-First Rules above.
500
548
  after the endpoints exist, and after `project_auth` when the project needs
501
549
  auth, so `client.auth` is included.
502
550
  - **Integration test for an existing endpoint** → `codegen_generate_test`.
503
- - **Workflow (status transitions)** → add `workflow` and `workflowActions` to the
504
- RDF payload; generates a `/change-status` endpoint automatically.
551
+ - **Every feature endpoint needs its `action` flag.** A feature block without
552
+ the matching flag in `action` produces no endpoint.
553
+ → references/rdf-advanced.md § The `action` Block
554
+ - **Workflow (status transitions)** → set `action.workflow: true` and add a
555
+ `workflow` block (`statusField`, `transitions` as a map `status → [targets]`,
556
+ optional `hooks` keyed by target status) to the RDF; generates
557
+ `/change-status`. The buttons are UDF `workflowActions` — a frontend key that
558
+ never goes into the RDF.
505
559
  → references/rdf-advanced.md § Workflow
506
- - **Master-detail (composite CRUD)** → add `details[]` to the RDF payload;
507
- generates `/create-composite`, `/update-composite`, `/read-composite`.
560
+ - **Master-detail (composite CRUD)** → run `codegen_generate_payload` with
561
+ `detail: "<detail table>"`. It writes the `masterDetail` block, the detail
562
+ query file, and `action.createComposite` / `updateComposite` /
563
+ `readComposite`; then fill `headerCalculations` and `calculated` formulas by
564
+ hand. Generates `/create-composite`, `/update-composite`, `/read-composite`.
508
565
  → references/rdf-advanced.md § Master-Detail
566
+ - **Summary numbers per resource** (count, sum, avg, min, max, optionally
567
+ grouped) → `action.aggregate: true`; the request body carries the operations,
568
+ and `aggregateConfig.joins` only whitelists JOINs. For charts or KPIs across
569
+ several tables, prefer a backend dashboard (`codegen_create_dashboard`).
570
+ → references/rdf-advanced.md § Aggregate Config
509
571
  - **Excel export** → `/export` works by default (falls back to
510
572
  `SELECT {fields} FROM tableName`); customise the columns/filter with
511
573
  `exportQuery` in the RDF payload. Tune `EXPORT_FILE_EXPIRY` / `EXPORT_CHUNK_SIZE`
512
574
  in config. Ground `exportQuery` via `codegen_get_query_declarative_catalog`.
513
575
  → references/rdf-advanced.md § Data Source Resolution
514
- - **Excel import (.xlsx)** → add `importConfig` (sheet, startRow, strategy,
515
- upsertKey, columns header→fieldName, optional lookup) to the RDF payload;
516
- generates `/import-preview` (validates, returns a diff) and `/import-commit`
517
- (applies). → references/rdf-advanced.md § Import Config
576
+ - **Excel import (.xlsx)** → set `action.import: true` and add `importConfig`
577
+ with `enabled: true` (`upsertKeys`, `upsertStrategy`, `requiredFields`,
578
+ optional `lookupFields`) to the RDF payload; generates `/import-upload`,
579
+ `/import-preview`, `/import-commit`, and `/import-status`.
580
+ → references/rdf-advanced.md § Import Config
518
581
  - Activate on an existing project: edit the payload to add `importConfig`
519
582
  (and/or `exportQuery`) → `codegen_validate_payload` → `codegen_create_endpoint`.
520
583
 
@@ -551,15 +614,38 @@ is `schemaPath` (CLI `--schema-path`, default `schema`).
551
614
  twice inserts the rows twice. Confirm with the user before pushing into a
552
615
  database that may already hold those rows.
553
616
 
617
+ ### Frontend UDF
618
+
619
+ - **A backend RDF exists** → `codegen_migrate_payload`; do not write the page by
620
+ hand. Run it once per RDF into the same output folder to build one app.
621
+ - **Re-running migrate** (RDF changed, or a page must pick up new columns) →
622
+ run it again **without** `overwrite`. Existing pages are merged: user edits
623
+ (labels, layout, removed fields, blocks) are kept and RDF changes to untouched
624
+ values are applied. Backend contract values (`apiPath`, `primaryKey`, `type`,
625
+ `required`, `maxlength`, `decimalPlaces`, `tableField`, lookup source, option
626
+ values) follow the RDF when both sides changed, with a warning. The merge uses
627
+ the snapshots in `<output>/.meta/pages/<pageId>.json`; commit them with the
628
+ pages and never edit them. The aggregator (`navigation`, `homepage`) and
629
+ `app-config.json` are merged too.
630
+ - **`overwrite: true`** recreates the page from the RDF and discards every
631
+ customisation (the old file goes to `.restforge/archive/`). Confirm with the
632
+ user before using it.
633
+ - **Date patterns** → `appConfig.dateFormat` / `dateTimeFormat` are rewritten
634
+ from the backend `DATEFORMAT` / `DATETIMEFORMAT` on every migrate. After the
635
+ backend changes them, re-run migrate and `designer_generate`; never edit the
636
+ frontend values to differ from the backend.
637
+
554
638
  ### Frontend page type
555
639
 
556
640
  - **Standard CRUD page** → `pageType: "crud"` (default) with `apiPath`,
557
641
  `primaryKey`, `displayField`, and `fields[]`.
558
- - **Dashboard page** → `pageType: "dashboard"` with `dataSources[]` and `rows[]`
559
- containing widget columns.
642
+ - **Dashboard page** → `pageType: "dashboard"` with a `dataSources` object
643
+ (`name → { url, method, body }`) and `rows[]` → `columns[]` → `widgets[]`.
560
644
  → references/udf-catalog.md § Dashboard Page
561
- - **Page with approval workflow** → add `workflow.statusField` and
562
- `workflowActions[]` to the page.
645
+ - **Page with approval workflow** → add `workflow` (`statusField` and
646
+ `transitions`, identical to the RDF) and `workflowActions[]` whose `actionId`
647
+ equals the target status. Add `fieldStates` to lock rows in final statuses.
648
+ → references/udf-catalog.md § Workflow Actions
563
649
 
564
650
  ### Frontend plugin choice
565
651
 
@@ -601,11 +687,15 @@ The following require explicit user confirmation before execution:
601
687
  and resource files of endpoints that no longer exist are left behind.
602
688
  - `setup_validate_config` with `autoCreateDb: true` — it runs CREATE DATABASE on
603
689
  the database server. The default call is read-only.
690
+ - `codegen_migrate_payload` with `overwrite: true` — existing UDF pages are
691
+ recreated and every customisation in them is discarded (the old files are
692
+ archived). Without `overwrite`, pages are merged and nothing is lost.
604
693
 
605
694
  `codegen_create_endpoint` and `codegen_create_dashboard` overwrite by default
606
- (`force` is true) but archive the previous version as `.archive.NNN` first, so
607
- they need a plain intent confirmation rather than a destructive-operation
608
- confirmation. Use `force: false` when the point is to find out whether the module
695
+ (`force` is true) but first move the previous files to
696
+ `.restforge/archive/<run>/<original relative path>` (the 5 most recent runs are
697
+ kept), so they need a plain intent confirmation rather than a
698
+ destructive-operation confirmation. Use `force: false` when the point is to find out whether the module
609
699
  already exists: the endpoint command then stops at its confirmation question
610
700
  without writing, and the dashboard command refuses with a clean error.
611
701
 
@@ -711,13 +801,14 @@ pass:
711
801
 
712
802
  ### Tools that depend on the installed platform version
713
803
 
714
- Two tools wrap CLI sub-commands that older platforms do not have. Both fail in a
715
- recognisable way, so treat the failure as a version answer, not a payload problem:
804
+ Two tools wrap CLI sub-commands that old platform releases do not have. Current
805
+ releases have both. On an old project they fail in a recognisable way, so treat
806
+ the failure as a version answer, not a payload problem:
716
807
 
717
808
  | Tool | Requirement | Symptom on an older platform |
718
809
  |---|---|---|
719
- | `codegen_validate_sql` | a platform providing `query validate` (confirmed present in 5.5.5; the exact minimum is not established) | `Unknown command: query` |
720
- | `codegen_validate_dashboard_payload` | a platform providing `dashboard create --validate-only`, which exists only after 5.5.5 | `Unknown flag: --validate-only`; the tool reports it as an upgrade requirement |
810
+ | `codegen_validate_sql` | a platform providing `query validate` | `Unknown command: query` |
811
+ | `codegen_validate_dashboard_payload` | a platform providing `dashboard create --validate-only` | `Unknown flag: --validate-only`; the tool reports it as an upgrade requirement |
721
812
 
722
813
  When `codegen_validate_dashboard_payload` is unavailable, the fallback is
723
814
  `codegen_create_dashboard` itself — it runs the same validator before writing.
@@ -734,6 +825,9 @@ When `codegen_validate_dashboard_payload` is unavailable, the fallback is
734
825
  | "Widget uses undeclared placeholder" | `:paramName` in SQL not in `params` | Add the entry to `params` in the dashboard payload |
735
826
  | "tableName and widgets conflict" | Payload contains both | Dashboard uses `widgets`; CRUD uses `tableName` — remove the wrong one |
736
827
  | UDF validation error on field type | Field type not supported by the active plugin | Run `designer_list_plugins` + `designer_get_udf_catalog` to verify supported types |
828
+ | `constraints.format ... is not supported for type 'date'` (or `timestamp`) | Per-field date pattern in RDF | Remove `format`; the pattern comes from `DATEFORMAT` / `DATETIMEFORMAT` |
829
+ | Frontend shows a different date than the backend stored | `appConfig.dateFormat` / `dateTimeFormat` differ from the backend config | Re-run `codegen_migrate_payload`, then `designer_generate` |
830
+ | Hook rejection answered HTTP 400 with only the hook message | A component handler returned `{ success: false }` or threw | Expected behaviour; the handler name and path are in the server log |
737
831
 
738
832
  When an error is not in this table, do not guess a fix. Re-run the relevant
739
833
  `*_validate_*` tool, read its message, and ground against the catalog before
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "RESTForge"
3
+ short_description: "Build RESTForge APIs and frontends through MCP"
4
+ default_prompt: "Use $restforge to build or update my RESTForge application."
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Offline mirror.** This file mirrors the auth commands of the installed
4
4
  > RESTForge platform and Designer (`restforge project auth`, `npx
5
- > restforge-designer auth`). The live tools/CLI are authoritative — when this file and them disagree,
5
+ > npx restforge-designer auth`). The live tools/CLI are authoritative — when this file and them disagree,
6
6
  > trust the tools, then update this file.
7
7
 
8
8
  **This file documents the auth EXTENSION — auth WITHOUT RBAC.** It is one of two
@@ -116,7 +116,7 @@ injected automatically when `designer_generate` creates pages later.
116
116
  **Prerequisites:** the Designer is invoked via `npx restforge-designer` and is
117
117
  bundled inside the `@restforgejs/platform` package; the prerequisite is that
118
118
  `@restforgejs/platform` is installed in the project (e.g. a project created with
119
- `npx create-restforge-app`), not a standalone binary on PATH.
119
+ `npx create-restforge-app`).
120
120
 
121
121
  Both are idempotent. **`--remove` is destructive** — confirm project name and
122
122
  intent with the user before running (MCP always passes `--force`).