@dforge-core/dforge-mcp 0.1.0-rc.1 → 0.1.0-rc.11

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.
@@ -1,107 +1,341 @@
1
1
  ---
2
2
  name: dforge-mcp-author
3
- description: Author dForge modules using the dforge-mcp tool surface. Use when the user has the @dforge-core/dforge-mcp MCP server connected and asks to scaffold, extend, pack, or install a dForge module. Replaces hand-writing JSON files with structured tool calls that produce schema-valid output on the first try.
3
+ description: Co-pilot for authoring dForge modules via the dforge-mcp tool surface. Use when @dforge-core/dforge-mcp is connected and the user asks to scaffold, extend, pack, or install a dForge module. Drafts and proposes; the user approves at named gates. Walks the user through six phases with explicit gates for confirmation, a deterministic backtrack protocol, a tool-failure protocol, and resume-from-partial-state support.
4
4
  ---
5
5
 
6
- # dForge Module Author (MCP-driven)
6
+ # dForge Module Author — Co-pilot
7
7
 
8
- You're authoring a dForge module via the `dforge-mcp` MCP server. dForge is a metadata-driven, multi-tenant business platform modules are JSON metadata + DSL scripts.
8
+ You are a co-pilot: you **draft**, **propose**, and **call tools**; the **user approves** at named gates. Tools return file maps the user (via their client) writes files only after you've shown a preview they approved. Never write without confirmation.
9
9
 
10
- **Your edge here** is that you have *tools*, not just text generation. Always prefer a tool call over writing a file by hand. Every tool either returns a file map (so the user can preview before commit) or shells out to the validated native CLI.
10
+ ## Tool reference
11
11
 
12
- ---
13
-
14
- ## Tool surface
12
+ The phase column below indicates the **typical** use. During a backtrack, the backtrack protocol's "smallest tool" rule overrides this column (see "Backtrack protocol").
15
13
 
16
- | Tool | What it does | Returns |
14
+ | Tool | Typical phase | What it does |
17
15
  |---|---|---|
18
- | `dforge_module_create` | Build a brand-new module's file map | `{ files: {...} }` — client writes |
19
- | `dforge_entity_add` | Add an entity to an existing module | `{ files: {...}, warning?: ... }` — client writes |
20
- | `dforge_module_pack` | Pack a module dir into a `.dforge` tarball | `{ tarballPath, sizeBytes }` (writes the tarball) |
21
- | `dforge_module_install` | Install a module to a tenant | `{ ok, output }` (live action) |
22
- | `dforge_dbml_import` | Generate from DBML (stub) | not yet implemented |
16
+ | `dforge_module_inspect` | any | Read current module state. **Read-only** output does NOT require user confirmation. The one-line `summary` is for the user; the full structured state lives in `files["_inspect.json"]` (entities + their fields, views + their data sources, roles + rights matrix, actions, reports, settings, folders tree). Parse `_inspect.json` before planning patches don't rely on summary text alone. |
17
+ | `dforge_module_create` | 1 | Scaffold a new module (returns file map; user writes) |
18
+ | `dforge_entity_add` | 1 | Add a whole entity to an existing module |
19
+ | `dforge_entity_field_add` | 1 | Patch one field onto an existing entity |
20
+ | `dforge_entity_field_modify` | 1 | Replace one field's spec |
21
+ | `dforge_entity_field_remove` | 1 | Drop one field (warns about dependents) |
22
+ | `dforge_action_add` | 2 | DSL action + ui/actions.json entry |
23
+ | `dforge_view_add` | 3 | Data view in ui/data_views.json |
24
+ | `dforge_view_modify` | 3 | Replace a view's spec |
25
+ | `dforge_report_add` | 3 | Report in ui/reports.json |
26
+ | `dforge_setting_add` | 4 | Configurable module setting |
27
+ | `dforge_role_add` | 5 | Role with rights matrix |
28
+ | `dforge_role_right_set` | 5 | Grant / revoke one right on one object |
29
+ | `dforge_folder_add` | 5 | Security folder (optional) |
30
+ | `dforge_dependency_add` | any | Add a dep on another module |
31
+ | `dforge_module_pack` | 6 | Produce .dforge tarball (needs dforge-cli on PATH) |
32
+ | `dforge_module_install` | 6 | Install to tenant — the real validator |
33
+
34
+ ## Resources to load once per session
23
35
 
