@josephyan/qingflow-app-builder-mcp 1.1.30 → 1.1.33

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.
Files changed (88) hide show
  1. package/README.md +6 -4
  2. package/docs/local-agent-install.md +57 -6
  3. package/entry_point.py +1 -1
  4. package/npm/bin/qingflow-app-builder-mcp.mjs +1 -1
  5. package/npm/bin/qingflow-skills.mjs +5 -0
  6. package/npm/lib/runtime.mjs +20 -59
  7. package/npm/scripts/postinstall.mjs +1 -10
  8. package/package.json +3 -2
  9. package/pyproject.toml +1 -1
  10. package/skills/qingflow-app-builder/SKILL.md +111 -55
  11. package/skills/qingflow-app-builder/references/complete-system-development-guide.md +169 -0
  12. package/skills/qingflow-app-builder/references/create-app.md +31 -24
  13. package/skills/qingflow-app-builder/references/environments.md +1 -1
  14. package/skills/qingflow-app-builder/references/gotchas.md +40 -14
  15. package/skills/qingflow-app-builder/references/match-rules.md +196 -85
  16. package/skills/qingflow-app-builder/references/public-surface-sync.md +2 -2
  17. package/skills/qingflow-app-builder/references/single-app-development-guide.md +84 -0
  18. package/skills/qingflow-app-builder/references/solution-playbooks.md +10 -0
  19. package/skills/qingflow-app-builder/references/tool-selection.md +40 -25
  20. package/skills/qingflow-app-builder/references/update-flow.md +27 -52
  21. package/skills/qingflow-app-builder/references/update-schema.md +14 -0
  22. package/skills/qingflow-app-builder/references/update-views.md +101 -32
  23. package/skills/qingflow-app-builder/scripts/validate_system_build_summary.py +124 -0
  24. package/skills/qingflow-app-builder-code-integrations/SKILL.md +5 -3
  25. package/skills/qingflow-app-builder-code-integrations/references/code-block.md +1 -1
  26. package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +1 -1
  27. package/skills/qingflow-mcp-setup/SKILL.md +13 -9
  28. package/skills/qingflow-mcp-setup/references/claude-desktop.md +1 -1
  29. package/skills/qingflow-mcp-setup/references/environments.md +2 -1
  30. package/skills/qingflow-mcp-setup/references/generic-stdio.md +6 -5
  31. package/skills/qingflow-workflow-builder/SKILL.md +9 -7
  32. package/skills/qingflow-workflow-builder/references/01-overview.md +4 -2
  33. package/skills/qingflow-workflow-builder/references/03-flow-patterns.md +2 -0
  34. package/skills/qingflow-workflow-builder/references/06-stage3-build-spec.md +59 -7
  35. package/skills/qingflow-workflow-builder/references/07-stage4-validate-spec.md +14 -5
  36. package/skills/qingflow-workflow-builder/references/08-stage5-apply-verify.md +19 -3
  37. package/skills/qingflow-workflow-builder/references/11-troubleshooting.md +2 -0
  38. package/src/qingflow_mcp/__main__.py +6 -2
  39. package/src/qingflow_mcp/builder_facade/models.py +473 -138
  40. package/src/qingflow_mcp/builder_facade/service.py +6356 -1866
  41. package/src/qingflow_mcp/cli/commands/builder.py +358 -355
  42. package/src/qingflow_mcp/cli/commands/chart.py +1 -1
  43. package/src/qingflow_mcp/cli/commands/common.py +12 -3
  44. package/src/qingflow_mcp/cli/commands/exports.py +2 -2
  45. package/src/qingflow_mcp/cli/commands/imports.py +3 -3
  46. package/src/qingflow_mcp/cli/commands/portal.py +2 -2
  47. package/src/qingflow_mcp/cli/commands/record.py +101 -27
  48. package/src/qingflow_mcp/cli/commands/task.py +28 -47
  49. package/src/qingflow_mcp/cli/commands/view.py +1 -1
  50. package/src/qingflow_mcp/cli/context.py +0 -3
  51. package/src/qingflow_mcp/cli/formatters.py +784 -16
  52. package/src/qingflow_mcp/cli/main.py +120 -41
  53. package/src/qingflow_mcp/errors.py +43 -2
  54. package/src/qingflow_mcp/public_surface.py +26 -17
  55. package/src/qingflow_mcp/response_trim.py +81 -17
  56. package/src/qingflow_mcp/server.py +14 -12
  57. package/src/qingflow_mcp/server_app_builder.py +83 -39
  58. package/src/qingflow_mcp/server_app_user.py +22 -16
  59. package/src/qingflow_mcp/session_store.py +11 -7
  60. package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
  61. package/src/qingflow_mcp/solution/executor.py +114 -15
  62. package/src/qingflow_mcp/tools/ai_builder_tools.py +3571 -1473
  63. package/src/qingflow_mcp/tools/app_tools.py +184 -43
  64. package/src/qingflow_mcp/tools/approval_tools.py +197 -35
  65. package/src/qingflow_mcp/tools/auth_tools.py +92 -16
  66. package/src/qingflow_mcp/tools/code_block_tools.py +298 -40
  67. package/src/qingflow_mcp/tools/custom_button_tools.py +64 -10
  68. package/src/qingflow_mcp/tools/directory_tools.py +236 -72
  69. package/src/qingflow_mcp/tools/export_tools.py +244 -34
  70. package/src/qingflow_mcp/tools/feedback_tools.py +9 -0
  71. package/src/qingflow_mcp/tools/file_tools.py +9 -3
  72. package/src/qingflow_mcp/tools/import_tools.py +336 -49
  73. package/src/qingflow_mcp/tools/navigation_tools.py +91 -12
  74. package/src/qingflow_mcp/tools/package_tools.py +118 -6
  75. package/src/qingflow_mcp/tools/portal_tools.py +39 -3
  76. package/src/qingflow_mcp/tools/qingbi_report_tools.py +116 -7
  77. package/src/qingflow_mcp/tools/record_tools.py +1141 -356
  78. package/src/qingflow_mcp/tools/resource_read_tools.py +188 -39
  79. package/src/qingflow_mcp/tools/role_tools.py +80 -9
  80. package/src/qingflow_mcp/tools/solution_tools.py +57 -15
  81. package/src/qingflow_mcp/tools/task_context_tools.py +687 -159
  82. package/src/qingflow_mcp/tools/task_tools.py +113 -29
  83. package/src/qingflow_mcp/tools/view_tools.py +106 -3
  84. package/src/qingflow_mcp/tools/workflow_tools.py +17 -1
  85. package/src/qingflow_mcp/tools/workspace_tools.py +71 -3
  86. package/src/qingflow_mcp/version.py +0 -2
  87. package/skills/qingflow-app-builder/references/build-complete-system.md +0 -234
  88. package/skills/qingflow-app-builder/references/build-single-app.md +0 -138
