@saltcorn/copilot 0.8.1 → 0.8.3

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.
@@ -0,0 +1,829 @@
1
+ // Arrays of logical rules for the app constructor prompt system.
2
+ // Originals in prompts.js are kept intact; these will replace them in a future refactor.
3
+ // Join with "\n\n" to reproduce block-style sections.
4
+
5
+ const saltcorn_description = [
6
+ `This application will be implemented in Saltcorn, a database application development
7
+ environment.
8
+
9
+ Saltcorn applications contain the following entity types:`,
10
+
11
+ `* Tables: These are relational database tables and consist of fields of specified types
12
+ and rows with a value for each field. Fields optionally can be required and/or unique.
13
+ Every field has a name, which is an identifier that is valid in both JavaScript and SQL,
14
+ and a label, which is any short user-friendly string. Every table has a primary key
15
+ (composite primary keys are not supported) which by default is an auto-incrementing integer
16
+ with name \`id\` and label ID. The \`id\` primary key field is always unique and not-null by
17
+ definition — never set unique=true or not_null=true on it. Fields can also be of Key type
18
+ (foreign key) referencing a primary key in another table, or its own table for a self-join.
19
+ Tables can have calculated fields, which can be stored or non-stored. Both stored and
20
+ non-stored fields are defined by a JavaScript expression, but only stored fields can
21
+ reference other tables with join fields and aggregations.`,
22
+
23
+ `* Views: Views are elementary user interfaces into a database table. A view is defined by
24
+ applying a view template (also sometimes called a view pattern, the two are synonymous) to
25
+ a table with a certain configuration. The view template defines the fundamental relationship
26
+ between the UI and the table. For instance, the Show view template displays a single database
27
+ row, the Edit view template is a form that can create a new row or edit an existing row, the
28
+ List view template displays multiple rows in a grid. Views can embed views, for instance Show
29
+ can embed another row through a Key field relationship, or some views are defined by an
30
+ underlying view. For instance, the Feed view repeats an underlying view for multiple tables.
31
+ New viewtemplates are provided by plugin modules.`,
32
+
33
+ `* Triggers: Triggers connect elementary actions (provided by plugin modules) to either a
34
+ button in the user interface, or a periodic (hourly, daily etc) or table (for instance insert
35
+ on specific table) event. The elementary action each has a number of configuration fields
36
+ that must be filled in after connecting the action to an event, table or button.`,
37
+
38
+ `* Page: A page has static content but can also embed views for dynamic content. Pages can
39
+ be either defined by a Saltcorn layout, for pages that can be edited with drag and drop, or
40
+ by HTML for more flexible graphic designs. HTML pages should be used for landing pages.`,
41
+
42
+ `* Plugin modules: plugin modules can supply new field types, view templates or actions.
43
+ Before they can be used, they need to be installed. A plugin may also have a configuration
44
+ that sets options for that plugin. Layout themes in Saltcorn are plugin modules.`,
45
+ ];
46
+
47
+ const task_planning_rules = [
48
+ "The plan should focus on building views, triggers (including workflows) and pages.",
49
+
50
+ `Important trigger planning rules:
51
+ * When a task involves a simple field update (e.g. marking an item complete or incomplete),
52
+ plan it as a trigger using modify_row — NOT a workflow. Use a workflow only when multiple
53
+ steps, branching, or looping are genuinely required.
54
+ * If multiple independent single-step actions are needed (e.g. "mark complete" and
55
+ "mark incomplete"), describe them as separate triggers in the task description — do not
56
+ describe them as one combined workflow.
57
+ * Do NOT mention "navigate back" or "return to context" in trigger task descriptions.
58
+ Navigation is configured at the view level (GoBack button), not inside a trigger.
59
+ * If a trigger should be accessible as a button in a view, prefer two separate tasks:
60
+ (1) a task that creates the trigger, (2) a task that updates the existing view to add an
61
+ action segment with action_name set to the trigger's name — this second task must depend on
62
+ the first. Only combine them into one task when the view is being created for the first
63
+ time in the same plan (i.e. the view does not yet exist), in which case the single
64
+ view-creation task must also add the action button and depend on the trigger task.
65
+ * Do NOT plan any task that uses run_bash_script or executes shell commands. If a requirement
66
+ seems to need a shell command (e.g. file conversion, PDF generation, sending email), look
67
+ for a Saltcorn plugin or built-in action that covers it instead.
68
+ * Only reference a plugin when no built-in action, field type, or view template covers the
69
+ requirement. Inserting rows, updating fields, looping, computing aggregates, and running
70
+ conditional logic are all covered by built-in workflow steps — only reach for a plugin when
71
+ there is no built-in equivalent. For example, do NOT use the 'sql' plugin to insert rows
72
+ or compute totals — use built-in workflow steps instead.
73
+ * Do NOT plan any task that writes to a virtual (read-only) calculated field. Virtual fields
74
+ are computed automatically and cannot be stored — any trigger or workflow that tries to
75
+ update them will be refused. If you find yourself planning a trigger to keep a calculated
76
+ field "current", delete that task — the field already updates itself.`,
77
+
78
+ `Important existing-entity rules:
79
+ * MANDATORY pre-flight check: before writing any task, scan the already-implemented pages
80
+ list above. If the page you are about to plan is already in that list, DO NOT add it —
81
+ planning a task to create an existing page is always wrong. This check must happen for
82
+ every page task, no exceptions.
83
+ * Before planning any view or page task, check the list of already-implemented views and
84
+ pages above. If an existing view or page already covers the required functionality — even
85
+ under a slightly different name — do NOT create a new one. Reference the existing entity by
86
+ its exact name in dependent tasks.
87
+ * Never create a new view that is a renamed variant of an existing one (e.g. prefixing with
88
+ "my_", "user_", "filtered_"). If the existing view needs filtering for a specific context,
89
+ embed it as-is and describe the filtering in the embedding page or view task.
90
+ * For every role's required dashboard or key page, verify it is either in the existing pages
91
+ list or has a task planned for it. A requirement that mentions a dashboard or home screen
92
+ for a role and has no corresponding existing page MUST have a task.
93
+ * If a page was previously created under one name and a requirement refers to the same concept
94
+ under a different name, use the existing page's actual name — do not plan a second page for
95
+ the same purpose.`,
96
+
97
+ `Important view planning rules:
98
+ * Each task must create exactly one view. Never put two or more views in the same task. Edit,
99
+ Show, and List for the same table are always three separate tasks with three separate names,
100
+ descriptions, and dependencies.
101
+ * Do NOT plan separate tasks for "create" and "edit" on the same table. In Saltcorn, a single
102
+ Edit view handles both (no id = create, id present = edit). One task, one Edit view,
103
+ description says "create and edit".
104
+ * Edit, Show, and List views for a table always go together as three separate tasks. Whenever
105
+ you plan a List view AND a Show view for the same table, you MUST also plan an Edit view for
106
+ that table — a List without an Edit leaves users unable to create or modify records. Only
107
+ omit the Edit view when the requirements explicitly say the data is read-only.
108
+ * The three tasks must be ordered: Edit and Show first (independent of each other, in any
109
+ order), List last. The List task MUST list both the Edit task and the Show task in its
110
+ depends_on — without exception. If you plan a List that depends on neither, that is a bug
111
+ in the plan.
112
+ * Before finalising the plan, for every List view task, verify that its depends_on includes
113
+ the corresponding Edit task and the corresponding Show task (if they exist). If either is
114
+ missing, add it.
115
+ * When a List view links to a Show view or Edit view, the task description must say: "Add a
116
+ viewlink column to [view_name] for the current row" — not just "link each row". This wording
117
+ makes it unambiguous that a viewlink column must be added to the list for each target view.
118
+ * Every link or viewlink that targets a Show view MUST include the row's \`id\` as a URL query
119
+ parameter (e.g. \`?id={{id}}\`). A Show view with no \`id\` in the URL displays "No row
120
+ selected". This applies to viewlinks in List views, page links, and any other navigation
121
+ pointing at a Show view.
122
+ * Every List view task description must include a delete action column unless the table is
123
+ explicitly read-only. State it explicitly: "Add a delete action column."
124
+ * In general, if a view embeds or links to another view, the linked view's task must be listed
125
+ as a dependency.
126
+ * When a table has foreign key fields referencing the users table, the task description must
127
+ explicitly state for each one whether it is an ownership field (automatically set from the
128
+ logged-in user, omit from the form) or a selector field (the user picks a value, include a
129
+ selector in the form). Example: "user_id records the owner and is set automatically;
130
+ shared_with_user_id must have a user selector."
131
+ * For FK fields that represent a parent context (e.g. trip_id on packing_items), always
132
+ include the field as a normal selector in the Edit view form. Do NOT say to omit it.
133
+ Saltcorn automatically pre-fills the selector from the URL query parameter when the view is
134
+ opened from a parent context, and the user can select it manually when the view is used
135
+ standalone.
136
+ * NEVER omit a NOT NULL (required) FK field from the Edit view form unless it references the
137
+ users table directly AND it is being used as an ownership field. Any other required FK field
138
+ — including FKs to non-user tables even if they are "set by the system" — MUST be included
139
+ as a selector in the form. A required field omitted from the form with no mechanism to set
140
+ it will produce a NOT NULL database error on save. "Will be set automatically" is not a
141
+ valid plan unless the field directly references the users table.
142
+ * For every task that creates a view, include the exact view name in the task description.
143
+ View names must be lowercase, snake_case, unique across all tasks in the plan, and
144
+ descriptive enough to identify the table and purpose — for example 'packing_items_edit'
145
+ rather than just 'edit'.
146
+ * Do NOT plan an Edit view for any table whose description says it is auto-populated or not
147
+ editable by users (e.g. audit logs, import/export job tracking tables). These tables may
148
+ have List and Show views for read-only visibility, but never an Edit view.`,
149
+
150
+ `Important user account rules:
151
+ * The platform (Saltcorn) provides a built-in user account system with login, registration,
152
+ and session management. Do NOT plan any tasks for user registration, login pages, password
153
+ management, authentication flows, or email verification — these are already handled by the
154
+ platform. Users register at /auth/signup and log in at /auth/login.
155
+ * User identity is always available as the logged-in user. Ownership fields (FK to users) are
156
+ set automatically from the session; no custom logic is needed.
157
+ * If a requirement mentions "user accounts", "secure login", "saving data per user",
158
+ "user-specific data", or "sharing between users", treat it as already satisfied by the
159
+ platform's built-in user system. Do not generate any task in response to such a requirement.
160
+ * Do NOT create any Edit, Show, or List view whose underlying table is the built-in \`users\`
161
+ table. The users table is managed entirely by the platform — records are created via
162
+ /auth/signup and managed via the platform's built-in admin panel. Never plan a task that
163
+ creates a view on the users table.`,
164
+
165
+ `Important date field rules:
166
+ * When a view task includes a date field that should pre-fill to today, the task description
167
+ must say to use "default_now": true in the flatpickr configuration — never "default":
168
+ "today".`,
169
+
170
+ `Important role rules:
171
+ * Every view and page task description MUST state the min_role explicitly, e.g. "Set min_role
172
+ to admin (1)." or "Set min_role to user (80).". Never omit it.
173
+ * Role values: admin=1, staff=40, user=80, public=100. Use the value that matches who will
174
+ use the view or page — admin (1) only for views that admins exclusively need (system config,
175
+ user management); staff (40) for views used by internal employees who are not admins (e.g.
176
+ lawyers, agents, staff members); user (80) for views used by logged-in non-staff users
177
+ (e.g. clients, customers, members); public (100) only when the page must be accessible
178
+ without login. Do not default everything to admin — setting min_role too restrictively
179
+ locks out the intended users.`,
180
+
181
+ `Important dashboard rules:
182
+ * A dashboard page that shows aggregate statistics (totals, counts, revenue, etc.) must NEVER
183
+ use client-side JavaScript fetch stubs or placeholder values. Every stat card must be backed
184
+ by a real Saltcorn Statistic view embedded with an embed-view tag.
185
+ * For each statistic shown on a dashboard, plan a separate Statistic view task (e.g.
186
+ "total_billable_hours_stat", "revenue_by_client_stat"). The dashboard page task must list
187
+ all these Statistic view tasks in its depends_on.
188
+ * Statistic view tasks must be planned before the dashboard page task and have descriptive
189
+ names that make their metric clear.
190
+ * No list view may be left orphaned. Every list view planned in the phase must be reachable
191
+ from at least one dashboard or page — embedded directly or linked via a navigation section.
192
+ Check each list view and confirm it appears in at least one page or dashboard task's
193
+ description.`,
194
+
195
+ `Important home page rules:
196
+ * Every role should land on the right page after visiting /. Plan a single task "Set home
197
+ pages by role" that depends on all relevant page tasks and configures home_page_by_role for
198
+ every role in one step.
199
+ * Role IDs: public=100, user=80, staff=40, admin=1.
200
+ * Landing/marketing page (public-facing intro): min_role must be 100 (public). It MUST include
201
+ visible links to /auth/login (Log in) and /auth/signup (Create an account). Set as home for
202
+ role 100 (public).
203
+ * If there is an admin dashboard page, set it as home for role 1 (admin).
204
+ * If there is a dashboard or main page for regular users or staff, set it as home for role 80
205
+ (user) and/or role 40 (staff) as appropriate.
206
+ * The "Set home pages by role" task description must list every role→page mapping explicitly
207
+ using the exact page names planned in this task list, e.g.: "Set home_page_by_role: public
208
+ (100) → landing, user (80) → client_dashboard, staff (40) → staff_dashboard, admin (1) →
209
+ app_admin_dashboard." Never use "admin_dashboard" as a page name — it is reserved by the
210
+ platform.`,
211
+
212
+ `Important bulk import/export rules:
213
+ * A plain Edit view creates or edits a single record — it is NOT a bulk import tool. Never
214
+ plan an Edit view as a solution for bulk data import.
215
+ * List views have no built-in export feature — do not plan an export button or column as part
216
+ of a list view.
217
+ * Bulk import and export functionality (e.g. CSV) must always be placed on a dedicated
218
+ management or admin page as embedded views, using whatever import/export viewtemplate is
219
+ available from an installed plugin.
220
+ * Bulk import and bulk export for the same table are always two separate tasks with two
221
+ separate view names. Never combine them into a single task.`,
222
+
223
+ `Important plugin rules:
224
+ * If multiple plugins need to be installed, combine them ALL into a single task named
225
+ "Install plugins" that lists every required plugin name. Do NOT create a separate task per
226
+ plugin.`,
227
+
228
+ `Important dependency rules:
229
+ * Every name in a task's depends_on MUST exactly match the name field of another task in the
230
+ same plan_tasks call. Never reference a name that is not present in the tasks array — not a
231
+ concept, not a table name, not a made-up label. If you find yourself writing a depends_on
232
+ entry whose name does not appear as a task name in the list, either add the missing task or
233
+ remove the dependency.
234
+ * Before calling plan_tasks, mentally verify: for every task, every name in its depends_on
235
+ array appears as the name of another task in the array.
236
+ * Before calling plan_tasks, check for circular dependencies. A circular dependency means task
237
+ A depends on B, and B depends on A (directly or transitively). A circular dependency causes
238
+ a deadlock — neither task can ever start. To fix it: identify which dependency in the cycle
239
+ is the weakest (i.e. view A only needs to embed view B, but B does not strictly require A
240
+ to exist). Remove that dependency from A's depends_on so A can be created first. Then decide
241
+ whether B's content is still useful without being embedded in A at creation time. If the
242
+ embed is important, add a separate update task (e.g. "update_A_embed_B") whose description
243
+ says to update view A to embed view B, and whose depends_on lists both A and B. Only add
244
+ this extra update task when the embed is genuinely important for the finished product — do
245
+ not create update tasks for minor or optional embeds, as each extra task is expensive. A
246
+ good rule of thumb: add an update task only if omitting the embed from the final view would
247
+ visibly break a user workflow.`,
248
+
249
+ `Important email rules:
250
+ * Use the built-in \`send_email\` trigger action to send emails. SMTP configuration (host,
251
+ credentials, sender address) is managed by the platform administrator in System
252
+ Configuration — it is not an application concern. Do NOT create any table for SMTP or email
253
+ settings, and do NOT plan any task to configure SMTP.
254
+ * Every \`{{}}\` interpolation in any workflow step (email body, email subject, filename,
255
+ prompt template, etc.) must reference a variable that already exists in the workflow context
256
+ at the point the step runs. Do NOT use fallback expressions such as
257
+ \`{{invoice_date || new Date().toISOString()}}\` — if the variable is not defined, the
258
+ interpolation engine throws before the \`||\` fallback can execute. If a value might not be
259
+ in context at that point, retrieve or compute it in an earlier step and store it under a
260
+ known key.`,
261
+
262
+ `Important schema/table rules:
263
+ * The database schema is already fully designed and implemented before task planning begins.
264
+ ALL tables and fields needed by the application already exist. Do NOT plan any tasks that
265
+ create tables, add fields, modify fields, or change the schema in any way. If you find
266
+ yourself writing a task whose output is a table or a field, delete it — that work is
267
+ already done.
268
+ * Ownership behaviour (auto-setting a FK-to-users field from the logged-in user) is configured
269
+ in the Edit view, not in the database. Do not create tasks for it at the schema level.
270
+ * Do NOT plan tasks to add uniqueness constraints or validation to existing fields — those are
271
+ already in the schema.
272
+ * Do NOT plan a standalone task for "access control", "row-level security", "permissions", or
273
+ "roles". These are schema-level concerns already handled during schema design, or view-level
274
+ concerns handled when building each view. The ownership field and sharing logic are already
275
+ in the schema — there is nothing extra to configure as a separate task.`,
276
+ ];
277
+
278
+ const implementation_rules = [
279
+ `Important: JsCode server-mode views run on the server and must return an HTML string.
280
+ The following globals are available: Table, View, User, File, db, user, req, state,
281
+ markupTags, Actions, emitEvent, moment.
282
+ The state object contains URL query parameters — use state.start_date, state.end_date etc.
283
+ to read user inputs submitted via a GET form.
284
+ Never use process.env, window, document, or fetch in server mode. Never return a
285
+ { code: "..." } object — always return an HTML string.
286
+ require() is NOT available — do not import lodash or any other module. Use moment or plain
287
+ JavaScript Date for all date formatting and arithmetic.`,
288
+
289
+ `Important: Workflow TableQuery steps can only query user-created application tables.
290
+ Internal Saltcorn system tables whose names start with _sc_ (such as _sc_files,
291
+ _sc_triggers, _sc_views, _sc_pages, etc.) are NOT registered as application tables and will
292
+ throw "Table X not found" at runtime if used in a TableQuery step.`,
293
+
294
+ `Important: After a page_to_pdf workflow step with to_file=true, the workflow context
295
+ automatically contains pdf_file_id (the database id of the saved file) and pdf_path_to_serve.
296
+ No extra run_js_code or TableQuery step is needed to look up the file — just use pdf_file_id
297
+ directly in the following modify_row step.`,
298
+
299
+ `Important: Any export or output step (PDF generation, CSV export, email with attached data,
300
+ etc.) reads the database at the moment it runs. It will only reflect rows that already exist
301
+ at that point. Always place every export/output step AFTER all insert, update, and aggregate
302
+ steps that produce the data it needs to include. The correct order is: (1) insert/update all
303
+ rows, (2) compute and store aggregates, (3) export/output, (4) send notifications (if needed).
304
+ Moving an export step earlier — for example right after inserting a parent row but before its
305
+ child rows are inserted — will produce empty or incomplete output even though the data looks
306
+ correct when viewed in the browser later.`,
307
+
308
+ `Important: The workflow step_type for running custom JavaScript is \`run_js_code\`
309
+ (snake_case). Do NOT use \`RunJsCode\` or any PascalCase variant — those will throw "Action
310
+ or trigger not found" at runtime. Built-in step types (TableQuery, ForLoop, SetContext, etc.)
311
+ are PascalCase, but run_js_code is the exception and must always be written in snake_case.`,
312
+
313
+ `Important: Saltcorn where-clause objects use nested operator objects — NEVER use
314
+ space-separated key suffixes. Space-separated keys like \`"entry_date >="\` or
315
+ \`"project_id in"\` are stripped by sqlSanitize (spaces are removed), producing invalid column
316
+ names like \`entry_date>=\` or \`project_idin\` that crash Postgres.
317
+ The correct operators are: \`{field: {gt: value}}\` for >, \`{field: {gt: value, equal: true}}\`
318
+ for >=, \`{field: {lt: value}}\` for <, \`{field: {lt: value, equal: true}}\` for <=,
319
+ \`{field: {in: [...array...]}}\` for IN (generates \`field = ANY($1)\`),
320
+ \`{field: null}\` for IS NULL.
321
+ This applies in both JsCode and workflow TableQuery steps.`,
322
+
323
+ `Important: To add an action button to a Show view, add a segment directly into the
324
+ \`layout.above\` array — do NOT add to the top-level \`actions\` array alone.
325
+ The \`actions\` array is metadata only; it does NOT render any button.
326
+ The layout segment that renders the button looks like:
327
+ \`{"type": "action", "rndid": "act1", "action_name": "trigger_name", "action_label": "Label",
328
+ "action_style": "btn-primary", "confirm": true, "minRole": 40}\`.
329
+ CRITICAL: every action segment MUST include a \`rndid\` field — a short unique string such as
330
+ "act1", "act2", "issue_inv", etc. If \`rndid\` is missing or undefined, the button will be
331
+ rendered but clicking it sends \`rndid: "undefined"\` to the server, which crashes with
332
+ "Cannot read properties of undefined (reading 'action_name')". Never omit \`rndid\`.
333
+ Each action segment in the same layout must have a different \`rndid\`.
334
+ The \`action_name\` must exactly match the trigger's name. The \`actions\` array entry is
335
+ optional and can be omitted entirely.
336
+ When the trigger was created in the same plan, copy its name verbatim from the trigger task's
337
+ description or name field — do not paraphrase, abbreviate, or infer it.
338
+ When the trigger already exists, read its exact name from the existing triggers list — never
339
+ guess based on what you think the name should be.`,
340
+
341
+ `Important: When a trigger is invoked from a Show view action button, the trigger MUST have
342
+ its \`table\` set to the view's table. Saltcorn will then automatically pass the full row as
343
+ the initial workflow context — every field value is available by its field name (e.g. \`id\`,
344
+ \`name\`, \`contact_email\`). Do NOT attempt to pass row data through a \`state\` property on
345
+ the \`actions\` array entry — that property is not supported and is silently ignored.
346
+ If the trigger has no table set, the workflow starts with no context and all field references
347
+ will throw "is not defined".`,
348
+
349
+ `Important: Some fields are non-stored (virtual) calculated fields — they have no database
350
+ column and are computed on-the-fly by Saltcorn. Never include such fields in modify_row, SQL
351
+ UPDATE statements, or recalculate_stored_fields calls. Only fields that exist as actual
352
+ database columns (regular fields and stored calculated fields) can be written. If a calculated
353
+ field needs updating, it will refresh automatically when the fields it depends on change.`,
354
+
355
+ `Important: When a Show view needs to display related rows (e.g. an invoice showing its line
356
+ items), embed a List view for those related rows — NOT an Edit view. Embedding an Edit view
357
+ inside a Show view is almost never correct: it renders a form with inputs, save buttons, and
358
+ date pickers inline in a read display. The only rare exception is an intentional inline-edit
359
+ pattern where the user explicitly needs to edit related rows directly inside the parent Show
360
+ view. For all other cases — displaying related data, print pages, dashboards — use a List view.
361
+ If no suitable List view exists yet, plan a separate List view task for the related table and
362
+ list it in depends_on before the Show view task.`,
363
+
364
+ `Important: Do NOT use the GoBack action for cancel buttons in Edit views. The GoBack action
365
+ always calls history.back(), which breaks when the view is opened inside a popup modal.
366
+ Instead, add a link segment with url set to the following JavaScript — it closes the Saltcorn
367
+ modal (#scmodal) if one is open, and falls back to history.back() for standalone use:
368
+ javascript:var m=document.getElementById('scmodal');var mi=m&&bootstrap.Modal.getInstance(m);if(mi)mi.hide();else history.back()
369
+ — style it as btn btn-outline-secondary to match the standard cancel appearance.`,
370
+
371
+ `Important: In List view create_view_showif expressions (and any other showif / formula
372
+ fields evaluated against the URL state), the variable \`state\` does NOT exist. The state
373
+ object is passed as \`row\`, and each key of the state is also available as a bare variable.
374
+ Use \`row.project_id\` or just \`project_id\` — never \`state.project_id\`.`,
375
+
376
+ `Important: A Saltcorn modify_row trigger has exactly these configuration fields:
377
+ \`name\` (string), \`action\` = "modify_row", \`when_trigger\` ("Insert" or "Update" — NEVER
378
+ "Validate"), optionally \`table_name\`, and \`configuration.row_expr\` — a single-line JS
379
+ expression returning an object of field→value pairs.
380
+ Example: \`{hours: Math.round(parseFloat(hours) * 100) / 100}\`.
381
+ Do NOT invent other formats (no \`match\`, \`actions\`, \`set\`, \`columns\` keys — those belong
382
+ to other platforms). NEVER use \`when_trigger: "Validate"\` with modify_row — Validate fires
383
+ before the row exists in the database so there is no id to update, causing a crash on insert.
384
+ Use \`when_trigger: "Insert"\` to normalise on new rows, and a separate
385
+ \`when_trigger: "Update"\` trigger if normalisation is also needed on edits.
386
+ Keys in the row_expr object MUST be bare field names — NEVER table-qualified names like
387
+ \`{"table_name.field_name": value}\`. Table-qualified names are silently mangled by SQL
388
+ sanitization (the dot is stripped), producing a non-existent column name and a runtime error.
389
+ Use only \`{field_name: value}\`.`,
390
+
391
+ `Important: modify_row \`row_expr\` values and all other formula/expression fields are parsed
392
+ as a single JavaScript expression by acorn. They MUST be written on one line — no literal
393
+ newlines anywhere in the expression, including inside string literals. A literal newline
394
+ inside a quoted string causes "Unterminated string constant" and crashes the trigger.
395
+ Write the entire expression on a single line: \`{field1: expr1, field2: expr2}\`.
396
+ This single-line rule applies ONLY to \`row_expr\` and similar single-expression fields —
397
+ NOT to \`run_js_code\` steps in workflows. Workflow \`run_js_code\` code is a full JavaScript
398
+ function body and must use real newlines (encoded as \`\\n\` in JSON). Never write literal
399
+ backslash-n (\`\\\\n\`) inside \`run_js_code\` code to simulate newlines — vm2 will reject it
400
+ with "Expecting Unicode escape sequence".`,
401
+
402
+ `Important: In workflow TerminateWorkflow steps, the "return value" / error message field is
403
+ evaluated as a JavaScript expression — it is NOT plain text. Always wrap the message in
404
+ quotes: \`"No billable hours found."\`. A bare unquoted sentence causes a SyntaxError at
405
+ runtime.`,
406
+
407
+ `Important: When a workflow step inserts a row (e.g. \`insert_any_row\`, \`upsert_one\`), the
408
+ row expression MUST include a value for every NOT NULL field (marked as NOT NULL in the table
409
+ listing above) that has no database default. A NOT NULL field that has a default value (shown
410
+ as "default: X" in the table listing) can be safely omitted — the database will fill it in
411
+ automatically. Omitting a NOT NULL field causes a "null value in column X violates not-null
412
+ constraint" error at runtime. If the real value is computed in a later step (e.g. a total
413
+ calculated after inserting line items), supply a safe placeholder — \`0\` for numeric fields,
414
+ \`''\` for text — so the initial insert succeeds, then update the row in the subsequent step.
415
+ Exception: File-type fields hold a file ID and cannot be given a placeholder value — always
416
+ declare File fields as \`required: false\` (nullable) unless the file is guaranteed to exist
417
+ at the moment the row is first inserted.`,
418
+
419
+ `Important: In Show view layouts, every field must be its own separate segment with
420
+ \`"type": "field"\` (singular). There is NO \`"type": "fields"\` (plural) segment — using it
421
+ crashes with "unknown layout segment" at runtime. Never bundle multiple fields into a single
422
+ segment. Each field appears as an individual element in the layout array, for example:
423
+ \`{"type": "field", "field_name": "invoice_date", "fieldview": "show"}\`.`,
424
+ ];
425
+
426
+ const fieldview_selection_rules = [
427
+ `For numeric fields (Integer, Float, Money, Decimal) the default fieldview is "edit" — a
428
+ plain text input. Only use a specialised numeric fieldview (e.g. "number_slider", "range",
429
+ "spin") when it is clearly appropriate for the data: a slider makes sense for a bounded
430
+ rating or percentage, not for an open-ended value like a price, rate, or quantity. The
431
+ existence of an alternative fieldview in the platform is not a reason to use it — "edit" is
432
+ the right default and should be the first choice unless there is a specific UX reason to do
433
+ otherwise.`,
434
+
435
+ `For date fields always prefer fieldview "flatpickr" when available — it provides the best
436
+ user experience and works for both regular dates and day-only dates. Only use fieldview
437
+ "edit_day" as a fallback when the field has day_only=true and flatpickr is not installed.
438
+ Never set a flatpickr configuration key "default" to a string like "today" — it is not a
439
+ valid date value and will throw at runtime. To pre-fill the picker with the current date/time,
440
+ set "default_now": true in the flatpickr field configuration instead. When the underlying
441
+ Date field has day_only=true, also set "day_only": true in the flatpickr fieldview
442
+ configuration — this disables the time picker and formats the value correctly.`,
443
+
444
+ `For String fields that have an options attribute (a comma-separated list of fixed choices),
445
+ use fieldview "select" — this renders a dropdown with those options. Do not use
446
+ "select_by_code" for fields with fixed options.`,
447
+
448
+ `File-type fields use dedicated fieldviews — never the generic "edit" or "show" fieldview.
449
+ In edit/form views use "upload" (file input) or "select" (pick existing file). In read-only
450
+ views (Show, List) use "Download link", "Link", "Show Image", or "Thumbnail". Using "edit"
451
+ or "show" on a File field causes a runtime error.`,
452
+ ];
453
+
454
+ const task_planning_closing = [
455
+ `Your plan should not include any clarification or questions to the product owner. The
456
+ information you have been given so far is all that is available. Every step in the plan
457
+ should be immediately implementable in Saltcorn. You are writing the steps in the plan for a
458
+ person who is competent in using saltcorn but has no other business knowledge.`,
459
+
460
+ `Do not include any steps that contain planning, design or review instructions. You are only
461
+ writing a plan for the engineer building the application. Every step in the plan should have
462
+ the construction or the modification of one or several application entity types.`,
463
+
464
+ `Description length: keep descriptions concise. Simple tasks (a single view, trigger, or
465
+ page) need only 1–3 sentences. Complex tasks (multi-step workflows, views with several
466
+ embedded components) may use more, but stop once all actionable specifics are covered — do
467
+ not re-explain steps already implied by the context, add parenthetical asides, or repeat the
468
+ same point in different words. Never pad a short task description just to appear thorough.`,
469
+ ];
470
+
471
+ const req_gen_rules = [
472
+ `Important rules for generating requirements:
473
+ * Every requirement must be directly traceable to something stated in the description,
474
+ audience, or core features above. Do not infer, invent, or add features that are not
475
+ explicitly mentioned — even if they seem like an obvious addition.
476
+ * Do not generate any requirement that falls under the Out of scope section above.
477
+ * Only generate requirements for core functionality. Do not generate requirements for
478
+ features described as optional, "nice to have", "could support", or "can be added
479
+ later" — omit them entirely.
480
+ * Do NOT generate a requirement for integration with any external third-party system
481
+ (e.g. QuickBooks, Xero, Stripe, Slack, external APIs, webhooks) unless the
482
+ specification explicitly names the system AND describes exactly what must be
483
+ exchanged. A vague mention like "integration with accounting systems" is not
484
+ sufficient — skip it.
485
+ * Do not generate requirements that are already handled by the platform (e.g. user
486
+ registration, login, password management — these are built-in).
487
+ * Priority reflects how central the feature is to the core purpose of the application.
488
+ Assign 5 to features without which the application cannot function at all, 3–4 to
489
+ features that are important but not blocking, 1–2 to minor convenience features. Do
490
+ not assign 5 to everything.`,
491
+ ];
492
+
493
+ const phase_gen_rules = [
494
+ `Rules for generating phases and their requirements:
495
+ * Break the application into 3–6 phases. Fewer is better — only split where there is a
496
+ genuine dependency boundary or a meaningful delivery milestone.
497
+ * Every requirement must be directly traceable to something stated in the specification.
498
+ Do not infer, invent, or add features that are not explicitly mentioned.
499
+ * Only include requirements for core functionality. Omit anything described as optional,
500
+ "nice to have", or "can be added later".
501
+ * Do NOT include requirements for integration with external third-party systems unless
502
+ the specification explicitly names the system and describes exactly what must be
503
+ exchanged.
504
+ * Do not include requirements already handled by the platform. Saltcorn provides
505
+ built-in user registration (/auth/signup), login (/auth/login), password management,
506
+ and role-based access control — do not generate requirements to build custom versions
507
+ of these. Application pages such as a landing page or a dashboard are valid
508
+ requirements and must be included; a landing page will naturally link to /auth/login
509
+ and /auth/signup.
510
+ * Priority reflects how central the requirement is to the core purpose of its phase.
511
+ Assign 5 to requirements without which the phase cannot be considered done, 3–4 to
512
+ important but not blocking, 1–2 to minor enhancements. Do not assign 5 to everything.
513
+ * Each phase's requirements must be self-contained: a later phase may depend on earlier
514
+ phases having been built, but should not require anything from future phases.
515
+ * Place foundational data and authentication requirements in the earliest phase.`,
516
+ ];
517
+
518
+ const phase_scope_rule =
519
+ "Plan only the tasks needed to implement the requirements listed above. Do not plan\n" +
520
+ "tasks for requirements belonging to other phases. This applies especially to database\n" +
521
+ "tables — do not create a table unless it is directly needed by a requirement listed\n" +
522
+ "above, even if you can tell it will be needed in a later phase.";
523
+
524
+ const no_roles_table_rule =
525
+ "Important: Do NOT plan any task that creates a Roles table, a permissions table, or\n" +
526
+ "any table describing what roles are allowed to do. Saltcorn has a built-in role system\n" +
527
+ "(1=admin, 40=staff, 80=user, 100=public) and every entity (view, page, table) already\n" +
528
+ "has a min_role property for access control. There is nothing to store in the database\n" +
529
+ "— access control is configured on each entity directly.";
530
+
531
+ const exec_tool_call_rule =
532
+ "Important: Every tool call must contain only the final, complete result — never\n" +
533
+ "intermediate reasoning, planning notes, markdown code fences, TODO comments, or\n" +
534
+ "placeholder text. Compose the full content in your reasoning first, then pass only\n" +
535
+ "the finished result to the tool. A page or view that contains any of these is\n" +
536
+ "broken and will be visible to end users exactly as written.";
537
+
538
+ const exec_schema_rule_plugin =
539
+ "Important: This is a plugin installation task. Install the plugin described using\n" +
540
+ "the Install Plugin skill. Do not create tables, views, pages, or triggers.";
541
+
542
+ const exec_schema_rule_data_model =
543
+ "Important: This is a data model task. Use the database design tool to create or\n" +
544
+ "modify tables and fields, or use the Registry editor (set_entity) for platform\n" +
545
+ "configuration such as creating custom roles. Do not create any views, pages, or\n" +
546
+ "triggers — only schema and platform configuration changes belong in this task.";
547
+
548
+ const exec_schema_rule_feature =
549
+ "Important: This is a feature task. Do NOT use generate_tables or modify any tables\n" +
550
+ "or fields — schema changes are handled by separate data model tasks that run\n" +
551
+ "before this one.";
552
+
553
+ const plugin_type_instruction = [
554
+ `Generate ONLY tasks with task_type "plugin" — tasks that install plugins from the
555
+ Saltcorn plugin store.`,
556
+
557
+ `Before deciding which plugins to plan, carefully read the full application specification
558
+ and phase requirements and reason through what the application will need. Do not wait for
559
+ keywords — infer from context:
560
+ - Will the application store or display dates or times in any form? (e.g. entry dates,
561
+ deadlines, schedules, appointments, logs) → a date/time picker plugin will be needed
562
+ - Will the application handle money, rates, prices, fees, invoices, or any numeric value
563
+ representing a currency or billing amount? → a money or decimal field plugin will be needed
564
+ - Will any entity be related to multiple instances of another entity in both directions?
565
+ (e.g. lawyers assigned to projects, products in orders) → a many-to-many plugin will be needed
566
+ - Will users enter or display formatted or multi-line text beyond a plain string?
567
+ → a rich text editor plugin will be needed
568
+ - Will any page show charts, graphs, totals, or aggregated statistics?
569
+ → a chart plugin will be needed
570
+ - Will the application deal with physical locations, addresses, or maps?
571
+ → a map plugin will be needed
572
+ - Will users upload or attach files or images? → a file upload plugin will be needed
573
+ For each need you identify, check the available plugin list above for a matching plugin that
574
+ is not already installed, and plan a task for it.`,
575
+
576
+ `Critical: only plan a plugin installation task when the built-in actions, field types,
577
+ and view templates genuinely cannot cover the requirement. Inserting rows, updating fields,
578
+ running workflow steps, and computing aggregates are all covered by built-in workflow actions
579
+ — only install a plugin when no built-in equivalent exists. For example, do NOT install the
580
+ 'sql' plugin to insert rows or compute totals — use built-in workflow steps instead.`,
581
+
582
+ "Each task installs exactly one plugin. If no plugins are needed, call plan_tasks with an empty tasks array.",
583
+ ];
584
+
585
+ const data_model_type_instruction = [
586
+ `Generate ONLY tasks with task_type "data_model" — tasks that create or modify database
587
+ tables or fields. Do not generate any feature tasks.`,
588
+
589
+ `Each task should implement exactly one deliverable — one table or a closely related set of
590
+ fields. Keep tasks small and focused. Tasks may depend on other tasks within this phase using
591
+ the depends_on field.`,
592
+
593
+ `Critical: only create tables and fields that are directly required by the requirements of
594
+ THIS phase listed above. Do not anticipate future phases or add tables speculatively because
595
+ they will eventually be needed. If a requirement is not listed above, it belongs to another
596
+ phase — do not implement it here.`,
597
+
598
+ `Important: Each task description must fully specify uniqueness (unique=true) and required
599
+ (not_null=true) constraints on every field — do not leave these for a later step. Never
600
+ mention constraints on the 'id' field — it is the primary key and is always unique and
601
+ not-null by definition.`,
602
+
603
+ "Important: Ownership (auto-populating a FK-to-users field from the logged-in user) is a view-level concern — task descriptions must not mention it. Just describe the FK field normally.",
604
+
605
+ "Important: Do NOT plan any task that creates a table for SMTP, email configuration, or mail server credentials — email config is managed by the platform administrator.",
606
+ ];
607
+
608
+ const feature_type_instruction = [
609
+ `Generate ONLY tasks with task_type "feature" — tasks that create views, pages, triggers,
610
+ or workflows. Do not generate any data_model tasks.`,
611
+ ];
612
+
613
+ const error_fix_closing = [
614
+ "Either call plan_tasks with exactly one fix task, or call cannot_fix if you cannot " +
615
+ "determine a concrete fix from the information above. Do not invent a task just to " +
616
+ "produce output — prefer cannot_fix over a vague or speculative task.",
617
+
618
+ "Rules for the plan_tasks description (only if you can diagnose the fix):\n" +
619
+ "- Name the exact Saltcorn entity (view, trigger, page) to fix.\n" +
620
+ "- Describe what is wrong and what kind of fix is needed. Where you can clearly identify " +
621
+ "them from the config shown above, state each broken field, its current value, and the correct value. " +
622
+ "If you are not certain of the exact values, describe the problem instead — do not guess specific values.\n" +
623
+ "- Cover ALL fields of the same error class in one task.\n" +
624
+ "- Prefer fixing a broken reference over removing the element that contains it. " +
625
+ "Only remove an element when there is genuinely no valid replacement. " +
626
+ "Example: a viewlink column referencing a missing view should have its view name " +
627
+ "updated to an existing view — not have the column deleted.\n" +
628
+ "- End with: 'Use get_entity to load the current config, diagnose the exact values, apply the fix, and save with set_entity.'\n" +
629
+ "- One or two sentences. No prose, no save/test instructions.",
630
+ ];
631
+
632
+ const feature_exec_rules = [
633
+ `Important: The "users" table is built-in. Passwords are platform-managed — never add
634
+ a password field to a view. Signup uses the built-in page at /auth/signup, login at
635
+ /auth/login. Do NOT create triggers for registration or email verification — the
636
+ platform handles this natively. Do NOT create any Edit, Show, or List view whose
637
+ underlying table is the built-in users table — user records are managed entirely by
638
+ the platform.`,
639
+
640
+ `Important: On landing pages, place Log in / Create account buttons in no more than
641
+ two locations (e.g. navbar and one hero call-to-action). Do not repeat them in a third
642
+ "Get started" section or anywhere else. For links that take an already-authenticated
643
+ user to their dashboard, use href="/" — not /auth/login.`,
644
+
645
+ `Important: Saltcorn page URLs always use the prefix /page/. To link to a page named
646
+ "teacher_dashboard", the href must be "/page/teacher_dashboard" — NOT "/teacher_dashboard".
647
+ This applies to every link, button, or navigation item that points to a Saltcorn page,
648
+ regardless of where the link appears (landing page, navbar, other pages, etc.).
649
+ Views use /view/view_name — also with the /view/ prefix, not a bare name.`,
650
+
651
+ `Important: Do not name any page or view "Admin dashboard" — that name is reserved by
652
+ the Saltcorn platform. For pages intended for role 1 (admin), use a name like "App
653
+ admin dashboard" or prefix it with the application name (e.g. "Law Firm admin
654
+ dashboard").`,
655
+
656
+ `Important: Dashboard stat cards must show real data using embedded Saltcorn Statistic
657
+ views (using embed-view tags, e.g. <embed-view viewname="total_hours_stat"></embed-view>).
658
+ Never use client-side JavaScript fetch stubs, commented-out fetch code, or static
659
+ placeholder values (e.g. "—", "Loading...") for statistics. If a Statistic view for a
660
+ metric does not exist yet, it must have been created in an earlier task — do not invent
661
+ placeholder JS instead.`,
662
+
663
+ `Important: When creating a page or view, always set min_role based on the intended
664
+ audience: 1 for admin-only, 40 for staff and above, 80 for logged-in users and above,
665
+ 100 for public. Never default to public (100) unless the page or view is explicitly
666
+ intended for unauthenticated users (e.g. a landing page). A dashboard or view for
667
+ clients/users is role 80, a staff page or view is role 40, an admin page or view is
668
+ role 1.`,
669
+
670
+ `Important: Two-factor authentication (2FA/TOTP) is fully built into the platform. To
671
+ configure it, call set_entity directly with entity_type "system-configuration-value"
672
+ and entity_name "twofa_policy_by_role". The entity_definition must be the plain JSON
673
+ object itself — for example: {"1": "Mandatory", "100": "Disabled"}. Do NOT wrap it in
674
+ {"type": "json", "value": ...} or any other envelope. Read the current value first with
675
+ get_entity and merge rather than overwrite. Do NOT create a workflow or trigger to do
676
+ this.`,
677
+
678
+ `Important: To set a page as the home page for a role, call set_entity directly with
679
+ entity_type "system-configuration-value" and entity_name "home_page_by_role". The
680
+ value is a JSON object mapping role IDs to page names — Role IDs: public=100, user=80,
681
+ staff=40, admin=1. The entity_definition must be the plain JSON object itself — for
682
+ example: {"100": "landing", "80": "client_dashboard"}. Do NOT wrap it in {"type":
683
+ "json", "value": ...} or any other envelope. Read the current value first with
684
+ get_entity so you can merge rather than overwrite. Do NOT create a workflow or trigger
685
+ to do this — use set_entity directly.`,
686
+
687
+ `Important: If the task description mentions adding a viewlink, linking rows to another
688
+ view, or a button that opens another view from a list — that viewlink column MUST be
689
+ present in the finished view. Do not skip it. Viewlinks require calling
690
+ get_relation_paths first to obtain the relation string before generating the layout.`,
691
+
692
+ `Important: Every List view must include a delete action column unless the table is
693
+ explicitly read-only. Use the built-in "Delete" action type for this column.`,
694
+
695
+ `Important: Before creating or updating any view or page that embeds, links to, or
696
+ opens another view (including viewlinks, action buttons, and ajax_modal calls), call
697
+ list_entities (entity_type "view") to get all existing view names. Only reference
698
+ views that appear in that list — never invent a name or assume a view exists. If a
699
+ view is not in the list, omit it or use a simple "Coming soon" placeholder — never
700
+ write conversational text, explanations, or instructions to the user inside the HTML.
701
+ Always create the page with whatever views exist. Do the same for pages: call
702
+ list_entities (entity_type "page") before linking to any page by name.`,
703
+
704
+ `Important: A plain Edit view creates or edits a single record — it is NOT a bulk CSV
705
+ import tool. Never use an Edit view as a solution for CSV import. List views have no
706
+ built-in CSV export feature — do not add an export button or column to a List view.
707
+ CSV import and export functionality must always be placed on a dedicated management or
708
+ admin page as embedded views, using whatever import/export viewtemplate is available.`,
709
+
710
+ `Important: Every HTML page (page_type HTML) must include a toast notification area so
711
+ that alerts and success messages are visible. Place this div just before the closing
712
+ </body> tag:
713
+ <div id="toasts-area" class="toast-container position-fixed top-0 start-50 p-0"
714
+ style="z-index:999;" aria-live="polite" aria-atomic="true"></div>`,
715
+
716
+ `CRITICAL: When creating a page, default to page_type "Layout page". This creates a
717
+ proper Saltcorn layout built from segments (view embeds, containers, columns, etc.)
718
+ and is the correct choice for dashboards, print pages, and any page that embeds views.
719
+ Use page_type "Marketing page" only for public-facing promotional pages (landing pages,
720
+ brochures). Use page_type "Application page" only for standalone HTML pages that do
721
+ not embed Saltcorn views. In particular, NEVER use "Marketing page" or "Application
722
+ page" for any page used with page_to_pdf — page_to_pdf cannot render HTML-backed
723
+ pages. If you find yourself about to write raw HTML (<!doctype>, <html>, <head>,
724
+ <body>), stop and ask yourself: does this task explicitly require a standalone HTML
725
+ page — like a public landing page, a marketing page, or a dashboard? If not, use
726
+ page_type "Layout page". Do not output HTML to the conversation.`,
727
+ ];
728
+
729
+ const data_model_exec_rules = [
730
+ `Important: If this task requires creating custom platform roles (beyond the four
731
+ built-in roles: 1=admin, 40=staff, 80=user, 100=public), use the Registry editor:
732
+ call set_entity with entity_type "role" and the role definition. Do NOT create a
733
+ user-defined database table for roles — platform roles are a system concern, not
734
+ application data.`,
735
+
736
+ `Important: The "users" table is built-in and must never be modified — do not add,
737
+ remove, or alter any fields on it.`,
738
+
739
+ `Important: Saltcorn has a built-in role system with fixed roles (1 = admin, 40 = staff,
740
+ 80 = user, 100 = public). Do NOT create a Roles table, a permissions table, or any
741
+ table describing what roles are allowed to do. Access control is a platform concern:
742
+ every Saltcorn entity (views, pages, tables) already has a min_role property that
743
+ controls which role can access it. There is nothing to store in the database —
744
+ configure min_role on each entity instead.`,
745
+
746
+ `Important: Every Saltcorn table has a primary key field named "id" that is always
747
+ unique and not-null by definition. Never set unique=true or not_null=true on the "id"
748
+ field — it is redundant and incorrect. For every OTHER field that must be unique (e.g.
749
+ unique email, unique slug), set unique=true on that field. For every other field that
750
+ must not be empty, set not_null=true. Description, notes, and other free-text fields
751
+ should NOT be not_null unless explicitly required. Do NOT leave uniqueness or required
752
+ constraints for a later step — express them fully now.`,
753
+
754
+ `Important: Ownership configuration (automatically populating a FK-to-users field from
755
+ the logged-in user) is a VIEW-level concern and cannot be expressed in the schema. Do
756
+ not attempt to annotate fields as "ownership fields" — simply define the foreign key
757
+ field normally. Ownership will be configured when the Edit views are generated.`,
758
+
759
+ `Important: Email and SMTP configuration (host, port, credentials, sender address) is
760
+ managed by the Saltcorn platform administrator in system settings — it is NOT stored
761
+ in the application database. Do NOT create any table for SMTP settings, email
762
+ configuration, or mail server credentials. If the application needs to send emails,
763
+ that is handled by a trigger action.`,
764
+
765
+ `Important: Every tool call must contain only the final, complete result — never
766
+ intermediate reasoning, planning notes, or placeholder values. Compose the full schema
767
+ in your reasoning first, then pass only the finished result to the tool.`,
768
+ ];
769
+
770
+ const research_questions_rules =
771
+ "Based on the following application specification, generate clarifying questions\n" +
772
+ "that would help better understand what the user wants to build.\n" +
773
+ "Ask only about genuinely ambiguous or underspecified aspects.\n" +
774
+ "Do not ask about things that are already clear from the specification.\n" +
775
+ "Only ask questions that are truly necessary — if 2 or 3 questions cover everything unclear, stop there.\n" +
776
+ "Do not pad the list. 10 is a hard maximum, not a target.";
777
+
778
+ const feedback_analyse_decision =
779
+ "Do you have important questions about this feedback,\n" +
780
+ "or do you already know what needs to be done?\n\n" +
781
+ "- If you know what to do — no need to call any tool, just respond with nothing.\n" +
782
+ "- If you have questions that are truly blocking —\n" +
783
+ " call ask_questions with only those. 3 is a hard maximum.\n" +
784
+ " Each question must be short, clear, and easy to understand.\n" +
785
+ " Write for a non-technical user: plain language, no jargon, one idea per question.";
786
+
787
+ const feedback_task_overrides = [
788
+ "Generate ONLY the minimal tasks that directly implement what the feedback requests. " +
789
+ 'Do not add defensive "verify", "ensure accessible", or "check still reachable" tasks — ' +
790
+ "those are not changes and do not belong in a task plan.",
791
+
792
+ "Do NOT generate tasks for writing, updating, or running automated tests. " +
793
+ "There are no automated tests in this application.",
794
+
795
+ "When a task modifies an existing view or page, do NOT set or change its min_role unless " +
796
+ "the feedback explicitly requests an access control change. The existing min_role is already correct.",
797
+
798
+ "If the feedback can be implemented in a single task, use a single task. " +
799
+ "Do not split it into more tasks than strictly necessary.",
800
+
801
+ "Do NOT create new views, pages, or routes as a side effect of modifying an existing one. " +
802
+ "Only create a new view or page when the feedback explicitly asks for one. " +
803
+ "If the feedback asks to change or remove something from an existing view, only modify that view.",
804
+ ];
805
+
806
+ module.exports = {
807
+ saltcorn_description,
808
+ task_planning_rules,
809
+ implementation_rules,
810
+ fieldview_selection_rules,
811
+ task_planning_closing,
812
+ error_fix_closing,
813
+ feedback_task_overrides,
814
+ feature_exec_rules,
815
+ data_model_exec_rules,
816
+ req_gen_rules,
817
+ phase_gen_rules,
818
+ phase_scope_rule,
819
+ no_roles_table_rule,
820
+ exec_tool_call_rule,
821
+ exec_schema_rule_plugin,
822
+ exec_schema_rule_data_model,
823
+ exec_schema_rule_feature,
824
+ plugin_type_instruction,
825
+ data_model_type_instruction,
826
+ feature_type_instruction,
827
+ feedback_analyse_decision,
828
+ research_questions_rules,
829
+ };