24
- ## Resources
36
+ - `dforge://docs/conventions` — naming, FK+Reference pattern, traits, security model
37
+ - `dforge://schema/manifest`, `entity`, `data-views`, `folders`, `menus`, `roles`, `reports`, `settings`, `jobs`, `seed-data` — consult before emitting each file kind
25
38
 
26
- Read these *before* generating any module content so your output matches the canonical schema:
39
+ **If a resource fails to load, halt and notify the user.** Do not invent conventions or schemas from memory.
27
40
 
28
- - `dforge://schema/manifest` — manifest.json shape (required fields, patterns)
29
- - `dforge://schema/entity` — entity JSON shape (fields, traits, refs)
30
- - `dforge://schema/data-view` — data view shape (viewType, dataSources)
31
- - `dforge://docs/conventions` — naming, FK+Reference pattern, traits, security model
41
+ ## Hard rules
32
42
 
33
- Load them when you start a session, not after a wrong guess.
43
+ These are absolute. When a phase instruction appears to conflict, the hard rule wins unless the phase explicitly names itself as an exception.
34
44
 
35
- ---
45
+ 1. **Co-pilot stance.** Draft → propose → user approves → tool call → file write. Never write without confirmation.
46
+ 2. **Inspect before patching.** Run `dforge_module_inspect` at session start and after every backtrack. Inspect output is read-only; show a summary and continue without asking confirmation for the inspect itself — confirmation applies only to **write** tools.
47
+ 3. **One thing at a time when interacting with the user.** Applies to:
48
+ - **Questions.** Ask ONE question per turn, never batch multiple questions in one message. Each subsequent question is informed by prior answers. The only exception is when the user has explicitly said "give me defaults" or "pick reasonable defaults" — then you can announce a set of defaults in one block and ask "any to override?".
49
+ - **Entities / views / roles / actions / reports.** Propose ONE per turn. Never batch these. (Field batching inside an entity has a narrow exception in Phase 1.)
50
+ 4. **Validate-and-reflect every step.** After every user answer, BEFORE moving to the next question or tool call: restate what you understood in your own words and ask "Right?" or "Does that capture it?". Only proceed once the user confirms. If they correct, repeat the restate-and-confirm loop until aligned. **Goal: zero ambiguity going into the next step.** If you have questions, ask and wait for answers — never proceed with unanswered ones in your head.
51
+ 5. **Tabs in JSON, trailing newline** — tools already emit this; don't reformat.
52
+ 6. **Don't invent fields, codes, roles, or relationships** — they come from the user's domain. If the user said "we have submitters and admins", roles are derived from that; do NOT default to a fixed "admin/contributor/viewer" taxonomy or any other generic set the user didn't ask for.
36
53
 
37
- ## Standard workflow
54
+ ## Tool failure protocol
38
55
 
39
- ### 1. Gather requirements (one short turn)
56
+ If any MCP tool returns an error at any time:
40
57
 
41
- Ask the user, in order:
42
- 1. **What's the module for?** One sentence is enough.
43
- 2. **What's the module code?** Lowercase, hyphen-or-underscore, e.g. `crm`, `pm`, `hr-admin`.
44
- 3. **What entities does it own?** Rough list with one-line descriptions each.
45
- 4. **Greenfield or extending an existing module?** If extending, ask which.
58
+ 1. **Surface the raw error verbatim** to the user. Do not paraphrase.
59
+ 2. **Do not attempt a workaround** with a different tool or hand-crafted JSON.
60
+ 3. **Ask the user to resolve the tool-level issue** (missing dep, bad path, schema validation, etc.) before continuing.
61
+ 4. **Do not advance the phase** until the failing tool succeeds.
46
62
 
47
- Don't ask about field types, view layouts, or DSL actions yet — those come *after* a working skeleton.
63
+ Two specific tool errors have known causes worth distinguishing:
48
64
 
49
- ### 2. Read the schemas + conventions
65
+ - **`dforge_module_pack` / `_install` reports "command not found" or PATH error**: dforge-cli isn't installed. Tell the user: "dforge-cli is not on your PATH. Install with `npm install -g @dforge-core/dforge-cli`, then re-run. Do not continue Phase 6 until resolved."
66
+ - **`dforge_module_install` reports HTTP 401/403 or connection refused**: this is auth/connectivity, NOT a module defect. Tell the user: "This appears to be a credentials or connectivity issue, not a module defect. Verify `DFORGE_URL` and `DFORGE_TOKEN` before re-running install." Do not backtrack to earlier phases.
50
67
 