@@ -0,0 +1,84 @@
1
+ # Single App Development Guide
2
+
3
+ Use this when the user asks for one app/form, or gives one `app_key`.
4
+ If the user asks for a package, system, or several related modules, use `complete-system-development-guide.md` instead.
5
+
6
+ ## Recommended Completeness
7
+
8
+ Required:
9
+
10
+ - target package/app resolved by `package_get`, `app_resolve`, or `app_get`
11
+ - business fields created or updated through `app_schema_apply`
12
+ - exactly one readable top-level `as_data_title: true`
13
+ - no platform system fields in `add_fields`
14
+ - layout places the important fields
15
+ - at least one business view beyond platform default views when the task includes user-facing list work
16
+
17
+ Strongly recommended:
18
+
19
+ - saved filters and query panel fields for the main operating views
20
+ - core operating views declare needed business actions directly in `app_views_apply.views[].action_buttons`, when the view has real actions
21
+ - simple charts when the app has status, amount, date, or owner fields worth tracking
22
+
23
+ Optional:
24
+
25
+ - workflow, sample data, roles, or visibility changes when requested by the user or clearly needed by the app's job
26
+
27
+ Workflow preflight:
28
+
29
+ - If the app will have approval/fill/copy workflow nodes, add one explicit business status `select` field first, such as `状态`, `处理状态`, `审批状态`, `工单状态`, or `流程阶段`.
30
+ - Do not create platform workflow system fields: `当前流程状态`, `当前处理人`, `当前处理节点`, or `流程标题`.
31
+
32
+ ## Standard Path
33
+
34
+ 1. Read current target: `app_resolve` or `app_get`.
35
+ 2. Read current fields: `app_get_fields`.
36
+ 3. For a new app, apply fields and form layout together with `app_schema_apply` using `form`; for an existing app, use `app_schema_apply` only for field changes.
37
+ 4. Use `app_layout_apply` only when repairing or changing layout on an existing app. Do not call it after new-app creation just to place fields.
38
+ 5. Apply workflow with the new complete chain when the user asks for approval, fill, copy, reminders, or process routing: read flow schema/current flow, build a WorkflowSpec for full flow writes or `patch_nodes` for targeted edits, call `app_flow_apply`, then read back flow. Do not use legacy `nodes/transitions` except for deliberately simple linear compatibility.
39
+ 6. Apply views with `app_views_apply` when list/table/card/gantt behavior is part of the request; declare needed view actions in `action_buttons` while designing the view.
40
+ 7. Apply charts only if they are part of the app's actual reporting need.
41
+ 8. Use `app_publish_verify` only when explicit live verification is required.
42
+
43
+ ## Field Rules
44
+
45
+ - Use agent-friendly field types where possible: `text`, `multiline`, `select`, `multi_select`, `number`, `amount`, `date`, `datetime`, `member`, `department`, `attachment`, `relation`.
46
+ - The tool normalizes aliases: `multiline -> long_text`, `select -> single_select`, `checkbox -> multi_select`. Readback may show canonical types; do not treat that as a failed write.
47
+ - Select fields must define `options` during schema design. Options may be strings or objects such as `{"label": "进行中"}`; later sample data should use those option labels or ids.
48
+ - Relation fields are for real cross-object links. If used, include `target_app_key` for an existing app or `target_app_ref` for a same-batch app, plus `display_field: {"name": "..."}` and `visible_fields: [{"name": "..."}]`.
49
+ - Do not impose a one-relation-field limit. Add the relation fields the business needs, then rely on backend validation and readback.
50
+ - Do not create `数据ID`, `编号`, `申请人`, `申请时间`, `创建人`, `创建时间`, `提交人`, `提交时间`, `更新时间`, `更新人`, `当前流程状态`, `当前处理人`, `当前处理节点`, or `流程标题`.
51
+ - Do not create built-in default views such as `全部数据` or `我的数据`; Qingflow provides system views.
52
+
53
+ ## View Query Rules
54
+
55
+ - `filters` are fixed saved filters; `query_conditions` only configures frontend query-panel fields.
56
+ - Put only query-panel fields in `query_conditions.rows`: text, long text, number, amount, date/datetime, select, member, department, phone, email, or boolean.
57
+ - Do not put relation, attachment, subtable/subfield, address, Q-Linker, or code-block fields in `query_conditions`; use fixed `filters` or associated-resource `match_mappings` instead.
58
+
59
+ ## Chart Rules
60
+
61
+ - Read `app_get_fields.chart_fields` before chart apply; normal form fields are not enough for QingBI dimensions, metrics, or filters.
62
+ - Use semantic chart input first: `metric`, `metrics`, `group_by`, and `where`.
63
+ - One KPI card uses `target` / `indicator` with `metric: "count(*)"` or `metric: "sum(金额)"`.
64
+ - Grouped distribution uses `bar` / `columnar` / `pie` with `group_by + metric`.
65
+ - Trend uses `line` / `area` / `columnar` with a date/month `group_by`.
66
+ - Do not use `summary` for a single KPI; `summary` is for table-style grouped summaries.
67
+ - Do not handwrite raw `indicator_field_ids`, `selectedMetrics`, or QingBI filter matrices on the main path.
68
+
69
+ ## View Action Rules
70
+
71
+ - Use `action_buttons` inside `app_views_apply.views[]` for buttons tied to one view.
72
+ - Use `add_data` when a current record creates a downstream/child record; configure `target_app_key + field_mappings`, usually mapping `source_field: "数据ID"` to the target relation/reference field.
73
+ - Use `link` only for SOP, help, external system, or fixed URL navigation. Do not use it to fake approval, status transition, or data writeback.
74
+ - Prefer `detail` for current-record add-data actions, `list` for row actions, and `header` for global actions with no current-row context. Do not use current-record `field_mappings` on `header`.
75
+ - Approval, rejection, close-task, and status transition should be workflow/task behavior or existing automation; they are not generic custom-button types.
76
+
77
+ ## Stop Conditions
78
+
79
+ - If the task actually needs multiple business objects, stop and switch to the complete-system guide.
80
+ - If an existing app with the same or very similar name appears and the user did not explicitly say update, extend, or create new, stop and ask which target to use.
81
+ - If readback shows the requested app already has some resources, patch the verified gaps instead of recreating the app.
82
+ - If a write returns `partial_success`, `write_executed=true`, or `safe_to_retry=false`, read back before retrying.
83
+ - If the same validation error repeats twice, re-read `builder_tool_contract` instead of guessing.
84
+ - Do not create `V2`, `测试`, timestamp, or random-suffix apps to bypass duplicate names in a real business package.
@@ -2,6 +2,16 @@
2
2
 
