@dforge-core/dforge-mcp 0.1.13 → 0.2.1
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.
- package/CHANGELOG.md +231 -0
- package/README.md +106 -72
- package/dist/server.js +2322 -393
- package/docs/creating-modules.md +21 -10
- package/package.json +7 -4
- package/resources/docs/dsl-reference.md +27 -6
- package/resources/schemas/domains.schema.json +78 -0
- package/resources/schemas/entity.schema.json +18 -0
- package/resources/schemas/triggers.schema.json +5 -5
- package/scripts/install-skills.mjs +165 -0
- package/skills/dforge-mcp-author/SKILL.md +147 -471
- package/skills/dforge-mcp-author/references/action-dsl.md +36 -1
- package/skills/dforge-module-build/SKILL.md +309 -0
- package/skills/dforge-module-design/SKILL.md +125 -0
- package/skills/dforge-module-ship/SKILL.md +163 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,237 @@ All notable changes to `@dforge-core/dforge-mcp`. This project uses semver-ish
|
|
|
4
4
|
`0.1.0-rc.N` pre-release tags; the published version is set at publish time via
|
|
5
5
|
the release workflow, so committed `package.json` versions are placeholders.
|
|
6
6
|
|
|
7
|
+
## 0.2.0
|
|
8
|
+
|
|
9
|
+
Tools go from 27 → 34; the single wizard skill splits into a router plus three
|
|
10
|
+
stage skills; `dforge_module_validate` grows the checks that previously only
|
|
11
|
+
surfaced at install.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`dforge_module_inspect` reported nothing useful about actions.** It read
|
|
16
|
+
`entity` / `mode` / `background`, but `dforge_action_add` has always written
|
|
17
|
+
`entityCode` / `executionMode` / `isAsync` (matching the installer and the
|
|
18
|
+
canonical example), so every action inspected as `entity: "?"`. Since the
|
|
19
|
+
skill makes inspect the pre-patch source of truth, agents were planning
|
|
20
|
+
against wrong data. Legacy key names are still read as a fallback.
|
|
21
|
+
- **`dforge_module_inspect` listed `["jobs"]` as the job list** — `logic/jobs.json`
|
|
22
|
+
is `{ jobs: [...] }`, not a code-keyed map, so `Object.keys` returned the
|
|
23
|
+
wrapper key. Jobs, triggers and webhooks are now reported properly, alongside
|
|
24
|
+
queries, print templates, domains and `supportedLocales`.
|
|
25
|
+
- **Every entity's `toString` was reported as an inherited function.** `toString`
|
|
26
|
+
comes from `Object.prototype`, so reading `entity.toString` never yields
|
|
27
|
+
`undefined`; `JSON.stringify` then dropped it silently. Now read as an own
|
|
28
|
+
property.
|
|
29
|
+
- **Freshly scaffolded entities shipped a dangling `toString`.** dforge-cli's
|
|
30
|
+
`buildEntity` emits `"{id}"`, but the `identity` trait names the PK
|
|
31
|
+
`{entity}_id` — so the template referenced a column that never existed.
|
|
32
|
+
Normalized to `{<entity>_id}` on the way out of `module_create` / `entity_add`.
|
|
33
|
+
- **Phase labels in the tool descriptions had drifted** from the skill: entity
|
|
34
|
+
and field tools claimed Phase 2 (they're Phase 1); views and reports claimed
|
|
35
|
+
Phase 4 (they're Phase 3). Tool descriptions are always in context and the
|
|
36
|
+
skill table isn't, so the wrong one was winning.
|
|
37
|
+
- **Resource descriptions never reached the client.** The deprecated
|
|
38
|
+
`server.resource()` signature dropped them; `registerResource` carries them.
|
|
39
|
+
|
|
40
|
+
### Added — composite entity tools
|
|
41
|
+
|
|
42
|
+
Three dForge concepts each span several coordinated keys, and hand-assembling
|
|
43
|
+
them from `entity_field_add` is the top source of broken modules. These take the
|
|
44
|
+
intent and emit the whole shape, so the broken variants aren't representable:
|
|
45
|
+
|
|
46
|
+
- **`dforge_entity_reference_add`** — a relation as all three of its parts:
|
|
47
|
+
hidden FK (`cuid` / `EM` / no `fieldTypeCd`), visible Reference (`R` /
|
|
48
|
+
`lookup` / `link`), and the `references` entry. Also *completes* a half-built
|
|
49
|
+
relation by reusing an FK column an import already created.
|
|
50
|
+
- **`dforge_entity_rollup_add`** — a child total as a **Generated** (`G`) column,
|
|
51
|
+
creating the parent's Set column when needed, and refusing to aggregate a
|
|
52
|
+
virtual `F`/`R`/`S` child (the `column old.<field> does not exist` failure).
|
|
53
|
+
- **`dforge_entity_status_add`** — a dropdown with `params.options` objects and
|
|
54
|
+
the initial value as a `formula`, never the `defaultValue` key the entity
|
|
55
|
+
schema rejects.
|
|
56
|
+
|
|
57
|
+
### Added — DSL static checking
|
|
58
|
+
|
|
59
|
+
- **`dforge_action_check`** — check a draft `dslBody` before committing to
|
|
60
|
+
`action_add`, or an `actionCode` already on disk (its execution mode and job
|
|
61
|
+
bindings are read from the module). Catches `TODAY()`/`NOW()` inside
|
|
62
|
+
`execute:`, `[field]` record-context in batch mode or a job-invoked action,
|
|
63
|
+
block order/duplication, top-level `return`, `:param` SQL placeholders, and
|
|
64
|
+
unknown host functions.
|
|
65
|
+
- `dforge_action_add` now runs the same checker and rejects errors, replacing
|
|
66
|
+
the single hard-coded `TODAY()` grep.
|
|
67
|
+
- `dforge_module_validate` runs it over every action body in the module.
|
|
68
|
+
|
|
69
|
+
### Added — the element tools that were missing
|
|
70
|
+
|
|
71
|
+
- **`dforge_menu_add`** — menus had a reference doc and a schema but no tool, so
|
|
72
|
+
agents hand-wrote the JSON and hit the same three documented mistakes. Now
|
|
73
|
+
`dataViewCode` is validated against `data_views.json`, `itemType` lands on
|
|
74
|
+
leaves only, and icons are normalized to the bare form menus require.
|
|
75
|
+
- **`dforge_translation_sync`** — generates every install-required key from the
|
|
76
|
+
module's own contents (entities + trait-provided fields, views, menus, roles,
|
|
77
|
+
actions, folders, settings), never overwriting existing translated text.
|
|
78
|
+
"Missing translation key" was a documented install-failure mode with no tool
|
|
79
|
+
behind it, and role labels are completeness-enforced.
|
|
80
|
+
- **`dforge_seed_add`** — enforces the four documented seed traps: numeric
|
|
81
|
+
`{entity}_id` PKs, parent-before-child load order, `audit-full` System-user
|
|
82
|
+
columns, and FKs pointing at seeded parents.
|
|
83
|
+
|
|
84
|
+
### Added — `apply: true`
|
|
85
|
+
|
|
86
|
+
Every patch tool accepts `apply`. It writes the file map to disk and returns the
|
|
87
|
+
paths instead of the contents — cutting the full-file round trip through context
|
|
88
|
+
on routine patches, and guaranteeing the `deletes` half of a rename/delete is
|
|
89
|
+
applied. Refuses to write outside `moduleDir`; never writes report payloads.
|
|
90
|
+
|
|
91
|
+
### Added — full-lifecycle phase ledger
|
|
92
|
+
|
|
93
|
+
`docs/phase.json` now records Phases 1-6, not just Phase 0.
|
|
94
|
+
`dforge_module_plan({ action: "check" })` returns `currentPhase`, `nextSkill`
|
|
95
|
+
and `gaps` derived from the ledger **plus** evidence read from the module
|
|
96
|
+
(entities without fields, without a view, without a Select grant).
|
|
97
|
+
`complete_phase` records a phase as done or deliberately skipped. Previously a
|
|
98
|
+
resumed session had to guess the phase by cross-referencing inspect output,
|
|
99
|
+
which can't distinguish "skipped deliberately" from "not started".
|
|
100
|
+
|
|
101
|
+
### Fixed — follow-ups from review
|
|
102
|
+
|
|
103
|
+
- **`dbDatatype: "number"` produced a suggestion with unbalanced quotes.** The
|
|
104
|
+
alias table smuggled quote characters into its value to fake a list, so the
|
|
105
|
+
rendered message depended on the surrounding template. Multi-option
|
|
106
|
+
suggestions are now real arrays formatted by one helper — `use 'int' /
|
|
107
|
+
'bigint' / 'numeric'.`
|
|
108
|
+
- **Folder codes were only checked among siblings.** A folder is addressed flat
|
|
109
|
+
and path-less outside the tree — `folder:<code>` in role rights,
|
|
110
|
+
`folders.<code>.label` in translations — so the same code in two branches was
|
|
111
|
+
ambiguous in the rights matrix and let one folder's label silently overwrite
|
|
112
|
+
the other's in a synced translation file. `dforge_folder_add` now refuses a
|
|
113
|
+
code used anywhere in the tree, `dforge_module_validate` errors on duplicates,
|
|
114
|
+
and `dforge_translation_sync` refuses to generate colliding keys.
|
|
115
|
+
- **`apply: true` without `moduleDir` silently degraded to a preview** — a
|
|
116
|
+
client relying on apply semantics got a success response and no write. It now
|
|
117
|
+
errors.
|
|
118
|
+
- **Raw NUL bytes were being used as composite-key separators** (the validator's
|
|
119
|
+
view+entity keys and `dforge_translation_sync`'s keep/prune path keys). Beyond
|
|
120
|
+
being invisible in a diff and unreadable in debug output, a NUL makes `grep`
|
|
121
|
+
classify the whole source file as BINARY and stop reporting matches in it — so
|
|
122
|
+
the usual "search the codebase" check came back clean while the problem sat
|
|
123
|
+
right there. Both now use a shared, exported `compositeKey()` / `KEY_SEP =
|
|
124
|
+
"::"`, and a `source-hygiene` test fails the build on any raw NUL or other
|
|
125
|
+
invisible control character in `src/` or `test/`.
|
|
126
|
+
- **`dforge_entity_reference_add` reused an existing FK column without checking
|
|
127
|
+
its shape.** An import commonly emits the FK as a visible numeric column;
|
|
128
|
+
reusing it as-is produced a pair that looked complete and failed at install.
|
|
129
|
+
The column is now normalized to the hidden-FK shape (`cuid` / `EM`, no
|
|
130
|
+
`fieldTypeCd`, no `columnType`), preserving author metadata like `orderNum`
|
|
131
|
+
and `description`, and the response reports exactly what changed.
|
|
132
|
+
- **`dforge_module_plan` was registered through the ToolResult envelope with a
|
|
133
|
+
cast**, which would have absorbed a real shape mismatch — most of its actions
|
|
134
|
+
return lifecycle state with no `files` at all. It now has an explicit
|
|
135
|
+
`PlanResult` type and a `serialize()` envelope that makes no ToolResult
|
|
136
|
+
assumption. (The envelope was also renamed off `readOnly`: read-only-ness is
|
|
137
|
+
declared by the tool `annotations`, and some tools it wraps do return files.)
|
|
138
|
+
- **`applyToDisk` would throw an opaque error if `deletes` ever contained a
|
|
139
|
+
directory.** `deletes` is a file-only contract, so it now says so: directories
|
|
140
|
+
are refused by name rather than removed recursively (silently deleting a
|
|
141
|
+
subtree would be the worst response to a tool bug), and symlinks are unlinked
|
|
142
|
+
rather than followed.
|
|
143
|
+
|
|
144
|
+
### Fixed — second review pass
|
|
145
|
+
|
|
146
|
+
- **`dforge_seed_add` hard-coded a list of "trait-provided columns" that was
|
|
147
|
+
wrong on almost every entry.** The registry's real names are `created_date` /
|
|
148
|
+
`last_updated` (audit), `order_num` (sorting), `active` (soft-delete) — not
|
|
149
|
+
`created_at` / `updated_at` / `sort_order` / `is_deleted`, and `audit-full`'s
|
|
150
|
+
`created_by_user` / `last_updated_by_user` and the whole `period` set were
|
|
151
|
+
missing. Seeding a legitimate `created_date` was rejected as an unknown
|
|
152
|
+
column. Now derived from `expandTraits` for the entity's actual trait list.
|
|
153
|
+
- **Unknown trait codes were silently dropped, not rejected.** `expandTraits`
|
|
154
|
+
returns only the codes it recognizes, so a typo'd trait doesn't fail — its
|
|
155
|
+
columns just vanish, and every downstream check then reports them as "not a
|
|
156
|
+
column". `dforge_module_validate` now flags the cause, and `seed_add` /
|
|
157
|
+
`translation_sync` refuse to run against one.
|
|
158
|
+
- **`dforge_translation_sync` silently skipped unreadable entity files**,
|
|
159
|
+
producing an incomplete skeleton while reporting success — the gap would only
|
|
160
|
+
surface later as a missing-label install failure. A missing or malformed
|
|
161
|
+
entity file named in the manifest is now fatal, and names the path.
|
|
162
|
+
- **The SQL-literal scan used a regex that stopped at the first escaped quote**,
|
|
163
|
+
so `query('... \' ... :cid')` truncated mid-statement and the placeholder
|
|
164
|
+
check missed what followed. Replaced with an escape-aware string scanner;
|
|
165
|
+
concatenation is now detected after the literal rather than inside it.
|
|
166
|
+
- `dforge_module_plan`'s `complete_phase` cast its own check result back to an
|
|
167
|
+
untyped bag, discarding the `PlanResult` typing; `buildPhaseCheck` now returns
|
|
168
|
+
a declared `BuildPhaseCheck` and the fields are destructured.
|
|
169
|
+
- Renamed the control-character guard test to match what it scans (whole source,
|
|
170
|
+
not only string literals).
|
|
171
|
+
|
|
172
|
+
### Changed — validation is now the single choke point
|
|
173
|
+
|
|
174
|
+
Field rules lived only in the `entity_field_add` zod schema, so anything
|
|
175
|
+
entering via `module_import`, `dbml_import`, the scaffolder or a hand edit
|
|
176
|
+
bypassed them entirely. They now live in one place and run in both. New checks
|
|
177
|
+
in `dforge_module_validate`:
|
|
178
|
+
|
|
179
|
+
- every field re-checked against the full rule set, module-wide
|
|
180
|
+
- Formula (`F`) and Generated (`G`) column shape; Reference (`R`) column shape
|
|
181
|
+
- `dbDatatype` values that are really `fieldTypeCd`s
|
|
182
|
+
- `toString` present, and its `{braces}` resolving to real columns
|
|
183
|
+
- an `F` column carrying a set aggregate; a `G` aggregate over a virtual child
|
|
184
|
+
- action `script` files missing from disk, or not bare filenames
|
|
185
|
+
- triggers/jobs firing actions that don't exist; job actions using `[field]`
|
|
186
|
+
- DSL static checks on every action body
|
|
187
|
+
- translation completeness: a file per `supportedLocales` entry, and a
|
|
188
|
+
`roles.<code>.label` in every locale file including the en-US base
|
|
189
|
+
|
|
190
|
+
### Fixed — the skills installer did not work on Windows
|
|
191
|
+
|
|
192
|
+
`scripts/install-skills.sh` was bash-only, so it could not run in cmd.exe or
|
|
193
|
+
PowerShell at all — and `npm run install-skills` invoked `bash`, which fails
|
|
194
|
+
there too. Under WSL it appeared to work but resolved `$HOME` to the *Linux*
|
|
195
|
+
home, silently installing to `/home/you/.claude` while a Windows Claude Code
|
|
196
|
+
read `C:\Users\you\.claude`. `scripts/` was also absent from package.json
|
|
197
|
+
`files`, so the script did not ship at all.
|
|
198
|
+
|
|
199
|
+
The installer is now **`scripts/install-skills.mjs`** (Node), behaving
|
|
200
|
+
identically on Windows/macOS/Linux/Git Bash/WSL:
|
|
201
|
+
|
|
202
|
+
- exposed as a `dforge-install-skills` bin, so
|
|
203
|
+
`npx -y -p @dforge-core/dforge-mcp dforge-install-skills` needs no clone and
|
|
204
|
+
no bash (npm shims it as `.cmd` on Windows)
|
|
205
|
+
- destination resolves `DEST` → `CLAUDE_CONFIG_DIR/skills` →
|
|
206
|
+
`os.homedir()/.claude/skills`, so Windows gets `%USERPROFILE%` regardless of
|
|
207
|
+
the invoking shell
|
|
208
|
+
- `--from-npm` uses `npm pack` + `tar` (built into Windows 10 1803+), which
|
|
209
|
+
fetches only this package rather than its ~35 MB native CLI dependency
|
|
210
|
+
- handles `EPIPE` so piping into `head`/`less` doesn't dump a stack trace
|
|
211
|
+
- `scripts/install-skills.mjs` added to package.json `files`
|
|
212
|
+
|
|
213
|
+
`scripts/install-skills.sh` is kept as a thin wrapper that execs the Node
|
|
214
|
+
script, so the documented `curl … | bash` one-liner still works.
|
|
215
|
+
|
|
216
|
+
### Changed — skills split by lifecycle stage
|
|
217
|
+
|
|
218
|
+
`dforge-mcp-author` becomes a thin router; `dforge-module-design` (Phase 0),
|
|
219
|
+
`dforge-module-build` (Phases 1-5) and `dforge-module-ship` (Phase 6) own the
|
|
220
|
+
instructions. Each stage needs a different half of the knowledge base, and the
|
|
221
|
+
488-line monolith was resident for all of it. Handoff is deterministic via
|
|
222
|
+
`dforge_module_plan`'s `nextSkill`. The router directory still carries the
|
|
223
|
+
shared `references/` + `examples/` the MCP server serves as resources.
|
|
224
|
+
|
|
225
|
+
`scripts/install-skills.sh` installs all four (`--from-npm` to pull the
|
|
226
|
+
published package).
|
|
227
|
+
|
|
228
|
+
### Changed — internal
|
|
229
|
+
|
|
230
|
+
- Migrated from the deprecated `server.tool()` / `server.resource()` to
|
|
231
|
+
`registerTool` / `registerResource`, adding titles and annotations
|
|
232
|
+
(`readOnlyHint` on inspect/validate/action_check, `destructiveHint` on the
|
|
233
|
+
delete/rename refactors and install, `openWorldHint` on pack/install).
|
|
234
|
+
- Tests: 80 → 161, including an end-to-end suite that drives a module through
|
|
235
|
+
the real tool surface on a temp directory and asserts it validates clean. That
|
|
236
|
+
suite is what caught the inspect key mismatch and the scaffolder's `{id}`.
|
|
237
|
+
|
|
7
238
|
## 0.1.12
|
|
8
239
|
|
|
9
240
|
> Release prerequisite: publish `@dforge-core/metadata@0.0.10` first (adds the
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @dforge-core/dforge-mcp
|
|
2
2
|
|
|
3
|
-
MCP server for dForge module authoring. Exposes
|
|
3
|
+
MCP server for dForge module authoring. Exposes 34 composable tools and the canonical schemas so AI agents (Claude Code, Cursor, Zed, etc.) can drive the full module lifecycle — scaffold → entities → actions → views → security → install — through structured tool calls instead of free-form JSON generation.
|
|
4
4
|
|
|
5
|
-
Ships with
|
|
5
|
+
Ships with **four Claude Skills** (`skills/`): a router plus one skill per lifecycle stage — design (Phase 0), build (Phases 1-5), and ship (Phase 6). The router directory carries 25 reference files (field types, flags, traits, formulas, DSL, security, etc.) and two annotated example modules.
|
|
6
6
|
|
|
7
7
|
**New here?** Start with **[docs/creating-modules.md](docs/creating-modules.md)** — three ways to scaffold a module (terminal CLI, VS Code sidebar, AI wizard) and when to pick each.
|
|
8
8
|
|
|
@@ -74,7 +74,7 @@ claude mcp list
|
|
|
74
74
|
# Should show: dforge — npx -y @dforge-core/dforge-mcp — connected
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
Or inside a Claude Code session, type `/mcp` to see all connected servers + their tools. The
|
|
77
|
+
Or inside a Claude Code session, type `/mcp` to see all connected servers + their tools. The 34 `dforge_*` tools should be listed.
|
|
78
78
|
|
|
79
79
|
### Cursor / Zed
|
|
80
80
|
|
|
@@ -82,7 +82,7 @@ Same `command + args` config shape; check their docs for the file location. Veri
|
|
|
82
82
|
|
|
83
83
|
## What it exposes
|
|
84
84
|
|
|
85
|
-
### Tools (
|
|
85
|
+
### Tools (34)
|
|
86
86
|
|
|
87
87
|
Grouped by typical phase in the wizard flow. All "return" tools emit `{ summary, files: { '<relPath>': '<contents>' } }`; the client decides whether to write — lets the AI preview diffs with the user before committing.
|
|
88
88
|
|
|
@@ -91,11 +91,11 @@ Phase 0 (identity → requirements → design → validation) is orchestrated by
|
|
|
91
91
|
**Module-level**
|
|
92
92
|
| Tool | Behavior |
|
|
93
93
|
|---|---|
|
|
94
|
-
| `dforge_module_plan` | **
|
|
94
|
+
| `dforge_module_plan` | **Lifecycle orchestrator** — drives Phase 0 (identity → requirements → design → validation), gates `dforge_module_create` until `readyToScaffold: true`, then tracks Phases 1-6 via a ledger in `docs/phase.json`. `action: "check"` returns `currentPhase` + `nextSkill`; `complete_phase` records a phase done or skipped. Call first in any session |
|
|
95
95
|
| `dforge_module_create` | New module scaffold (blocked until Phase 0 passes) |
|
|
96
96
|
| `dforge_module_import` | Import a normalized **table-spec** (tables → columns → relationships) into an existing module as entities. Infers `fieldTypeCd` from SQL type / sample values / name (metadata-validated, `dbDatatype` derived) and builds the FK+Reference pair per relationship. Fed by DBML/SQL, Excel/CSV, or a hand-authored spec |
|
|
97
97
|
| `dforge_module_inspect` | Read current module state. Full structured data is in `files["_inspect.json"]`; `summary` is one-line stats |
|
|
98
|
-
| `dforge_module_validate` | Offline
|
|
98
|
+
| `dforge_module_validate` | Offline check (run before pack): dangling FK targets, missing hidden-FK columns, view/menu/role refs to non-existent things, uncovered entities, **field-spec rules re-run across every field**, `toString` templates, Formula-vs-Generated set aggregates, missing action DSL files, triggers/jobs firing non-existent actions, DSL static checks, and translation completeness. Errors + warnings in `files["_validate.json"]` |
|
|
99
99
|
| `dforge_module_pack` | Shells to `dforge-cli module pack` via bundled CLI, PATH fallback, or `DFORGE_CLI_BINARY`. Returns tarball path + size |
|
|
100
100
|
| `dforge_module_install` | Shells to `dforge-cli module install`. Args: `pathOrTarball`, optional `tenantUrl` / `token` / `tenantCode` — fall back to `DFORGE_URL` / `DFORGE_TOKEN` env. Returns `ok`, `exitCode`, `command`, and raw CLI `output` so the AI can fix install-time module defects and retry |
|
|
101
101
|
|
|
@@ -110,23 +110,41 @@ Phase 0 (identity → requirements → design → validation) is orchestrated by
|
|
|
110
110
|
| `dforge_entity_field_rename` | **Refactor-safe rename** — propagates the new name to the paired Reference, formulas, view columns + order, seed data, and other entities' FKs |
|
|
111
111
|
| `dforge_entity_field_remove` | **Refactor-safe remove** — cascade-cleans paired Reference, view columns + order, seed keys; warns on formula/cross-entity dependents |
|
|
112
112
|
|
|
113
|
+
**Composite entity tools (Phase 1) — one call per concept, prefer these**
|
|
114
|
+
|
|
115
|
+
Each of these spans several coordinated keys that hand-assembly gets wrong. They exist so the broken shapes aren't expressible.
|
|
116
|
+
|
|
117
|
+
| Tool | Emits |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `dforge_entity_reference_add` | A whole relation: hidden FK (`cuid`/`EM`) **+** Reference column (`R`/`lookup`/`link`) **+** the `references` entry. The documented #1 source of broken modules, in one call. Also completes a half-built relation by reusing an FK an import already created |
|
|
120
|
+
| `dforge_entity_rollup_add` | A child total as a **Generated** (`G`) column — never a Formula, whose set-aggregates silently render empty — creating the parent's Set column if needed, and refusing to aggregate a virtual `F`/`R`/`S` child (`column old.<field> does not exist`) |
|
|
121
|
+
| `dforge_entity_status_add` | A dropdown with `params.options` objects and the initial value as a `formula` — entity fields have no `defaultValue` key |
|
|
122
|
+
|
|
113
123
|
The field/entity tools validate against the `@dforge-core/metadata` registry: an unknown `fieldTypeCd` (e.g. `integer`, `reference`), `columnType`, or trait code is rejected at authoring time with a "did you mean" hint, and `dbDatatype` is auto-derived from the field type (currency → `numeric(18,2)`, text → `varchar`; reference/formula columns get none) unless you set it explicitly.
|
|
114
124
|
|
|
115
125
|
**Behavior (Phase 2 — optional)**
|
|
116
126
|
| Tool | Behavior |
|
|
117
127
|
|---|---|
|
|
118
|
-
| `dforge_action_add` | DSL script + `ui/actions.json` entry |
|
|
128
|
+
| `dforge_action_add` | DSL script + `ui/actions.json` entry. Runs the DSL static checker first — errors reject the call |
|
|
129
|
+
| `dforge_action_check` | Statically check a **draft** `dslBody` before committing, or an `actionCode` already on disk. Catches `TODAY()` in `execute:`, `[field]` in batch/job context, block order, top-level `return`, `:param` placeholders, unknown host functions |
|
|
119
130
|
| `dforge_trigger_add` | DB-event trigger in `logic/triggers.json` (entity event + optional condition → action) |
|
|
120
131
|
| `dforge_job_add` | Scheduled job in `logic/jobs.json` (5-field cron + timeout + action) |
|
|
121
132
|
| `dforge_webhook_add` | Outbound webhook in `logic/webhooks.json` (entity event → POST to endpoint) |
|
|
122
133
|
|
|
123
|
-
**Views + reports (Phase 3)**
|
|
134
|
+
**Views, menus + reports (Phase 3)**
|
|
124
135
|
| Tool | Behavior |
|
|
125
136
|
|---|---|
|
|
126
137
|
| `dforge_view_add` | Add a data view |
|
|
127
138
|
| `dforge_view_modify` | Replace a view's spec |
|
|
139
|
+
| `dforge_menu_add` | Add a menu leaf or section. Validates `dataViewCode` against `data_views.json`, emits `itemType: "V"` on leaves only, and normalizes icons to the bare form menus require (strips `bi-`) |
|
|
128
140
|
| `dforge_report_add` | Add a report |
|
|
141
|
+
|
|
142
|
+
**Polish (Phase 4)**
|
|
143
|
+
| Tool | Behavior |
|
|
144
|
+
|---|---|
|
|
129
145
|
| `dforge_setting_add` | Configurable module-level setting |
|
|
146
|
+
| `dforge_translation_sync` | Generate/refresh `translations/<locale>.json` from the module's own contents. Never overwrites existing translated text; fills the role labels that are **completeness-enforced at install**. Defaults to en-US + every `supportedLocales` entry |
|
|
147
|
+
| `dforge_seed_add` | Write a seed file for one entity. Enforces numeric `{entity}_id` PKs, parent-before-child load order, `audit-full` System-user columns, and FKs that point at seeded parents |
|
|
130
148
|
|
|
131
149
|
**Security (Phase 5)**
|
|
132
150
|
| Tool | Behavior |
|
|
@@ -141,23 +159,33 @@ The field/entity tools validate against the `@dforge-core/metadata` registry: an
|
|
|
141
159
|
| `dforge_dependency_add` | Add a dep on another dForge module |
|
|
142
160
|
| `dforge_dbml_import` | **DBML front-end** to `module_import` — parses DBML (Table blocks, typed columns, inline + top-level refs) into the table-spec, drops the source PK (identity provides `{entity}_id`), and imports. Pass `module` for a greenfield import |
|
|
143
161
|
|
|
144
|
-
###
|
|
162
|
+
### Writing files: preview vs `apply`
|
|
163
|
+
|
|
164
|
+
Every patch tool returns `{ summary, files, deletes? }` for the client to write, so the agent can preview a diff with the user first. Passing **`apply: true`** instead writes the files (and honours `deletes`) directly and returns only the paths touched.
|
|
145
165
|
|
|
146
|
-
|
|
166
|
+
```jsonc
|
|
167
|
+
// preview (default) — full file contents come back through the model's context
|
|
168
|
+
{ "moduleDir": "/path/to/mod", "entityName": "order", "fieldName": "note", "field": { ... } }
|
|
169
|
+
|
|
170
|
+
// apply — writes to disk, returns { applied: true, written: [...], deleted: [...] }
|
|
171
|
+
{ "moduleDir": "/path/to/mod", "entityName": "order", "fieldName": "note", "field": { ... }, "apply": true }
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Use `apply` for routine patches inside an already-approved plan, and for every `rename`/`delete` refactor — it guarantees the `deletes` half is applied, which is easy to drop by hand. It refuses to write outside `moduleDir`, and never writes the `_inspect.json` / `_validate.json` / `_action_check.json` report payloads, which only reuse the file-map shape for transport.
|
|
175
|
+
|
|
176
|
+
### Resources
|
|
177
|
+
|
|
178
|
+
Served over MCP with descriptions and mime types, so the agent can tell what a URI is for before pulling it.
|
|
179
|
+
|
|
180
|
+
| URI pattern | Content |
|
|
147
181
|
|---|---|
|
|
148
|
-
| `dforge://schema
|
|
149
|
-
| `dforge://
|
|
150
|
-
| `dforge://
|
|
151
|
-
| `dforge://
|
|
152
|
-
| `dforge://schema/menus` | ui/menus.json |
|
|
153
|
-
| `dforge://schema/roles` | security/roles.json |
|
|
154
|
-
| `dforge://schema/jobs` | logic/jobs.json |
|
|
155
|
-
| `dforge://schema/seed-data` | seed-data/*.json |
|
|
156
|
-
| `dforge://schema/reports` | ui/reports.json |
|
|
157
|
-
| `dforge://schema/settings` | settings.json |
|
|
158
|
-
| `dforge://schema/traits` | entity trait codes |
|
|
159
|
-
| `dforge://schema/webhooks` | ui/webhooks.json |
|
|
182
|
+
| `dforge://schema/<name>` | JSON Schemas: `manifest`, `entity`, `domains`, `data-views`, `folders`, `menus`, `roles`, `jobs`, `seed-data`, `traits`, `webhooks`, `triggers`, `print-templates`, `settings`, `reports` |
|
|
183
|
+
| `dforge://reference/<name>` | 25 per-element authoring references — schema shape + worked example + common-mistakes list for one element type |
|
|
184
|
+
| `dforge://example/<path>` | Files from the canonical `simple-todo` module (mandatory structure validators) |
|
|
185
|
+
| `dforge://example/matrix-budget/<path>` | Files from the `matrix` (pivot) view example |
|
|
160
186
|
| `dforge://docs/conventions` | MODULE_CONVENTIONS.md |
|
|
187
|
+
| `dforge://docs/dsl` | Full action-DSL grammar, built-ins, patterns, anti-patterns |
|
|
188
|
+
| `dforge://script/xlsx-to-model` | Stdlib Python `.xlsx` → table-spec extractor |
|
|
161
189
|
|
|
162
190
|
Schemas + conventions are vendored at build time from `iash44/dForge-core`'s `docs/`. The published npm tarball ships them under `resources/`, and jsdelivr serves them at:
|
|
163
191
|
|
|
@@ -167,70 +195,76 @@ https://cdn.jsdelivr.net/npm/@dforge-core/dforge-mcp@latest/resources/schemas/<n
|
|
|
167
195
|
|
|
168
196
|
**Compatibility:** schemas vendored for this release came from `iash44/dForge-core` `main` as of the publish date stamped in `package.json`. If the platform adds new entity properties / field types after this release, generated modules using those features may validate locally but be rejected at install time. Bump the dforge-mcp version when the platform schemas change materially.
|
|
169
197
|
|
|
170
|
-
## Claude
|
|
198
|
+
## Claude Skills — router + three stage skills
|
|
171
199
|
|
|
172
|
-
|
|
200
|
+
Authoring guidance ships as **four** skills, split by lifecycle stage. Each stage needs a different half of the knowledge base — Phase 0 needs none of the field-type/DSL detail, Phase 6 needs none of the intake guardrails — so loading only the active stage is what keeps a full module build inside one context window.
|
|
201
|
+
|
|
202
|
+
| Skill | Phases | Owns |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| `dforge-mcp-author` | — | **Router. Start here.** Calls `dforge_module_plan` to find the current phase and hands off. Also carries the shared `references/` + `examples/`. |
|
|
205
|
+
| `dforge-module-design` | 0a–0d | Identity, intake guardrails, design doc, pre-scaffold validation. Ends at `readyToScaffold: true`. |
|
|
206
|
+
| `dforge-module-build` | 1–5 | Entities, behavior, views/menus, polish, security. Loading-policy table, core-rules cheat sheet, backtrack protocol. |
|
|
207
|
+
| `dforge-module-ship` | 6 | Validate → pre-pack review → version audit → pack → install-fix loop. |
|
|
208
|
+
|
|
209
|
+
The handoff is deterministic rather than vibes-based: `dforge_module_plan({ action: "check" })` returns `currentPhase` **and** `nextSkill`, derived from the Phase 0 artifacts, the phase ledger in `docs/phase.json`, and evidence read from the module itself (entities without fields, entities without a view, entities without a Select grant).
|
|
210
|
+
|
|
211
|
+
The router directory also holds the shared assets:
|
|
173
212
|
|
|
174
213
|
| Path | Contents |
|
|
175
214
|
|---|---|
|
|
176
|
-
| `
|
|
177
|
-
| `references/*.md` | 23 detailed reference files (field types, flags, traits, formulas, DSL, security, views, menus, translations, …) |
|
|
215
|
+
| `references/*.md` | 25 reference files (field types, flags, traits, formulas, DSL, security, views, menus, translations, …) |
|
|
178
216
|
| `examples/simple-todo/` | Annotated reference module showing all core patterns |
|
|
217
|
+
| `examples/matrix-budget/` | Worked example for the `matrix` (pivot) view type |
|
|
218
|
+
| `scripts/xlsx_to_model.py` | Stdlib Python `.xlsx` → table-spec extractor |
|
|
219
|
+
|
|
220
|
+
**Skills are NOT auto-installed by `npm install`** — they ship in the npm tarball, but Claude Code looks in `~/.claude/skills/`, not `node_modules`. Use the installer, which is a Node script so it behaves identically on **Windows (cmd.exe / PowerShell), macOS, Linux, Git Bash and WSL**:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Straight from the published package — no clone needed:
|
|
224
|
+
npx -y -p @dforge-core/dforge-mcp dforge-install-skills
|
|
225
|
+
|
|
226
|
+
# From a local checkout:
|
|
227
|
+
npm run install-skills
|
|
179
228
|
|
|
180
|
-
|
|
229
|
+
# Equivalently, without npm:
|
|
230
|
+
node scripts/install-skills.mjs [--from-npm]
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Destination resolution, in order: `DEST` → `CLAUDE_CONFIG_DIR/skills` → `<home>/.claude/skills`. The home directory comes from Node's `os.homedir()`, so on Windows it's `%USERPROFILE%` no matter which shell invoked it.
|
|
181
234
|
|
|
182
235
|
```bash
|
|
183
|
-
|
|
184
|
-
# then pin the jsdelivr URL to it. We don't use jsdelivr's `@latest`
|
|
185
|
-
# alias directly — that CDN endpoint caches aggressively (6-12h lag
|
|
186
|
-
# after a new publish), which silently serves stale Skill content.
|
|
187
|
-
VERSION=$(npm view @dforge-core/dforge-mcp version)
|
|
188
|
-
BASE="https://cdn.jsdelivr.net/npm/@dforge-core/dforge-mcp@${VERSION}/skills/dforge-mcp-author"
|
|
189
|
-
|
|
190
|
-
# Wizard
|
|
191
|
-
mkdir -p ~/.claude/skills/dforge-mcp-author
|
|
192
|
-
curl -fsSL "$BASE/SKILL.md" -o ~/.claude/skills/dforge-mcp-author/SKILL.md
|
|
193
|
-
|
|
194
|
-
# Reference files (23 guides — load on demand per the table in SKILL.md)
|
|
195
|
-
mkdir -p ~/.claude/skills/dforge-mcp-author/references
|
|
196
|
-
for f in action-dsl column-types conventions data-migration data-views \
|
|
197
|
-
field-types filters flags formulas jobs manifest menus \
|
|
198
|
-
number-sequences print-templates queries reports schema-import \
|
|
199
|
-
security settings traits translations validation-checklist; do
|
|
200
|
-
curl -fsSL "$BASE/references/${f}.md" \
|
|
201
|
-
-o ~/.claude/skills/dforge-mcp-author/references/${f}.md
|
|
202
|
-
done
|
|
203
|
-
|
|
204
|
-
# simple-todo example
|
|
205
|
-
mkdir -p ~/.claude/skills/dforge-mcp-author/examples/simple-todo/{entities,logic/actions,ui,security,seed-data}
|
|
206
|
-
for f in README.md manifest.json; do
|
|
207
|
-
curl -fsSL "$BASE/examples/simple-todo/$f" \
|
|
208
|
-
-o ~/.claude/skills/dforge-mcp-author/examples/simple-todo/$f
|
|
209
|
-
done
|
|
210
|
-
# … entity, ui, security, seed-data files follow the same pattern
|
|
211
|
-
|
|
212
|
-
# Or, straight from GitHub main (always fresh, but pre-release content):
|
|
213
|
-
# curl -fsSL https://raw.githubusercontent.com/dforge-core/dforge-mcp/main/skills/dforge-mcp-author/SKILL.md \
|
|
214
|
-
# -o ~/.claude/skills/dforge-mcp-author/SKILL.md
|
|
236
|
+
DEST=/path/to/skills npm run install-skills
|
|
215
237
|
```
|
|
216
238
|
|
|
217
|
-
>
|
|
239
|
+
<details>
|
|
240
|
+
<summary>Windows notes</summary>
|
|
241
|
+
|
|
242
|
+
- **cmd.exe / PowerShell**: `npm run install-skills` works directly. There is no bash requirement.
|
|
243
|
+
- **WSL**: run it from *Windows*, not inside WSL — inside WSL, `os.homedir()` is the Linux home (`/home/you`), so the skills would land where a Windows Claude Code never looks. If you deliberately run Claude Code inside WSL, then installing from WSL is correct.
|
|
244
|
+
- `--from-npm` shells out to `tar`, built into Windows 10 1803+ (and macOS/Linux). Without it, clone the repo and run the installer without `--from-npm`.
|
|
245
|
+
- `scripts/install-skills.sh` still exists and works (it just execs the Node script), so the older `curl … | bash` one-liner keeps working on macOS/Linux/Git Bash.
|
|
246
|
+
|
|
247
|
+
</details>
|
|
218
248
|
|
|
219
|
-
|
|
249
|
+
It replaces each skill directory wholesale — a stale reference file left behind is worse than a missing one, because the agent will happily author against it.
|
|
250
|
+
|
|
251
|
+
**Re-run after every dforge-mcp upgrade.** The skill version isn't checked at runtime, so stale skills against new tools will misroute calls.
|
|
252
|
+
|
|
253
|
+
> **Note on CLAUDE.md:** Every module gets a `CLAUDE.md` in its root, authored during Phase 0a (the AI drafts it; you write it) and kept current as later phases complete. It tells Claude Code that the directory is a dForge module, points at the skills, describes the module layout, and carries a live **Module status** tracker so future sessions resume accurately.
|
|
220
254
|
|
|
221
255
|
The phases:
|
|
222
256
|
|
|
223
|
-
| Phase | Required? | Tools used |
|
|
224
|
-
|
|
225
|
-
| 0. Identity / requirements / design / validation | yes |
|
|
226
|
-
| 1. Domain | yes | `module_create`, `entity_add`, `entity_field_
|
|
227
|
-
| 2.
|
|
228
|
-
| 3. Views +
|
|
229
|
-
| 4. Polish
|
|
230
|
-
| 5. Security |
|
|
231
|
-
| 6. Verify | yes | `module_pack`, `module_install` |
|
|
232
|
-
|
|
233
|
-
Key principles encoded in the
|
|
257
|
+
| Phase | Required? | Skill | Tools used |
|
|
258
|
+
|---|---|---|---|
|
|
259
|
+
| 0. Identity / requirements / design / validation | yes | design | `module_plan` |
|
|
260
|
+
| 1. Domain | yes | build | `module_create`, `entity_add`, `entity_field_*`, `entity_reference_add`, `entity_rollup_add`, `entity_status_add`, `module_import`, `dbml_import` |
|
|
261
|
+
| 2. Behavior | optional | build | `action_add`, `action_check`, `trigger_add`, `job_add`, `webhook_add` |
|
|
262
|
+
| 3. Views + menus, reports | 3a yes, rest optional | build | `view_*`, `menu_add`, `report_add` |
|
|
263
|
+
| 4. Polish | optional | build | `setting_add`, `translation_sync`, `seed_add` |
|
|
264
|
+
| 5. Security | 5a yes, folders optional | build | `role_add`, `role_right_set`, `folder_add` |
|
|
265
|
+
| 6. Verify | yes | ship | `module_validate`, `module_pack`, `module_install` |
|
|
266
|
+
|
|
267
|
+
Key principles encoded in the skills: inspect-before-patch, one-at-a-time, composite-tools-first, deterministic backtrack on the earliest-phase-first rule, a tool-failure protocol that distinguishes auth/connectivity from module defects, and user-driven end-of-session cleanup.
|
|
234
268
|
|
|
235
269
|
## For maintainers
|
|
236
270
|
|