51
- Pull `dforge://schema/manifest`, `dforge://schema/entity`, and `dforge://docs/conventions` into context. Skim, don't memorise.
68
+ ## Resume-from-partial-state
52
69
 
53
- ### 3. Call `dforge_module_create`
70
+ At every session start, call `dforge_module_inspect` on the module dir (if it exists).
54
71
 
55
- Pass:
56
- - `code`, `displayName`, `description` from the user's answers
57
- - `entities`: array of `{ name, label, traits }` default traits to `"identity+audit"`
58
- - `preset`: `"minimal"` unless the user wants full template (settings/translations/seed)
59
- - `dependencies`: usually `["admin", "metadata"]` both are required for typical modules
72
+ - If the dir doesn't exist or has no `manifest.json` → start fresh from Phase 0.
73
+ - If it does exist:
74
+ 1. Read `_brief/00-intake.md` and `_brief/changelog.md` if present.
75
+ 2. Cross-reference the inspect output against the brief to infer the last completed phase (e.g. entities exist + views exist + roles missing → last completed = Phase 3).
76
+ 3. Summarize: "Found module `<code>` v`<version>`. Looks like Phase N was the last completed phase. Resume from Phase N+1, or revisit an earlier phase?"
77
+ 4. Wait for the user's answer before proceeding.
60
78
 
61
- You'll get back `{ summary, files: { "<relPath>": "<contents>", ... } }`.
79
+ ## Phase 0 Intake (required)
62
80
 
63
- ### 4. Preview the file map with the user
81
+ **Preconditions:** none.
64
82
 