3
3
  Use these when you need a quick reminder of the standard v2 builder sequences.
4
4
 
5
+ ## Create a complete system / app package
6
+
7
+ 1. `package_get` or `package_apply`
8
+ 2. one multi-app `app_schema_apply(package_id=..., apps=[...])`
9
+ 3. use stable `apps[].client_key` values and relation `target_app_ref` for same-call app references
10
+ 4. use returned/readback `app_key` values for layout, views, workflow, charts, buttons, associated resources, and portal work
11
+ 5. `app_publish_verify` only when the user asks for explicit live verification or a final verification pass is required
12
+
13
+ If the multi-app schema write times out or returns `partial_success`, `write_executed=true`, `safe_to_retry=false`, or incomplete readback, the next action is `readback_before_retry`: read package/app/fields first, then retry only verified missing pieces. Do not repeat the whole apps payload, split into single-app rebuilds, or create `V2` / `测试` / random-suffix apps to dodge duplicate names.
14
+
5
15
  ## Create a new app in an existing package
6
16
 
7
17
  1. `package_get`
@@ -19,27 +19,40 @@ Before picking tools, decide which layer the request targets:
19
19
 
20
20
  If the user asks for multiple forms/modules that relate to each other, this is a package-level multi-app task, not a single-app create.
21
21
 
22
+ Use this split consistently:
23
+
24
+ - Complete system/package: `package_apply` first, then one `app_schema_apply(package_id=..., apps=[...])`.
25
+ - Single app: `app_resolve/app_get` first, then app-scoped apply tools.
26
+ - Record/task/data operation: leave builder and use record/task skills.
27
+
28
+ Decision gate before writing:
29
+
30
+ | Evidence | Action |
31
+ | --- | --- |
32
+ | User gives an `app_key`, `view_key`, `chart_id`, `dash_key`, or exact `package_id` | Treat the task as an update to that existing target unless the user explicitly asks for a new one |
33
+ | User names several forms/modules or asks for a system/package | Use the complete-system path; do not compress them into one app |
34
+ | Same or very similar package/app already exists and the user did not say extend/replace/new | Stop and ask whether to extend existing, repair missing parts, or create a new target |
35
+ | Existing readback already contains part of the requested system | List verified existing resources, identify gaps, and patch only missing or incorrect slices |
36
+ | A write is uncertain: timeout, `partial_success`, `write_executed=true`, or `safe_to_retry=false` | Read back before retrying; do not create `V2`, `测试`, timestamp, or random-suffix resources |
37
+
22
38
  ## Resolve
23
39
 
24
- - `package_get`: read one known package by `package_id`
25
- - `package_apply`: create or update one package; use `create_if_missing=true` only after explicit user intent
40
+ - `package_get`: read one known package by `package_id`; it reads package `baseInfo` first and may warn `PACKAGE_DETAIL_READ_DEGRADED` when the richer detail endpoint needs package edit/add-app permission. Treat that warning as degraded detail, not as package-read failure.
41
+ - `package_apply`: create or update one package; `package_name` without `package_id` creates a package; layout/group/order changes require package edit permission because they call the backend package ordering route
26
42
  - `member_search`: resolve named people from the directory
27
43
  - `role_search`: resolve reusable roles from the directory
28
44
  - `role_create`: create a reusable role when the business owner wants role-based routing
29
- - `app_resolve`: locate an existing app by exactly one selector mode: `app_key`, or `app_name + package_id`
45
+ - `app_resolve`: locate an existing app by exactly one selector mode: `app_key`, or `app_name + package_id`; by-name resolution checks package detail/current visible apps before using broader admin-style app search, so a `/app/item` permission miss is not a frontend-visible-app failure
30
46
 
31
47
  ## Summary reads
32
48
 
33
- All `app_get_*` tools accept either `app_key` (single) or `app_keys[]` (batch). Batch returns `{status, apps[], errors[]}` — prefer batch when reading multiple apps in one step.
34
-
35
49
  - `app_get`: overall app config health, publish state, counts, and builder editability
36
50
  - `app_get_fields`: field names, types, required flags, section ids
37
51
  - `app_get_layout`: sections, rows, unplaced fields
38
52
  - `app_get_views`: current view names, types, columns, group-by
39
- - `app_get_flow`: workflow enabled state, full spec (nodes + transitions)
53
+ - `app_get_flow`: workflow enabled state, nodes, transitions
40
54
  - `app_get_charts`: current chart ids, names, types, order
41
- - `app_get_associated_resources`: current associated resource pool (draft state)
42
- - `app_publish_verify`: publish state and package tag verification — accepts `app_keys[]` for multi-app batch
55
+ - `chart_get`: one chart's base/config detail; base info is read through the Qingflow/qflow visible route first, and config may degrade from chart data when the CHART_SEE config endpoint is unavailable. Treat degraded config as a read-mode warning, not as proof the user cannot see the chart.
43
56
  - `portal_get`: current portal config detail and component inventory
44
57
 
45
58
  ## Apply tools
@@ -47,14 +60,15 @@ All `app_get_*` tools accept either `app_key` (single) or `app_keys[]` (batch).
47
60
  These execute normalized patches. Some app apply tools publish by default and still accept `publish=false`; custom button and associated-resource apply publish after at least one write succeeds and do not expose that switch.
48
61
 
49
62
  - `app_schema_apply`: create app shell or change fields
50
- - `app_layout_apply`: layout-only maintenance for existing apps; new app layout belongs in `app_schema_apply` `form.sections`
51
- - `app_flow_apply`: replace full workflow spec; use `patch_nodes[]` (`{id, set, unset}`) to update specific nodes without rewriting the full spec
52
- - `app_views_apply`: use top-level `views[]` for same-app/cross-app batch create, patch, and remove; view business actions belong in each view item's `action_buttons`
53
- - `app_associated_resources_apply`: attach existing BI reports/views to the Qingflow app associated-resource pool and per-view display area; it does not create or edit QingBI report bodies/configs. Use `patch_resources` for existing associated-resource parameter replacement; use `upsert_resources` for creation or full target config; `view_configs`, remove, and reorder may reference existing resources by internal `associated_item_id` or by `chart_id`/`chart_key`/`view_key`; use `match_mappings` for associated view/report filters; publishes after successful writes; omit raw `sourceType`, and use `report_source="dataset"` only to attach an existing BI dataset report. Before `upsert_resources`, read `app_get.associated_resources` and reuse an existing matching `target_app_key + view_key/chart_key`; repeated upsert can create duplicates because `client_key` is only valid inside one apply call. Use `apps[]` for multi-app batch.
54
- - `app_charts_apply`: create/edit/remove/reorder app-source QingBI report bodies/configs with `dataSourceType=qingflow`; it does not create/edit dataset BI reports and does not attach reports to Qingflow app associated-resource display. Use `patch_charts` for existing-chart parameter replacement; use `upsert_charts` for creation or full target config; supports `target/table` aliases plus QingBI chart types such as `summary`, `columnar`, `area`, `funnel`, `radar`, `scatter`, `dualaxes`, and `map`; charts are immediate-live and do not publish; use `chart_id` when names are not unique; use `apps[]` for multi-app batch
55
- - `portal_apply`: create or replace-update portal pages; use `dash_key` for update mode or `package_id + dash_name` for create mode; edit mode may omit `sections` for base-info-only updates; when sections are supplied they still use replace semantics; sections use a 24-column PC grid all components in the same row (same `y`) must share the same `rows` value and their `cols` must sum to exactly 24; mismatched `rows` causes height misalignment, `cols` under 24 leaves trailing blank space; use `patch_sections[]` (`{chart/view_ref/order, set, unset}`) to update individual sections without replacing all
63
+ - `app_layout_apply`: merge or replace layout
64
+ - `app_flow_apply`: replace workflow
65
+ - `app_views_apply`: use top-level `views[]`; `operation="upsert"` creates or fully targets a view, `operation="patch"` changes existing view parameters, and `operation="remove"` removes by key; declare view-specific business buttons in the same `views[]` item with `action_buttons`; new views default associated report/view display to visible with `limit_type="all"`
66
+ - `app_custom_buttons_apply`: advanced custom-button maintenance only: style/icon changes, cross-view reuse, deleting button bodies, bulk reordering bindings, or exact qRobot/wings configs. Use `patch_buttons` for existing-button parameter replacement; use `upsert_buttons` for creation or full target config; bind buttons to header/detail/list view positions; `placement=list` maps to the backend `INSIDE` row/list button position; merge-mode view configs require `buttons`; use `view_configs[].mode="replace"` or `buttons=[]` to clear a view's custom button bindings. For child-record creation linked to the current source record, map `source_field: "数据ID"` to the target relation field.
67
+ - `app_associated_resources_apply`: attach existing BI reports/views to the Qingflow app associated-resource pool and per-view display area; it does not create or edit QingBI report bodies/configs. Permission is split like the backend: resource pool writes use EditAppAuth, while `view_configs` uses the view config/DataManageAuth path. Use `patch_resources` for existing associated-resource parameter replacement; use `upsert_resources` for creation or full target config; `view_configs`, remove, and reorder may reference existing resources by internal `associated_item_id` or by `chart_id`/`chart_key`/`view_key`; use `match_mappings` with `target_field + operator + source_field/value` for associated view/report filters; publishes after successful writes; omit raw `sourceType`, and use `report_source="dataset"` only to attach an existing BI dataset report. Before `upsert_resources`, read `app_get.associated_resources` and reuse an existing matching `target_app_key + view_key/chart_key`; repeated upsert can create duplicates because `client_key` is only valid inside one apply call.
68
+ - `app_charts_apply`: create/edit/remove/reorder app-source QingBI report bodies/configs with `dataSourceType=qingflow`; it does not create/edit dataset BI reports and does not attach reports to Qingflow app associated-resource display. Use `app_get_fields.chart_fields` as the source for dimensions, metrics, and filters. Use semantic `metric`, `metrics`, `group_by`, and `where`: `target/indicator` for one KPI, `bar/columnar/pie` for distribution, `line/area` for trend, `table/detail/summary` for tabular summaries, and `dualaxes` for two-metric comparison. Do not use `summary` for a single metric card. Use `filters` with `field_name + operator + value/values`; the tool compiles them to QingBI string judge types. Use `patch_charts` for existing-chart parameter replacement; use `upsert_charts` for creation or full target config; avoid raw `indicator_field_ids`, `selectedMetrics`, and QingBI filter matrices on the main path; charts are immediate-live and do not publish; use `chart_id` when names are not unique; for complete systems, keep chart writes business-scoped, commonly 4-8 upserts by app or topic. Larger calls are accepted; if `CHART_UPSERT_BATCH_SIZE_RECOMMENDED` appears, read back before retrying and only repair failed items.
69
+ - `portal_apply`: create or replace-update portal pages; use `dash_key` for update mode or `package_id + dash_name` for create mode; create mode only prechecks package add_app, matching backend portal creation; edit mode may omit `sections` for base-info-only updates; when sections are supplied they still use replace semantics. Build portals only after referenced apps, raw `view_key`s, and chart ids/keys are known. PC layout uses 24 columns: components with the same `y` must have the same `rows`, same-row `cols` should sum to 24, metric cards use `rows=5`, BI charts use `rows=7`, data views use `rows=11`, and business-entry grids must include real `config.items[]`. Use business entry -> metrics -> BI charts -> concrete data views; do not use platform default views or raw `source_type: "filter"` as the main path.
56
70
 