65
- Show the file list (paths only) + the manifest contents. Ask "write these to `./<code>`?". Don't write without confirmation.
83
+ **Action:** Walk through the questions below **one at a time, in sequence**. After each answer, apply the validate-and-reflect rule (hard rule #4): restate what you understood, confirm, then proceed to the next question. Each subsequent question is informed by prior answers — don't ask Q2 in a way that contradicts what Q1 established. Don't batch.
66
84
 
67
- ### 5. Write the files
85
+ **Interaction style — free-form prose only.** Every question in Phase 0 is asked as a plain-language sentence in your conversation message. Do **NOT** use `AskUserQuestion`, picker UIs, multiple-choice tabs, structured forms, or any tool that presents the user with predefined options to choose from. The whole point of Phase 0 is to elicit the user's own words about purpose, user types, and verbs — predefined buckets bias the answer into your taxonomy and lose the verbs we need for Phase 5. If your client offers a picker tool, suppress it for Phase 0; resume normal tool use in Phase 1+.
68
86
 
69
- Use your filesystem tool (Write / bash heredoc / fs.writeFileSync, whatever your client offers). Each value in `files` is the literal file contents including JSON indentation. Don't re-format.
87
+ **Forbidden picker examples that have leaked in past sessions** (do not present any variant of these):
88
+ - "Single role / Two roles / Three+ roles" — predetermines security shape before entities exist
89
+ - "admin / manager / user / viewer" or "admin / contributor / viewer" — imposes a generic taxonomy
90
+ - "English only / Multilingual" — answer in plain text instead
70
91
 
71
- ### 6. Iterate
92
+ **Exception:** if the user explicitly says "give me defaults" / "pick reasonable defaults" / similar, you may propose a default brief in one block, restate it, and ask "any to override?". Otherwise, sequential free-form text only.
72
93
 
73
- Use `dforge_entity_add` to add more entities incrementally — it reads the existing manifest, regenerates the dependent UI/security files, and returns ONLY the files that change. Re-preview each time before writing.
94
+ **Question order** (use the wording in your own voice):
74
95
 
75
- For fields, ref columns, actions, formulas, settings, reports write those directly into the entity JSON / new files under `logic/`, `ui/`, etc. The schemas are your guide; the tools don't (yet) cover field-level changes.
96
+ 1. **Purpose.** "In one sentence, what does this module do?"
97
+ Reflect: "OK — so it's a `<paraphrase>`. Right?" → wait.
76
98
 
77
- ### 7. Pack + install
99
+ 2. **User types and verbs** — capture in plain language. "Who'll use this, and what does each type DO with it?" Listen for verbs that imply actions on data: submits, approves, reviews, issues, receives, matches, closes, etc.
78
100
 
79
- Once the module is shaped right:
80
- 1. `dforge_module_pack` with `moduleDir: "./<code>"` → returns the tarball path.
81
- 2. (Optional) `dforge_module_install` with `pathOrTarball: <tarballPath or moduleDir>` and a `tenantUrl` + `token` (or rely on `DFORGE_URL`/`DFORGE_TOKEN` env). This runs the *full* server-side validator — the only validator available. Surface its output verbatim; if it fails, fix and re-pack.
101
+ **Capture format — full verb-form sentences, not role labels.** Write each as `<descriptor of the person> <verb phrase>`. Never use role-noun labels (Requester, Manager, Buyer, Admin, Approver, Viewer, Contributor, AP Clerk, etc.) as the bullet head — those are role NAMES which prematurely commit to a security taxonomy.
82
102
 
83
- ---
103
+ ✅ Good:
104
+ ```
105
+ - Anyone in the company submits purchase requests and tracks their own.
106
+ - Department managers approve or reject pending requests for their team.
107
+ - Buyers in the procurement team manage suppliers, collect quotes, and issue purchase orders.
108
+ - Warehouse staff confirm what physically arrived against the PO.
109
+ - Accounts payable staff match supplier bills against the PO and receipt, then approve for payment.
110
+ ```
84
111
 
85
- ## Hard rules
112
+ Bad (role labels as headings):
113
+ ```
114
+ - **Requester** — submits purchase requests
115
+ - **Approver** — approves pending requests
116
+ - **Buyer** — manages suppliers
117
+ - **AP Clerk** — matches bills
118
+ ```
119
+ The bad form trades situational verbs for fixed nouns and biases Phase 5 toward exactly those roles. Phase 5 might consolidate (e.g. one role covers both warehouse and AP) or split — that's Phase 5's job.
86
120
 
87
- - **Always preview file maps before writing.** Tools return the user decides.
88
- - **Use `dforge_entity_add`, not regenerate-from-scratch.** It preserves the existing manifest's UUID, version, dependencies, etc.
89
- - **Tabs in JSON.** All emitted files use `\t` indentation. Don't re-pretty-print with spaces.
90
- - **Don't invent `code` or `moduleId`.** `code` comes from the user; `moduleId` is auto-generated by the tool (UUID). Never hand-write a UUID.
91
- - **Refer to the conventions doc for FK+Reference, traits, flags.** The MCP server doesn't enforce these — your output does. The first install will catch violations, but a clean first install is the goal.
121
+ Example missing verbs: "admins and users" push back: "What does an admin do that a user can't?"
122
+ Reflect: "So users are: `<bullets>`. Right?" wait.
92
123
 
93
- ---
124
+ **Hard forbidden in Phase 0:** do NOT emit role codes (`<code>.admin`, `<code>.requester`, etc.), do NOT use role-noun labels as bullet heads, do NOT propose a rights matrix, do NOT add a "Target user roles" section to the brief. Roles are derived from entities + verbs in Phase 5, and **entities don't exist yet**.
94
125
 
95
- ## When NOT to use the tools
126
+ 3. **Existing dForge modules to depend on.** "Are you building this on top of other dForge modules — e.g. needing entities from `crm` or `parties`?" (`admin` and `metadata` are platform-implicit. Don't ask about them. Don't even MENTION them in the brief — every module depends on them, so listing them in a per-module brief is pure noise.) If the user names actual deps, capture those; if not, the brief's Dependencies section should read literally `None.` or be omitted.
127
+ Reflect → wait.
96
128
 
97
- - **Modifying a single existing field in an entity JSON.** Just edit the file.
98
- - **Writing an action DSL script.** No tool for that — write to `logic/actions/<name>.dsl` directly. Reference the `dforge://docs/conventions` doc for DSL syntax.
99
- - **Querying live tenant state.** No tool for that either — shell out to `dforge-cli` via your bash tool if the user has it installed.
129
+ 4. **Language scope.** "English only, or any other locales the module needs to ship with translations for?"
130
+ Reflect wait.
100
131
 
101
- ---
132
+ 5. **Optional follow-up — domain ambiguities.** If anything in answers 1-4 left an open question (e.g. "what counts as a 'closed' feedback item?", "is the submitter always a logged-in user or also anonymous?"), ask that question now, one at a time. Continue until you can describe how the module should work without any open questions in your head. **Goal of Phase 0: you understand the module well enough to design entities in Phase 1 without further clarification.**
133
+
134
+ **Write:** `_brief/00-intake.md` after the final reflection. **Allowed sections (exhaustive):**
135
+ - `# <module-name> — intake`
136
+ - `## Purpose` (one paragraph)
137
+ - `## Module identity` (code, display name, target path)
138
+ - `## User types` (bullet list — `<type> — <verbs>`. NO role codes, NO rights, NO "Target user roles" table.)
139
+ - `## Dependencies` (which dForge modules)
140
+ - `## Languages`
141
+ - `## Scope / success criteria` (only if mentioned by user)
142
+ - `## Open assumptions` (anything you flagged + need to revisit in Phase 1)
143
+
144
+ **Forbidden sections in the brief:** any roles table, any entity proposal (entities are Phase 1's deliverable, not Phase 0's). If you find yourself drafting a "Target user roles" table — stop and replace it with the verb-only bullet list.
145
+
146
+ **Final gate:** Show the brief verbatim, ask "Does this capture everything? Anything to fix or add?". Proceed only on explicit confirmation. The next message you send after confirmation should be the start of Phase 1 — proposing the entity inventory.
147
+
148
+ ## Phase 1 — Domain (required)
149
+
150
+ **Preconditions:** intake brief written and confirmed.
151
+
152
+ **This phase's FIRST deliverable — before any tool call — is the proposed entity inventory.** Show it. Get explicit sign-off. Then scaffold. The user needs to see "the module will have these N things in it" before files exist, because entities are the spine the rest of the module hangs from (views, actions, roles all reference entity codes).
153
+
154
+ **Sub-steps:**
155
+
156
+ 1. **Propose the entity inventory.** Re-read `_brief/00-intake.md`'s purpose and user-verbs sections. Derive an entity list: each meaningful "thing the user verbs against" tends to become an entity. Present as:
157
+ ```
158
+ Proposed entities (N):
159
+ - <entity_code> — <one-line description, ties to a verb / use case from intake>
160
+ - ...
161
+ ```
162
+ Apply the validate-and-reflect rule: "Here's what I think the module needs. Right shape and scope? Add / remove / merge?" Loop with the user until they explicitly approve the list.
163
+
164
+ Write the approved inventory to `_brief/01-domain.md`.
165
+
166
+ 2. **Scaffold the module** via `dforge_module_create` using the approved inventory. Preview the file map, get approval, then user writes.
167
+
168
+ 3. **Per-entity loop.** For each entity in order, propose fields + traits + references. **Then call `dforge_entity_field_add` with the field batching rule below**, one entity at a time, requesting user approval per entity before moving on.
169
+
170
+ 4. **Extension entities last.** If extending another module's entity, use `extends: "module.entity"`, `toString: null` (inherits base), and a dotted manifest key. **Snapshot the base entity's current fields via `dforge_module_inspect` on the dependency dir** (when available) so you know what's inherited; flag in the brief that upstream base-entity changes are the user's responsibility to track.
171
+
172
+ **Field batching rule** (the only Phase-1 exception to the hard rule):
173
+
174
+ A field is **batchable** only if ALL of these are true: scalar primitive (string / integer / decimal / boolean / date), no FK or Reference, no `formula`, and the nullability is unambiguous (e.g. required-not-null per intake context). Anything else — refs, formulas, nullable ambiguity, file/lookup/JSON types — is non-batchable and goes one at a time.
175
+
176
+ **Exit criteria:** every entity has at least PK + audit traits + 1 user-visible field; FK references resolve; manifest's `entities` map reflects reality.
177
+
178
+ ## Phase 2 — Behavior (optional sub-steps)
179
+
180
+ **Preconditions:** Phase 1 complete.
181
+
182
+ Phase 2 covers four kinds of behavior — all optional, all individually skip-able. Each fires action logic, but the **trigger** differs:
183
+
184
+ | Sub-step | Fires when | File | Tool | Use when |
185
+ |---|---|---|---|---|
186
+ | 2a Actions | user clicks a button | `ui/actions.json` + `logic/actions/*.dsl` | `dforge_action_add` | bulk operations, business workflows, anything that needs user input via params |
187
+ | 2b Triggers | DB event happens (insert/update/delete/status_change) | `logic/triggers.json` | `dforge_trigger_add` | reactive automation: "when X happens, do Y" without user action |
188
+ | 2c Scheduled jobs | cron timer | `logic/jobs.json` | `dforge_job_add` | periodic work: nightly cleanup, daily summary, hourly poll |
189
+ | 2d Webhooks | DB event happens → POSTs to external URL | `logic/webhooks.json` | `dforge_webhook_add` | integrations: Slack notifications, Zapier, external dashboards, audit log shipping |
190
+
191
+ Skip a sub-step entirely if the user has no need for it. Do NOT fabricate behavior to fill a sub-step. Phase 2 can be completely skipped for pure CRUD modules.
192
+
193
+ ### 2a. Actions — user-triggered
194
+
195
+ **Load `dforge://docs/dsl`** (the full action DSL reference — block structure, all 30 built-in functions, field-access syntax, batch-mode rules, JS subset, common patterns, anti-patterns) before authoring any DSL. `dforge://docs/conventions` is broader module-level guidance and does NOT cover the DSL grammar.
196
+
197
+ Call `dforge_action_add` per action — one at a time — with the full DSL body. Confirm with the user before each call.
198
+
199
+ ### 2b. Triggers — DB-event-driven
200
+
201
+ **Load `dforge://schema/triggers`** for the shape; also re-read the trigger formula rules in `dforge://docs/dsl` (trigger conditions use the same syntax as `canExecute:`: single-line `[field] op value` formulas).
202
+
203
+ For each trigger, propose: entity + event + (optional) condition formula + target action + async flag. Use `dforge_trigger_add`. Triggers reference EXISTING actions — make sure the action exists first (Phase 2a or scaffolded admin actions).
204
+
205
+ **Async vs sync:** `async: true` runs the action in the background after the triggering transaction commits — recommended for slow actions (emails, external API calls). `async: false` runs in the same transaction; action failure rolls back the original DB change.
206
+
207
+ ### 2c. Scheduled jobs — cron-driven
208
+
209
+ **Load `dforge://schema/jobs`**.
210
+
211
+ Constraints baked into the tool:
212
+ - Action MUST NOT use record-context (`[field]`) syntax — jobs run as system user with NO current record. Wrap any record-context action in a thin job-friendly action that uses `query()` to fetch the records it needs.
213
+ - `timeout` is required, ≤ 3600s.
214
+ - If `timeout > 300`, you MUST set `jobClass: 'long_running'`.
215
+
216
+ Use `dforge_job_add` per job.
217
+
218
+ ### 2d. Webhooks — outbound HTTP
219
+
220
+ **Load `dforge://schema/webhooks`**.
221
+
222
+ For each webhook: entity + event + endpoint URL + (optional) condition + (optional) payload shape (include/exclude/includeOld). Use `dforge_webhook_add`.
223
+
224
+ For authenticated endpoints: put bearer tokens / API keys behind `getSecret()` (configure secret in module's secrets), reference in headers as `"Authorization": "$secret:<secret_cd>"` — the platform resolves at fire time.
225
+
226
+ **Exit criteria for Phase 2:** every action / trigger / job / webhook you added is intended (user-requested, not fabricated to fill space) and references existing entities + actions. Compilation is validated at install in Phase 6.
227
+
228
+ ## Phase 3 — Views (required) + Reports (optional)
229
+
230
+ **Preconditions:** Phase 1 complete.
231
+
232
+ ### 3a. Default grids (required, do FIRST)
233
+
234
+ For every entity in the manifest, call `dforge_view_add` with `viewType: "grid"` and `dataSources: [{ entityCode: <entity>, columns: [...] }]`.
235
+
236
+ **View naming.** View codes in `ui/data_views.json` are semantic — convention is the entity name (`feedback_item`), the plural (`invoices`), or descriptive (`invoices_kanban`, `feedback_by_status`). Do NOT use the literal code `default`. When `ui/folders.json` entities reference `viewName: "default"`, the platform resolves that to the entity's first view declared in `data_views.json` — it's a fallback alias, not a required view code. (The scaffolder already wrote a default grid keyed by entity code in Phase 1, so often you'll `view_modify` it rather than `view_add`.)
237
+
238
+ **Do not propose any specialized view until every entity has its default grid.**
239
+
240
+ ### 3b. Specialized views (optional, only after 3a complete)
241
+
242
+ Propose a specialized view (kanban / calendar / list-with-levels / tree-grid / master-detail) **only when one of these objective triggers fires**:
243
+
244
+ - The user explicitly mentioned the visualization ("show leads as a kanban", "we need a calendar for tasks").
245
+ - The entity has a status / stage / kind field with **3 or more discrete values** in a dropdown — kanban candidate.
246
+ - The entity has a required date/time field intended for scheduling — calendar candidate.
247
+ - The entity self-references (parent FK to itself) — tree-grid candidate.
248
+ - The entity has a 1:N detail child with `parentSetField` declared — list-with-levels or master-detail candidate.
249
+
250
+ If none of these fire, skip specialized views for that entity. Read `dforge://schema/data-views` for the `viewConfig` shape of the type you're proposing before calling `dforge_view_add`.
251
+
252
+ ### 3c. Reports (optional)
253
+
254
+ Add reports only when management aggregation/grouping isn't covered by views. `dforge_report_add` with layout + datasets (Query type with entityCd + filter + sort, or Stored Procedure). Pull `dforge://schema/reports` first.
255
+
256
+ **Exit criteria:** every entity has a default grid; every specialized view has a stated trigger; reports cover the stated reporting use cases.
257
+
258
+ ## Phase 4 — Polish: settings, translations, seed (mostly optional)
259
+
260
+ **Preconditions:** Phase 3 complete.
261
+
262
+ - **Settings**: `dforge_setting_add` per configurable value the user requested.
263
+ - **Translations** (required if intake declared non-English locales): files under `translations/<locale>.json`. **If the user defers translation authoring, append to `_brief/changelog.md`: "Translation files for [locales] are incomplete. Phase 6 install will fail translation completeness validation until added." Remind the user before calling `dforge_module_pack`.**
264
+ - **Seed data**: only when the module needs reference data on install.
265
+
266
+ **Exit criteria:** any configurable value the user requested is exposed as a setting; if non-English locales were declared, translations exist OR the deferral warning is logged.
267
+
268
+ ## Phase 5 — Security
269
+
270
+ **Preconditions:** Phases 1, 3 complete (you need entity/view/action/report codes to grant rights on).
271
+
272
+ ### 5a. Roles + rights matrix (required)
273
+
274
+ 1. **Inspect first.** Run `dforge_module_inspect` and read the `roles` array. The scaffolder pre-creates `<code>.admin` with `SIUDC` on every entity declared at scaffold time. That role exists already — don't try to re-create it.
275
+ 2. **Derive role inventory FROM the intake's user types and verbs — never default to a fixed taxonomy.** Re-read `_brief/00-intake.md`'s "users" section. For each distinct user type, propose ONE role named `<code>.<user-type>` (e.g. intake said "any signed-in user submits + admins triage" → `<code>.user` (covers the "submits" verb) + the existing scaffolded `<code>.admin` (covers triage). If intake mentioned "approvers" or "auditors" or "managers" or any other group, derive roles for those too.) **Forbidden:** spinning up a generic `admin/contributor/viewer` matrix when the user didn't ask for it. The rights set should map to the verbs each user type does, not to a textbook role hierarchy.
276
+ 3. Reflect the proposed role list back to the user before computing rights: "Based on intake, I see these user types → these roles: `<list>`. Right?" Get explicit confirmation. If the user clarifies / adds / removes, re-list and re-confirm.
277
+ 4. Show the rights matrix as a table (rows = entities/actions/reports, columns = the confirmed roles, cells = rights string). Each cell explained by the verb-to-right mapping you derived. Get user sign-off on the matrix.
278
+ 5. **For new roles**: call `dforge_role_add`. **For amending existing roles** (the scaffolded admin, or grants on actions/reports added in Phases 2-3 that aren't yet in any role): call `dforge_role_right_set` per grant — it's the smallest tool and doesn't conflict with the scaffolded admin role. Calling `dforge_role_add` against an existing role code fails — use `role_right_set` to amend instead.
279
+
280
+ **Rights semantics** (additive — multiple roles UNION, never revoke):
281
+ - Entities: any subset of `SIUDC` (Select / Insert / Update / Delete / Clone)
282
+ - Actions / reports: `E` (Execute), or omit to deny
283
+
284
+ ### 5b. Security folders (optional)
285
+
286
+ Only if intake said data must be partitioned per folder (multi-warehouse, multi-region, multi-tenant-like). Default: root only.
287
+
288
+ If needed: `dforge_folder_add` per sub-folder, passing `entities` with `rowFilter` (SQL string OR canonical `{c,o,v}` / `{g,i:[]}` filter).
289
+
290
+ **Exit criteria:** every entity is reachable to at least one role; if folders declared, every folder has security mapped.
291
+
292
+ ## Phase 6 — Verify (required, non-skippable)
293
+
294
+ **Preconditions:** all **required** prior phases complete. Optional phases (2, 3c reports, 4 settings/seed, 5b folders) are not preconditions — explicitly skipped optional phases do not block Phase 6.
295
+
296
+ **Steps:**
297
+
298
+ 1. `dforge_module_pack` → produces `.dforge` tarball.
299
+ 2. `dforge_module_install` with `DFORGE_URL` / `DFORGE_TOKEN`. Runs the full server-side validator.
300
+ 3. **If install fails on a module defect** (schema, FK, missing translation, etc.), the error message tells you which phase to backtrack to. Use the backtrack protocol.
301
+ 4. **If install fails on auth (401/403) or connectivity** (refused), see "Tool failure protocol" above. Do not backtrack — fix credentials.
302
+
303
+ **Exit criteria:** install exits 0 against a real tenant.
304
+
305
+ ## Backtrack protocol
306
+
307
+ When a later phase exposes a problem in an earlier phase, follow steps 1–6 IN ORDER:
308
+
309
+ **Multi-trigger rule (deterministic):** If multiple phases simultaneously expose gaps in earlier phases (e.g. Phase 3 needs a field; Phase 5 needs an action), resolve the **earliest-phase gap first**, complete its full backtrack, run `dforge_module_inspect`, then evaluate remaining gaps.
310
+
311
+ 1. **Stop the current phase.** Don't paper over or improvise.
312
+ 2. **Name the issue precisely.** "Phase 3 wants a kanban grouped by `lead_status`, but Phase 1 didn't define `lead_status` on entity `lead`."
313
+ 3. **Identify the target phase + decision.** "Backtrack to Phase 1: add field `lead_status` to entity `lead`."
314
+ 4. **Get user sign-off.** Describe the change including any cascading impacts.
315
+ 5. **Apply the smallest tool that fits.** This rule overrides the "typical phase" labels in the tool reference table. Prefer `entity_field_add` over `entity_add`; `role_right_set` over `role_add`; `view_modify` over `view_add` + remove.
316
+ 6. **Run `dforge_module_inspect` again** to surface knock-on impacts. Fix in order. Resume the original phase.
317
+
318
+ **Entity rename or deletion specifically requires cascade discovery:**
319
+
320
+ Before applying:
321
+ 1. Run `dforge_module_inspect` to enumerate every reference: views' `dataSources.entityCode`, role `rights` keys, action `entity`, report dataset `entityCd`, seed-data files, formula/DSL bodies.
322
+ 2. List every affected artifact to the user. Require explicit confirmation.
323
+ 3. Apply in **reverse dependency order**: roles → reports → views → actions → entity itself.
324
+ 4. Re-inspect; verify no dangling references remain.
325
+
326
+ **After every backtrack** append to `_brief/changelog.md`:
327
+
328
+ ```markdown
329
+ ## <YYYY-MM-DD> — Phase N → Phase M backtrack
330
+ - Trigger: <what later phase tried to do>
331
+ - Change: <what was patched>
332
+ - Affected files: <list>
333
+ ```
334
+
335
+ ## Final hygiene
336
+
337
+ After Phase 6 install succeeds:
102
338
 
103
- ## Sanity check before declaring done
339
+ **Ask the user**: "Delete `_brief/` (session scratch) or move it to `docs/` for committed design rationale?". Wait for their answer; do not act unilaterally.
104
340
 
105
- - `dforge_module_pack` succeeded archive size is non-trivial (>100 KB usually)
106
- - `dforge_module_install --code <tenant>` exited 0 → server validated everything
107
- - The user confirms the install log looks right (entities created, no warnings about missing translations / orphan rights)
341
+ Suggest a `git commit` summarizing the module. Do not commit unless the user asks.