57
- For object-level updates, the safe partial syntax is `patch_*` with the object's real selector field plus `set` and optional `unset`. `selector` is only a concept, not a literal key. Examples: `patch_views: [{"view_key": "VIEW_KEY", "set": {...}}]`, `patch_resources: [{"associated_item_id": 123, "set": {...}}]`, `patch_charts: [{"chart_id": 456, "set": {...}}]`, `patch_nodes: [{"id": "approve_1", "set": {...}}]`, `patch_sections: [{"chart": {"chart_key": "ck_001"}, "set": {"title": "新标题"}}]`. The tool reads the current backend config, merges the patch, then submits the full backend payload internally. Do not send a partial `upsert_*` and expect missing required fields to be preserved.
71
+ For object-level updates, use the object's real selector field plus `set` and optional `unset`; `selector` is only a concept, not a literal key. Examples: `views: [{"operation": "patch", "app_key": "APP_KEY", "view_key": "VIEW_KEY", "set": {...}}]`, `patch_buttons: [{"button_id": 1001, "set": {...}}]`, `patch_resources: [{"associated_item_id": 123, "set": {...}}]`, `patch_charts: [{"chart_id": 456, "set": {...}}]`. The tool reads the current backend config, merges the patch, then submits the full backend payload internally. Do not send a partial `upsert_*` and expect missing required fields to be preserved.
58
72
 
59
73
  ## Explicit post-apply tools
60
74
 
@@ -65,27 +79,27 @@ For object-level updates, the safe partial syntax is `patch_*` with the object's
65
79
  - Create one app inside an existing package:
66
80
  `package_get -> app_resolve -> app_schema_apply`
67
81
  - Create a brand new package, then create one app in it:
68
- `package_apply(create_if_missing=true) -> app_schema_apply`
82
+ `package_apply(package_name, icon, color) -> app_schema_apply`
69
83
  - Create a brand new multi-app system/package:
70
- `package_apply(create_if_missing=true) -> app_schema_apply(apps[] with form.sections)`
84
+ `package_apply(package_name, icon, color) -> app_schema_apply(apps[])`; use `apps[].client_key` plus `target_app_ref`, or `target_app` when referencing by app name
71
85
  - Update fields on an existing app:
72
86
  `app_resolve -> app_get_fields -> app_schema_apply`
73
87
  - Tidy layout:
74
- `app_get_fields -> app_get_layout -> app_layout_apply`
88
+ `app_get_fields -> app_get_layout -> builder_tool_contract (if shape is unclear) -> app_layout_apply`
75
89
  - Add workflow:
76
90
  `builder_tool_contract -> app_get_fields -> app_get_flow -> role_search/member_search -> app_flow_apply -> app_get_flow`
77
- - Update specific flow nodes:
78
- `app_get_flow -> app_flow_apply.patch_nodes[]`
79
91
  - Add views:
80
- `app_get_fields -> app_get_views -> app_views_apply.views[] -> app_get_views`
81
- - Add QingBI charts for a portal:
82
- `portal_apply.sections[].chart`
92
+ `builder_tool_contract -> app_get_fields -> app_get_views -> app_views_apply(views[]) -> app_get_views`
93
+ - Maintain advanced custom buttons:
94
+ `app_get -> app_custom_buttons_apply.patch_buttons/upsert_buttons + view_configs -> app_get_views`
95
+ - Add QingBI charts:
96
+ `builder_tool_contract -> app_get_fields -> app_get_charts -> app_charts_apply.patch_charts/upsert_charts -> app_get_charts`
83
97
  - Show an existing QingBI chart inside a Qingflow app/view:
84
98
  `app_get -> app_associated_resources_apply.upsert_resources/patch_resources + view_configs -> app_get`
85
99
  - Create or update a portal:
86
100
  `builder_tool_contract -> portal_get -> portal_apply -> portal_get`
87
- - Update portal section(s) without replacing all:
88
- `portal_get -> portal_apply.patch_sections[]`
101
+ - Patch one portal section:
102
+ `portal_get -> portal_apply.patch_sections[] -> portal_get`
89
103
 
90
104
  ## Avoid
91
105
 
@@ -103,3 +117,4 @@ For object-level updates, the safe partial syntax is `patch_*` with the object's
103
117
  - Do not omit assignees on approval/fill/copy nodes
104
118
  - Do not patch preset flows with brand new approval/fill node ids unless you are intentionally replacing the skeleton; reuse preset ids like `approve_1` and `fill_1`
105
119
  - Do not guess role ids, member ids, or editable field ids; resolve names first
120
+ - Do not force agent-authored schema into backend-internal names when public keys exist: write icons as `icon + color` first; `icon_config` / `icon:{name,color}` are compatibility aliases only. Options may use `{label,value}`, and same-call relation targets may use `target_app_ref` / `target_app`.
@@ -6,18 +6,19 @@ Use this when the app already exists and the task is only about workflow.
6
6
 
7
7
  1. `builder_tool_contract(tool_name="app_flow_apply")`
8
8
  2. `app_get_fields`
9
- 3. `app_get_flow`
10
- 4. `role_search` or `member_search`
11
- 5. `role_create` if the user wants a reusable directory role and no good role exists
12
- 6. start from a canonical preset when possible
13
- 7. patch the skeleton instead of freehanding a full graph
14
- 8. reuse preset node ids when patching:
9
+ 3. Confirm the app has one explicit business status field, usually a `select` named `状态`, `处理状态`, `审批状态`, `工单状态`, or `流程阶段`
10
+ 4. `app_get_flow`
11
+ 5. `role_search` or `member_search`
12
+ 6. `role_create` if the user wants a reusable directory role and no good role exists
13
+ 7. start from a canonical preset when possible
14
+ 8. patch the skeleton instead of freehanding a full graph
15
+ 9. reuse preset node ids when patching:
15
16
  - `basic_approval` -> patch `approve_1`
16
17
  - `basic_fill_then_approve` -> patch `fill_1` and `approve_1`
17
18
  Do not add a second approval/fill node with a new id unless you are intentionally replacing the skeleton.
18
19
  The MCP now auto-aligns the simplest single-node preset overrides, but still prefer explicit preset ids so the merged graph stays predictable.
19
- 9. `app_flow_apply`
20
- 10. `app_get_flow` when apply returns `partial_success` or the user asked for verification
20
+ 10. `app_flow_apply`
21
+ 11. `app_get_flow` when apply returns `partial_success` or the user asked for verification
21
22
 
22
23
  If you are unsure about presets or node shapes, call `builder_tool_contract(tool_name="app_flow_apply")` before guessing.
23
24
 
@@ -55,50 +56,13 @@ Apply a simple approval flow with a role assignee and node-level editable fields
55
56
  }
56
57
  ```
57
58
 
58
- For flexible business requirements, do not jump straight to a full custom graph. Use this safer pattern:
59
+ For flexible business requirements, do not freehand hidden backend fields. Use this safer pattern:
59
60
 
60
- 1. build a base skeleton from a preset
61
- 2. identify the business-specific changes
62
- 3. patch nodes/transitions explicitly
61
+ 1. read `app_flow_get_schema`
62
+ 2. read the current flow with `app_get_flow` / `app_flow_get`
63
+ 3. use `patch_nodes` for targeted edits, or submit a complete `spec` when replacing the workflow
63
64
 
64
- ## Targeted node updates
65
-
66
- To change one or a few nodes without rewriting the full spec, use `patch_nodes[]` instead of `spec`:
67
-
68
- ```json
69
- {
70
- "tool_name": "app_flow_apply",
71
- "arguments": {
72
- "profile": "default",
73
- "app_key": "APP_123",
74
- "publish": true,
75
- "patch_nodes": [
76
- {
77
- "id": "approve_1",
78
- "set": {
79
- "name": "总监审批",
80
- "assignees": {"role_names": ["总监"]}
81
- }
82
- }
83
- ]
84
- }
85
- }
86
- ```
87
-
88
- `patch_nodes[]` reads the current flow, merges `set` keys and removes `unset` keys on the matched node, then writes the full spec back. It returns `FLOW_NODE_NOT_FOUND` if the `id` does not match any existing node — call `app_get_flow` first to confirm ids.
89
-
90
- Do NOT use `patch_nodes` and `spec` together in the same call.
91
-
92
- Public flow building is intentionally limited to linear workflows. Use only:
93
-
94
- - `start`
95
- - `approve`
96
- - `fill`
97
- - `copy`
98
- - `webhook`
99
- - `end`
100
-
101
- Do not generate `branch` or `condition` nodes through `app_flow_apply`. The backend workflow route is not front-end stable for those node types, and MCP now returns `FLOW_NODE_TYPE_UNSUPPORTED` instead of writing a visually broken flow.
65
+ Legacy `nodes/transitions` input is still limited to simple linear public aliases: `start`, `approve`, `fill`, `copy`, `webhook`, and `end`. Requirements that need branching or richer routing should use the WorkflowSpec `spec` path after reading the schema.
102
66
  After `app_flow_apply` returns blocking issues or canonical arguments, prefer reusing its `suggested_next_call.arguments` directly. Do not rewrite the result into internal fields such as `role_entries` or `editable_que_ids`.
103
67
  When you patch a preset, patch the preset node itself. Do not leave the preset approval node unassigned while adding a second custom approval node.
104
68
 
@@ -124,7 +88,18 @@ Preferred fix order:
124
88
 
125
89
  ### `FLOW_DEPENDENCY_MISSING`
126
90
 
127
- The workflow depends on fields that do not exist yet, usually `status`. Fix schema first.
91
+ The workflow depends on fields that do not exist yet, usually an explicit business status field. Fix schema first.
92
+
93
+ Do:
94
+
95
+ - add a business field such as `状态`, `处理状态`, `审批状态`, `工单状态`, or `流程阶段`
96
+ - use type `select` / `single_select`
97
+ - use business options such as `草稿`, `进行中`, `已完成`
98
+
99
+ Do not:
100
+
101
+ - create platform workflow system fields such as `当前流程状态`, `当前处理人`, `当前处理节点`, or `流程标题`
102
+ - skip the flow and still report workflow completion
128
103
 
129
104
  Preferred recovery:
130
105
 
@@ -177,7 +152,7 @@ Do not copy internal keys from old plan outputs or logs, including:
177
152
 
178
153
  ## Notes
179
154
 
180
- - `mode=replace` is the only supported flow apply mode when using `spec`; `patch_nodes[]` does not require a `mode`
155
+ - `mode=replace` is the only supported flow apply mode
181
156
  - `app_flow_apply` publishes by default
182
157
  - Prefer roles over explicit members unless the user explicitly asks for named members
183
158
  - `basic_approval` and `basic_fill_then_approve` are skeletons, not complete business workflows
@@ -10,6 +10,18 @@ Use this when the app already exists and the task is only about fields.
10
10
 
11
11
  ## Example
12
12
 
13
+ Do not add platform system fields as form controls: `数据ID`, `编号`, `申请人`, `申请时间`, `创建人`, `创建时间`, `提交人`, `提交时间`, `更新时间`, `更新人`, `当前流程状态`, `当前处理人`, `当前处理节点`, `流程标题`. They are generated by Qingflow; use readback/list fields when you need them.
14
+
15
+ Field patch rules:
16
+
17
+ - Re-read fields first, then choose `add_fields`, `update_fields`, or `remove_fields`. If a field already exists, use `update_fields` instead of adding a duplicate.
18
+ - Drafts may use intuitive type aliases: `multiline -> long_text`, `select -> single_select`, `checkbox -> multi_select`, `currency -> amount`, `mobile -> phone`. Readback canonical types are normal and do not prove a failed update.
19
+ - `title` and `label` are accepted aliases for `name`, but the preferred public key is `name`.
20
+ - Keep exactly one top-level data title field after the patch. `as_data_cover` is optional and only valid on top-level `attachment`.
21
+ - Select fields must keep a clear `options` set. Sample data and filters should use those option labels or ids.
22
+ - Relation fields must use `target_app_key` for existing apps, or `target_app_ref` only in same-batch app creation. `display_field` and `visible_fields` are selector objects such as `{"name": "客户名称"}`, not bare strings.
23
+ - Do not impose a one-relation-field limit when updating schema; add the relation fields the business needs and rely on backend validation/readback.
24
+
13
25
  Read current fields first:
14
26
 
15
27
  ```json
@@ -64,9 +76,11 @@ Treat it as uncertain write state. Read back with `app_get_fields` before retryi
64
76
 
65
77
  - `title` and `label` are accepted aliases for `name`
66
78
  - `textarea -> long_text`
79
+ - `multiline` / `multiline_text -> long_text`
67
80
  - `currency -> amount`
68
81
  - `mobile -> phone`
69
82
  - `select/radio -> single_select`
70
83
  - `checkbox -> multi_select`
71
84
  - `as_data_title: true` marks the app data title; the final form must have exactly one top-level data title field
72
85
  - `as_data_cover: true` marks the app data cover; the cover is optional and must be a top-level `attachment` field
86
+ - `数据ID`, `编号`, applicant/creation/update time, and workflow status fields are system-generated and must not appear in `add_fields`
@@ -28,45 +28,89 @@ Canonical rules before any example:
28
28
  - Always use `columns`
29
29
  - Do not emit `column_names`
30
30
  - Treat `fields` only as a legacy alias the MCP may normalize, not as the preferred shape
31
- - Use `filters` with canonical keys `field_name`, `operator`, `value`/`values`
31
+ - Use `filters` with the unified fixed-filter DSL: `field_name`, `operator`, `value`/`values`; do not write raw `judgeType` / `judgeValues`
32
32
  - Use `query_conditions` for the frontend query panel. Do not put query-panel fields into `filters`.
33
- - When creating any new table or card view, always include `query_conditions` with `enabled: true`. In `rows`, list the fields users would most commonly search by — typically the data-title field, any status/type select fields, date fields, and member fields. Do not omit `query_conditions` or leave `rows` empty on a new view.
33
+ - Do not create views named `全部数据`, `我的数据`, `我发起的`, `待办`, `已办`, or `抄送`. These are built-in default/system views. New views must use business-specific names such as `订单台账视图`, `客户跟进视图`, or `逾期任务看板`.
34
+ - To change a built-in default/system view, first read the existing raw `view_key` from `app_get.views` or `app_get_views`, then use `views[]` with `operation: "patch"`.
34
35
  - New views created by `app_views_apply` default the frontend associated report/view area to visible with `limit_type="all"`. Existing views preserve their current associated-resource display unless `associated_resources` is explicitly patched.
35
- - Use `app_associated_resources_apply` for the associated report/view resource pool, selected resources, and match rules. `associated_item_id` is the internal associated-resource id from `app_get.associated_resources`; `view_configs`, remove, and reorder may also pass an existing resource's `chart_id`/`chart_key`/`view_key`, which the tool resolves to the internal id. Do not write backend raw `sourceType`; reports default to BI app reports, and dataset reports use `report_source="dataset"`. Use `match_mappings` for associated view/report filters; read `match-rules.md` if field type compatibility is unclear.
36
+ - Use `app_associated_resources_apply` for the associated report/view resource pool, selected resources, and match rules. Permission is split like the backend: resource pool writes use EditAppAuth, while `view_configs` uses the view config/DataManageAuth path. `associated_item_id` is the internal associated-resource id from `app_get.associated_resources`; `view_configs`, remove, and reorder may also pass an existing resource's `chart_id`/`chart_key`/`view_key`, which the tool resolves to the internal id. Do not write backend raw `sourceType`; reports default to BI app reports, and dataset reports use `report_source="dataset"`. Use `match_mappings` with `target_field + operator + source_field/value` for associated view/report filters; read `match-rules.md` if field type compatibility is unclear.
36
37
  - For gantt, use `start_field`, `end_field`, and optionally `title_field`
37
- - If `app_get.views` or `app_get_views` shows duplicate view names, include `view_key` in `upsert_views[]` and update that exact target
38
+ - If `app_get.views` or `app_get_views` shows duplicate view names, include `view_key` in `views[]` and update that exact target
38
39
  - Builder view writes always use the raw `view_key` from `app_get.views[].view_key`, such as `emsrao25rs02`. Do not pass `custom:emsrao25rs02`; that prefixed form is only for record-data `view_id`.
39
- - For an existing view, prefer `patch_views` for parameter replacement. Do not send a partial `upsert_views` object such as only `name/type/query_conditions`; backend view saves require other type-specific fields, and the patch path preserves them for you.
40
+ - For an existing view, prefer `views[].operation="patch"` for parameter replacement. Do not send a partial `upsert` object such as only `name/type/query_conditions`; backend view saves require other type-specific fields, and the patch path preserves them for you.
41
+ - For view-specific business buttons, declare `action_buttons` inside the same `views[]` item. For existing views, use `operation: "patch"` with `set.action_buttons`.
42
+ - Choose the button by user intent before choosing a trigger type:
43
+ - current record -> downstream/related record: `add_data` with `target_app_key + field_mappings`
44
+ - global independent entry: `add_data` on `header` without current-record `source_field`
45
+ - URL/SOP/help page: `link` with `url`
46
+ - approval/status transition/close task: do not fake it with a normal button; use workflow/task action or exact existing automation config
47
+ - Button placement choice: `header` is global and has no current-row context; `list` is row/list action; `detail` is the safest current-record context action. Do not use current-record `field_mappings` on `header`.
40
48
 
41
- Apply a default table view:
49
+ Apply a business table view:
42
50
 
43
51
  ```json
44
52
  {
45
53
  "tool_name": "app_views_apply",
46
54
  "arguments": {
47
55
  "profile": "default",
48
- "app_key": "APP_123",
49
56
  "publish": true,
50
- "upsert_views": [
57
+ "views": [
51
58
  {
52
- "name": "全部订单",
59
+ "operation": "upsert",
60
+ "app_key": "APP_123",
61
+ "name": "订单台账视图",
53
62
  "view_key": "VIEW_KEY_IF_DUPLICATE_NAMES_EXIST",
54
63
  "type": "table",
55
- "columns": ["订单编号", "客户名称", "订单金额", "状态", "负责人", "创建时间"],
56
- "query_conditions": {
57
- "enabled": true,
58
- "exact": false,
59
- "hide_before_query": false,
60
- "rows": [["订单编号", "客户名称"], ["状态", "负责人"], ["创建时间"]]
61
- }
64
+ "columns": ["订单编号", "客户名称", "订单金额", "状态"]
62
65
  }
63
- ],
64
- "remove_views": []
66
+ ]
65
67
  }
66
68
  }
67
69
  ```
68
70
  After `app_views_apply` returns canonical arguments or blocking issues, prefer reusing its `suggested_next_call.arguments` directly. Do not rewrite aliases back into non-canonical keys such as `column_names`.
69
71
 
72
+ Create a table view with ordinary business buttons:
73
+
74
+ ```json
75
+ {
76
+ "tool_name": "app_views_apply",
77
+ "arguments": {
78
+ "profile": "default",
79
+ "publish": true,
80
+ "views": [
81
+ {
82
+ "operation": "upsert",
83
+ "app_key": "APP_123",
84
+ "name": "工单执行视图",
85
+ "type": "table",
86
+ "columns": ["工单编号", "产品", "状态", "负责人"],
87
+ "action_buttons": [
88
+ {
89
+ "text": "创建质检单",
90
+ "action": "add_data",
91
+ "target_app_key": "QUALITY_APP",
92
+ "field_mappings": [
93
+ {"source_field": "数据ID", "target_field": "关联工单"}
94
+ ],
95
+ "default_values": {"处理状态": "待处理"},
96
+ "placement": "detail",
97
+ "visible_when": [
98
+ {"field_name": "状态", "operator": "eq", "value": "已完工"}
99
+ ]
100
+ },
101
+ {
102
+ "text": "查看作业说明",
103
+ "action": "link",
104
+ "url": "https://example.com/sop",
105
+ "placement": "header"
106
+ }
107
+ ]
108
+ }
109
+ ]
110
+ }
111
+ }
112
+ ```
113
+
70
114
  Existing table view: replace only frontend query conditions:
71
115
 
72
116
  ```json
@@ -74,10 +118,11 @@ Existing table view: replace only frontend query conditions:
74
118
  "tool_name": "app_views_apply",
75
119
  "arguments": {
76
120
  "profile": "default",
77
- "app_key": "APP_123",
78
121
  "publish": true,
79
- "patch_views": [
122
+ "views": [
80
123
  {
124
+ "operation": "patch",
125
+ "app_key": "APP_123",
81
126
  "view_key": "VIEW_KEY",
82
127
  "set": {
83
128
  "query_conditions": {
@@ -88,8 +133,7 @@ Existing table view: replace only frontend query conditions:
88
133
  }
89
134
  }
90
135
  }
91
- ],
92
- "remove_views": []
136
+ ]
93
137
  }
94
138
  }
95
139
  ```
@@ -168,16 +212,16 @@ Board example:
168
212
  "tool_name": "app_views_apply",
169
213
  "arguments": {
170
214
  "profile": "default",
171
- "app_key": "APP_123",
172
- "upsert_views": [
215
+ "views": [
173
216
  {
217
+ "operation": "upsert",
218
+ "app_key": "APP_123",
174
219
  "name": "按状态看板",
175
220
  "type": "board",
176
221
  "group_by": "状态",
177
222
  "columns": ["订单编号", "客户名称", "订单金额"]
178
223
  }
179
- ],
180
- "remove_views": []
224
+ ]
181
225
  }
182
226
  }
183
227
  ```
@@ -189,9 +233,10 @@ Gantt example with filters:
189
233
  "tool_name": "app_views_apply",
190
234
  "arguments": {
191
235
  "profile": "default",
192
- "app_key": "APP_123",
193
- "upsert_views": [
236
+ "views": [
194
237
  {
238
+ "operation": "upsert",
239
+ "app_key": "APP_123",
195
240
  "name": "项目甘特图",
196
241
  "type": "gantt",
197
242
  "columns": ["项目名称", "开始日期", "结束日期", "状态"],
@@ -206,8 +251,7 @@ Gantt example with filters:
206
251
  }
207
252
  ]
208
253
  }
209
- ],
210
- "remove_views": []
254
+ ]
211
255
  }
212
256
  }
213
257
  ```
@@ -277,7 +321,32 @@ At least one `query_conditions.rows` field does not exist on the app.
277
321
 
278
322
  ### `INVALID_QUERY_CONDITION_FIELD`
279
323
 
280
- The field exists but cannot be used in the frontend query-condition panel, such as attachment, relation, Q-Linker, code block, location/address, or subtable/subfield selections.
324
+ The field exists but cannot be used in the frontend query-condition panel.
325
+
326
+ Supported `query_conditions.rows` fields are query-panel fields:
327
+
328
+ - text / long text
329
+ - number / amount
330
+ - date / datetime
331
+ - single select / multi select
332
+ - member / department
333
+ - phone / email
334
+ - boolean
335
+
336
+ Do not use these fields in `query_conditions`:
337
+
338
+ - relation
339
+ - attachment
340
+ - subtable or subtable subfield
341
+ - address/location
342
+ - Q-Linker
343
+ - code block
344
+
345
+ Fix path:
346
+
347
+ - If you wanted a saved filter that opens with the view, use `filters`.
348
+ - If you wanted a related report/view to match the current record, use `app_associated_resources_apply.match_mappings`.
349
+ - If you only need frontend search fields, remove unsupported fields from `query_conditions.rows` and keep query-panel supported fields only.
281
350
 
282
351
  ## Notes
283
352
 
@@ -286,6 +355,6 @@ The field exists but cannot be used in the frontend query-condition panel, such
286
355
  - `app_get_views` should be treated as canonical readback and now returns `columns`
287
356
  - If `app_views_apply` returns `AMBIGUOUS_VIEW`, stop and re-run `app_get_views`; then retry with the exact `view_key`
288
357
  - `filters` are ANDed together as one flat condition group
289
- - `query_conditions.rows` does not mean OR; it controls frontend query-field layout
358
+ - `query_conditions.rows` does not mean OR; it controls frontend query-field layout and should only contain query-panel supported fields
290
359
  - `app_views_apply` publishes by default
291
360
  - For select-style filters, success means the backend preserved the option value in readback, not just that the view name now exists