@josephyan/qingflow-app-user-mcp 0.2.0-beta.985 → 0.2.0-beta.987

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 (52) hide show
  1. package/README.md +2 -2
  2. package/docs/local-agent-install.md +70 -11
  3. package/package.json +1 -1
  4. package/pyproject.toml +1 -1
  5. package/skills/qingflow-app-user/SKILL.md +21 -12
  6. package/skills/qingflow-app-user/references/data-gotchas.md +1 -1
  7. package/skills/qingflow-app-user/references/public-surface-sync.md +70 -0
  8. package/skills/qingflow-app-user/references/record-patterns.md +1 -1
  9. package/skills/qingflow-record-analysis/SKILL.md +44 -2
  10. package/skills/qingflow-record-insert/SKILL.md +3 -0
  11. package/skills/qingflow-record-update/SKILL.md +3 -0
  12. package/skills/qingflow-task-ops/SKILL.md +31 -10
  13. package/src/qingflow_mcp/__init__.py +1 -1
  14. package/src/qingflow_mcp/builder_facade/service.py +376 -19
  15. package/src/qingflow_mcp/cli/commands/auth.py +14 -43
  16. package/src/qingflow_mcp/cli/commands/workspace.py +8 -5
  17. package/src/qingflow_mcp/cli/formatters.py +19 -22
  18. package/src/qingflow_mcp/config.py +39 -0
  19. package/src/qingflow_mcp/errors.py +2 -2
  20. package/src/qingflow_mcp/public_surface.py +4 -6
  21. package/src/qingflow_mcp/response_trim.py +1 -8
  22. package/src/qingflow_mcp/server.py +1 -1
  23. package/src/qingflow_mcp/server_app_builder.py +4 -28
  24. package/src/qingflow_mcp/server_app_user.py +4 -28
  25. package/src/qingflow_mcp/session_store.py +31 -5
  26. package/src/qingflow_mcp/solution/compiler/form_compiler.py +2 -2
  27. package/src/qingflow_mcp/solution/executor.py +2 -2
  28. package/src/qingflow_mcp/tools/ai_builder_tools.py +117 -1
  29. package/src/qingflow_mcp/tools/app_tools.py +51 -1
  30. package/src/qingflow_mcp/tools/approval_tools.py +82 -1
  31. package/src/qingflow_mcp/tools/auth_tools.py +306 -288
  32. package/src/qingflow_mcp/tools/base.py +204 -4
  33. package/src/qingflow_mcp/tools/code_block_tools.py +21 -0
  34. package/src/qingflow_mcp/tools/custom_button_tools.py +24 -1
  35. package/src/qingflow_mcp/tools/directory_tools.py +28 -1
  36. package/src/qingflow_mcp/tools/feedback_tools.py +8 -0
  37. package/src/qingflow_mcp/tools/file_tools.py +25 -1
  38. package/src/qingflow_mcp/tools/import_tools.py +40 -1
  39. package/src/qingflow_mcp/tools/navigation_tools.py +34 -1
  40. package/src/qingflow_mcp/tools/package_tools.py +37 -1
  41. package/src/qingflow_mcp/tools/portal_tools.py +28 -1
  42. package/src/qingflow_mcp/tools/qingbi_report_tools.py +38 -1
  43. package/src/qingflow_mcp/tools/record_tools.py +255 -2
  44. package/src/qingflow_mcp/tools/repository_dev_tools.py +21 -2
  45. package/src/qingflow_mcp/tools/resource_read_tools.py +23 -1
  46. package/src/qingflow_mcp/tools/role_tools.py +19 -1
  47. package/src/qingflow_mcp/tools/solution_tools.py +56 -1
  48. package/src/qingflow_mcp/tools/task_context_tools.py +72 -1
  49. package/src/qingflow_mcp/tools/task_tools.py +49 -3
  50. package/src/qingflow_mcp/tools/view_tools.py +56 -1
  51. package/src/qingflow_mcp/tools/workflow_tools.py +65 -1
  52. package/src/qingflow_mcp/tools/workspace_tools.py +100 -217
package/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  Install:
4
4
 
5
5
  ```bash
6
- npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.985
6
+ npm install @josephyan/qingflow-app-user-mcp@0.2.0-beta.987
7
7
  ```
8
8
 
9
9
  Run:
10
10
 
11
11
  ```bash
12
- npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.985 qingflow-app-user-mcp
12
+ npx -y -p @josephyan/qingflow-app-user-mcp@0.2.0-beta.987 qingflow-app-user-mcp
13
13
  ```
14
14
 
15
15
  Environment:
@@ -6,6 +6,20 @@
6
6
  2. 记录/待办优先的 `qingflow-app-user-mcp`
7
7
  3. 精简 builder 的 `qingflow-app-builder-mcp`
8
8
 
9
+ ## 本地鉴权推荐方案
10
+
11
+ 本地模式现在推荐优先使用 `credential` 建立会话,而不是直接注入 `token`。
12
+
13
+ 推荐链路:
14
+
15
+ 1. createClaw 或其它本地宿主为当前实例保存 `credential`
16
+ 2. 本地 MCP 调用 `auth_use_credential`
17
+ 3. MCP 用该 `credential` 请求 apaas `/mcp/auth/context`
18
+ 4. 解析并保存 `token / wsId / qfVersion / uid`
19
+ 5. 业务工具直接使用这份上下文
20
+
21
+ `auth_use_credential` 是本地唯一鉴权主路径。
22
+
9
23
  ## npm 安装器适用场景
10
24
 
11
25
  适合这类本地 agent / gateway:
@@ -63,17 +77,17 @@ npm run pack:npm
63
77
  会生成:
64
78
 
65
79
  ```bash
66
- dist/npm/josephyan-qingflow-cli-<version>.tgz
67
- dist/npm/josephyan-qingflow-app-user-mcp-<version>.tgz
68
- dist/npm/josephyan-qingflow-app-builder-mcp-<version>.tgz
80
+ dist/npm/qingflow-tech-qingflow-cli-<version>.tgz
81
+ dist/npm/qingflow-tech-qingflow-app-user-mcp-<version>.tgz
82
+ dist/npm/qingflow-tech-qingflow-app-builder-mcp-<version>.tgz
69
83
  ```
70
84
 
71
85
  然后在目标机器安装:
72
86
 
73
87
  ```bash
74
- npm install /absolute/path/to/dist/npm/josephyan-qingflow-cli-<version>.tgz
75
- npm install /absolute/path/to/dist/npm/josephyan-qingflow-app-user-mcp-<version>.tgz
76
- npm install /absolute/path/to/dist/npm/josephyan-qingflow-app-builder-mcp-<version>.tgz
88
+ npm install /absolute/path/to/dist/npm/qingflow-tech-qingflow-cli-<version>.tgz
89
+ npm install /absolute/path/to/dist/npm/qingflow-tech-qingflow-app-user-mcp-<version>.tgz
90
+ npm install /absolute/path/to/dist/npm/qingflow-tech-qingflow-app-builder-mcp-<version>.tgz
77
91
  ```
78
92
 
79
93
  安装时会自动:
@@ -136,7 +150,10 @@ qingflow-app-builder-mcp
136
150
  ],
137
151
  "env": {
138
152
  "QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api",
139
- "QINGFLOW_MCP_HOME": "/absolute/path/to/.qingflow-mcp"
153
+ "QINGFLOW_MCP_HOME": "/absolute/path/to/.qingflow-mcp",
154
+ "QINGFLOW_MCP_CREDIT_METER_ENABLED": "true",
155
+ "QINGFLOW_MCP_CREDIT_APAAS_BASE_URL": "https://apaas.internal.example.com",
156
+ "QINGFLOW_MCP_CREDIT_APAAS_PATH": "/user/credit/usage"
140
157
  }
141
158
  }
142
159
  }
@@ -153,7 +170,10 @@ qingflow-app-builder-mcp
153
170
  "args": [],
154
171
  "env": {
155
172
  "QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api",
156
- "QINGFLOW_MCP_HOME": "/absolute/path/to/.qingflow-mcp"
173
+ "QINGFLOW_MCP_HOME": "/absolute/path/to/.qingflow-mcp",
174
+ "QINGFLOW_MCP_CREDIT_METER_ENABLED": "true",
175
+ "QINGFLOW_MCP_CREDIT_APAAS_BASE_URL": "https://apaas.internal.example.com",
176
+ "QINGFLOW_MCP_CREDIT_APAAS_PATH": "/user/credit/usage"
157
177
  }
158
178
  }
159
179
  }
@@ -170,7 +190,10 @@ qingflow-app-builder-mcp
170
190
  "args": [],
171
191
  "env": {
172
192
  "QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api",
173
- "QINGFLOW_MCP_HOME": "/absolute/path/to/.qingflow-mcp"
193
+ "QINGFLOW_MCP_HOME": "/absolute/path/to/.qingflow-mcp",
194
+ "QINGFLOW_MCP_CREDIT_METER_ENABLED": "true",
195
+ "QINGFLOW_MCP_CREDIT_APAAS_BASE_URL": "https://apaas.internal.example.com",
196
+ "QINGFLOW_MCP_CREDIT_APAAS_PATH": "/user/credit/usage"
174
197
  }
175
198
  }
176
199
  }
@@ -191,7 +214,10 @@ qingflow-app-builder-mcp
191
214
  "@josephyan/qingflow-app-user-mcp"
192
215
  ],
193
216
  "env": {
194
- "QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api"
217
+ "QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api",
218
+ "QINGFLOW_MCP_CREDIT_METER_ENABLED": "true",
219
+ "QINGFLOW_MCP_CREDIT_APAAS_BASE_URL": "https://apaas.internal.example.com",
220
+ "QINGFLOW_MCP_CREDIT_APAAS_PATH": "/user/credit/usage"
195
221
  }
196
222
  },
197
223
  "qingflow-builder": {
@@ -201,7 +227,10 @@ qingflow-app-builder-mcp
201
227
  "@josephyan/qingflow-app-builder-mcp"
202
228
  ],
203
229
  "env": {
204
- "QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api"
230
+ "QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api",
231
+ "QINGFLOW_MCP_CREDIT_METER_ENABLED": "true",
232
+ "QINGFLOW_MCP_CREDIT_APAAS_BASE_URL": "https://apaas.internal.example.com",
233
+ "QINGFLOW_MCP_CREDIT_APAAS_PATH": "/user/credit/usage"
205
234
  }
206
235
  }
207
236
  }
@@ -212,6 +241,7 @@ qingflow-app-builder-mcp
212
241
  - 源码目录 `npm install` 不会把命令加到全局 PATH;这种模式请用 `node ./npm/bin/qingflow.mjs`、`node ./npm/bin/qingflow-app-user-mcp.mjs` 或 `node ./npm/bin/qingflow-app-builder-mcp.mjs`
213
242
  - `npx` 方式适合临时安装或容器化本地 agent
214
243
  - 全局安装方式更适合长期固定使用的本机开发环境
244
+ - 计费接口使用当前登录会话的 `token` 与 `wsId` 请求头,可通过 `QINGFLOW_MCP_CREDIT_APAAS_BASE_URL/PATH` 覆盖调用记录接口地址
215
245
 
216
246
  ## 排障
217
247
 
@@ -242,3 +272,32 @@ npm install
242
272
  4. 再启动 MCP 客户端
243
273
 
244
274
  现在 stdio MCP 入口会拒绝在启动瞬间“边启动边重建 Python 运行时”,因为安装日志一旦写进 stdout,就会破坏 MCP 握手并表现成 `Transport closed`。如果运行时缺失或版本不一致,入口会直接报错并提示重装,而不是静默自修复。
275
+
276
+ ## createClaw 本地接入示例
277
+
278
+ 如果 createClaw 已经为当前本地实例保存了 `credential`,推荐在首次建链时调用:
279
+
280
+ ```bash
281
+ qingflow auth use-credential \
282
+ --base-url https://qingflow.com/api \
283
+ --credential-stdin
284
+ ```
285
+
286
+ 然后把 `credential` 写到 stdin。
287
+
288
+ 等价 MCP 工具调用参数:
289
+
290
+ ```json
291
+ {
292
+ "profile": "default",
293
+ "base_url": "https://qingflow.com/api",
294
+ "credential": "1602853_277941",
295
+ "persist": false
296
+ }
297
+ ```
298
+
299
+ 说明:
300
+
301
+ - 本地会把解析后的 `token` 和原始 `credential` 写入 profile 文件,用于后续 CLI 命令恢复会话
302
+ - `persist=true` 时,本地还会优先把解析后的 `token` 和原始 `credential` 同步写入系统 keychain
303
+ - 当前工作区以 `/mcp/auth/context` 返回的 `wsId` 为准,不再通过本地 MCP 显式切换
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyan/qingflow-app-user-mcp",
3
- "version": "0.2.0-beta.985",
3
+ "version": "0.2.0-beta.987",
4
4
  "description": "Operational end-user MCP for Qingflow records, tasks, comments, and directory workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qingflow-mcp"
7
- version = "0.2.0b985"
7
+ version = "0.2.0b987"
8
8
  description = "User-authenticated MCP server for Qingflow"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -11,31 +11,35 @@ metadata:
11
11
 
12
12
  This skill is a lightweight router for operational Qingflow work.
13
13
  Assumes MCP is connected, authenticated, and on the correct workspace.
14
+ Before routing, skim the shared maintenance baseline: [public-surface-sync.md](references/public-surface-sync.md).
14
15
 
15
16
  ## Default Paths
16
17
 
17
18
  Route to exactly one of these specialized paths:
18
19
 
19
20
  1. Record insert
20
- Switch to [$qingflow-record-insert](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-insert/SKILL.md)
21
+ Switch to [$qingflow-record-insert](../qingflow-record-insert/SKILL.md)
21
22
 
22
23
  2. Record update
23
- Switch to [$qingflow-record-update](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-update/SKILL.md)
24
+ Switch to [$qingflow-record-update](../qingflow-record-update/SKILL.md)
24
25
 
25
26
  3. Record delete
26
- Switch to [$qingflow-record-delete](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-delete/SKILL.md)
27
+ Switch to [$qingflow-record-delete](../qingflow-record-delete/SKILL.md)
27
28
 
28
29
  4. Record import
29
- Switch to [$qingflow-record-import](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-import/SKILL.md)
30
+ Switch to [$qingflow-record-import](../qingflow-record-import/SKILL.md)
30
31
 
31
32
  5. Task workflow operations
32
- Switch to [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md)
33
+ Switch to [$qingflow-task-ops](../qingflow-task-ops/SKILL.md)
33
34
 
34
35
  6. Analysis
35
- Switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
36
+ Switch to [$qingflow-record-analysis](../qingflow-record-analysis/SKILL.md)
36
37
 
37
38
  7. MCP connection / auth / workspace selection
38
- Switch to [$qingflow-mcp-setup](/Users/yanqidong/.codex/skills/qingflow-mcp-setup/SKILL.md)
39
+ Switch to [$qingflow-mcp-setup](../qingflow-mcp-setup/SKILL.md)
40
+
41
+ 8. App / view / workflow / chart / portal / package configuration
42
+ Switch to [$qingflow-app-builder](../qingflow-app-builder/SKILL.md)
39
43
 
40
44
  ## Routing Rules
41
45
 
@@ -46,11 +50,13 @@ Route to exactly one of these specialized paths:
46
50
  - If the task is about deleting records directly, switch to `$qingflow-record-delete`
47
51
  - If the task is about import templates, import capability discovery, import-file verification, authorized local file repair, import execution, or import status, switch to `$qingflow-record-import`
48
52
  - If the task is about todo discovery, task context, approval actions, rollback or transfer, associated report review, or workflow log review, switch to `$qingflow-task-ops`
53
+ - If the task is about package, app, field, layout, workflow, view, chart, portal, visibility, icon, or app base configuration, switch to `$qingflow-app-builder`
49
54
  - If the task involves member, department, or relation fields and the user only has natural names/titles, keep the same route; direct write now supports backend-native auto resolution and may return `needs_confirmation` with candidates instead of failing blind
50
55
  - If the task involves linked visibility, upstream/downstream field dependencies, reference-driven auto fill, or formula-driven defaulting, keep the same insert/update route and read field-level `linkage` from the schema before composing payloads
51
56
  - If the task is about subtable writes, still route to the matching insert/update skill, but shape the payload as parent subtable field -> row array; do not route users toward top-level leaf selectors
52
57
  - If the task is insert-focused and readback consistency matters, keep the same route and prefer `record_get / record_list` with `output_profile="normalized"` after the write
53
58
  - If the user sounds like an ordinary workflow assignee rather than a system operator, prefer `$qingflow-task-ops` over direct record mutation whenever both paths could fit
59
+ - If the task is about task discovery by natural language query, still route to `$qingflow-task-ops`; `task_list --query` now uses backend search first and only falls back to local matching when backend returns zero rows
54
60
  - If the task is about grouped distributions, ratios, rankings, trends, insights, or any final statistical conclusion, switch to `$qingflow-record-analysis`
55
61
  - If the MCP is not connected, authenticated, or bound to the right workspace, switch to `$qingflow-mcp-setup`
56
62
 
@@ -72,8 +78,11 @@ Route to exactly one of these specialized paths:
72
78
 
73
79
  ## Resources
74
80
 
75
- - Record insert: [$qingflow-record-insert](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-insert/SKILL.md)
76
- - Record update: [$qingflow-record-update](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-update/SKILL.md)
77
- - Record delete: [$qingflow-record-delete](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-delete/SKILL.md)
78
- - Record import: [$qingflow-record-import](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-import/SKILL.md)
79
- - Dedicated analysis workflow: [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md)
81
+ - Shared public-surface baseline: [public-surface-sync.md](references/public-surface-sync.md)
82
+ - Record insert: [$qingflow-record-insert](../qingflow-record-insert/SKILL.md)
83
+ - Record update: [$qingflow-record-update](../qingflow-record-update/SKILL.md)
84
+ - Record delete: [$qingflow-record-delete](../qingflow-record-delete/SKILL.md)
85
+ - Record import: [$qingflow-record-import](../qingflow-record-import/SKILL.md)
86
+ - Task workflow operations: [$qingflow-task-ops](../qingflow-task-ops/SKILL.md)
87
+ - Dedicated analysis workflow: [$qingflow-record-analysis](../qingflow-record-analysis/SKILL.md)
88
+ - Builder workflow: [$qingflow-app-builder](../qingflow-app-builder/SKILL.md)
@@ -1,6 +1,6 @@
1
1
  # Data Gotchas
2
2
 
3
- For final statistics, grouped distributions, rankings, trends, or insight-style conclusions, use [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md) instead of keeping that reasoning inside `$qingflow-app-user`.
3
+ For final statistics, grouped distributions, rankings, trends, or insight-style conclusions, use [$qingflow-record-analysis](../../qingflow-record-analysis/SKILL.md) instead of keeping that reasoning inside `$qingflow-app-user`.
4
4
 
5
5
  ## Record Reads
6
6
 
@@ -0,0 +1,70 @@
1
+ # Qingflow Core Public Surface Sync
2
+
3
+ Use this file as the maintenance baseline for the core Qingflow skills.
4
+ It is not a user-facing product spec. It exists to prevent skill drift.
5
+
6
+ ## Current Public Defaults
7
+
8
+ ### User data
9
+
10
+ - Read range first with `app_get`, then `record_browse_schema_get(view_id=...)`
11
+ - Standard flows:
12
+ - browse / export detail: `app_get -> record_browse_schema_get -> record_list / record_get`
13
+ - insert: `record_insert_schema_get -> record_insert`
14
+ - update: `record_update_schema_get -> record_update`
15
+ - analyze: `app_get -> record_browse_schema_get -> record_analyze`
16
+
17
+ ### Tasks
18
+
19
+ - Discovery stays on `task_list`
20
+ - `task_list --query` uses backend search first and only applies local fallback when backend returns zero rows
21
+ - Public actions are:
22
+ - `approve`
23
+ - `reject`
24
+ - `rollback`
25
+ - `transfer`
26
+ - `urge`
27
+ - `save_only`
28
+ - `reject` requires `payload.audit_feedback`
29
+ - `save_only` requires non-empty `fields`
30
+ - `TASK_RUNTIME_CONSUMED_AFTER_ACTION` is a normal post-success warning when the current node runtime is consumed and `46001` appears on re-read
31
+
32
+ ### Builder
33
+
34
+ - Official package entry: `package_get`, `package_apply`
35
+ - Official builder writes:
36
+ - `app_schema_apply`
37
+ - `app_layout_apply`
38
+ - `app_flow_apply`
39
+ - `app_views_apply`
40
+ - `app_charts_apply`
41
+ - `portal_apply`
42
+ - `app_publish_verify`
43
+ - `portal_apply` edit mode may omit `sections` for base-info-only updates
44
+ - `app_charts_apply.visibility` is a public capability and should be treated as a base-only visibility update
45
+ - `app_get.editability` uses:
46
+ - `can_edit_app_base`
47
+ - `can_edit_form`
48
+ - `can_edit_flow`
49
+ - `can_edit_views`
50
+ - `can_edit_charts`
51
+
52
+ ## Known High-Drift Areas
53
+
54
+ - Task actions, especially `save_only`, reject payload requirements, and `46001` post-action interpretation
55
+ - Package public tools: do not regress to `package_create` / `package_attach_app` as the public default story
56
+ - App editability: do not let `can_edit_form` imply app base-info writes
57
+ - Portal and chart visibility: keep the public story on `portal_apply` / `app_charts_apply`, not low-level internal writes
58
+ - Analysis fallback: standard path stays `record_analyze`, but complex tables may require explicit fallback modes
59
+
60
+ ## Release Checklist For Skill Maintenance
61
+
62
+ After each beta that changes public behavior, re-check:
63
+
64
+ 1. `public_surface.py`
65
+ 2. `README.md`
66
+ 3. `server_app_builder.py` and `server.py` top-level guidance
67
+ 4. CLI help for `task`, `builder package`, `builder portal`, `builder charts`
68
+ 5. Whether new warnings or verification fields need to be explained in skills
69
+
70
+ If a tool behavior changed but the public surface did not, prefer updating the relevant skill section instead of expanding this file.
@@ -1,6 +1,6 @@
1
1
  # Record Patterns
2
2
 
3
- If the task shifts into grouped analysis, ratio, ranking, trend, or any final statistical conclusion, switch to [$qingflow-record-analysis](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-record-analysis/SKILL.md).
3
+ If the task shifts into grouped analysis, ratio, ranking, trend, or any final statistical conclusion, switch to [$qingflow-record-analysis](../../qingflow-record-analysis/SKILL.md).
4
4
 
5
5
  ## Browse Pattern
6
6
 
@@ -17,7 +17,42 @@ If `app_get.accessible_views` marks a view with `analysis_supported=false`, do n
17
17
 
18
18
  This is the ONLY execution order. Never skip `app_get` when the browse range is unclear. Never call `record_analyze` without a browse schema.
19
19
 
20
- Core tools: `app_get`, `record_browse_schema_get`, `record_analyze`. Use `record_list`/`record_get` only for post-analysis samples; task/comment work stays in [$qingflow-task-ops](/Users/yanqidong/Documents/qingflow-next/.codex/skills/qingflow-task-ops/SKILL.md).
20
+ Core tools: `app_get`, `record_browse_schema_get`, `record_analyze`. Use `record_list`/`record_get` only for post-analysis samples or an explicit fallback. Task/comment work stays in [$qingflow-task-ops](../qingflow-task-ops/SKILL.md).
21
+
22
+ ## Execution Modes
23
+
24
+ Choose the lightest mode that can still support a trustworthy conclusion:
25
+
26
+ 1. `server_aggregate`
27
+ - Default and preferred path
28
+ - Use `record_analyze` directly after `app_get -> record_browse_schema_get`
29
+
30
+ 2. `client_aggregate_from_record_list`
31
+ - Allowed fallback when `record_analyze` is unstable, unsupported on the target view, or the table is complex enough that service-side aggregation is not trustworthy
32
+ - Still requires `app_get -> record_browse_schema_get` first
33
+ - Use only after disclosing that the result is a fallback built from detail rows
34
+
35
+ 3. `cross_app_manual_reconcile`
36
+ - Use when the question depends on joining multiple apps, organization-history alias mapping, or other business logic that current public tools do not express directly
37
+ - Be explicit that the conclusion is based on manual reconciliation rules, not one single DSL execution
38
+
39
+ ## Fallback Ladder
40
+
41
+ Trigger a fallback when any of these are true:
42
+
43
+ - `record_analyze` is unstable or cannot complete the scan reliably
44
+ - the target view is unsupported for analysis
45
+ - field semantics are ambiguous enough that a server aggregate would be misleading
46
+ - the question requires cross-app reconciliation
47
+ - the question depends on organization-tree scope, historical department aliases, or other business rules that are not first-class MCP filters
48
+
49
+ When you fall back:
50
+
51
+ 1. Keep the standard read order: `app_get -> record_browse_schema_get`
52
+ 2. State which fallback mode you chose
53
+ 3. State whether the result is still full-scope or only a verified subset
54
+ 4. State the time field, organization scope, and any alias mapping used
55
+ 5. Prefer concrete numbers plus a conservative conclusion over broad wording
21
56
 
22
57
  ---
23
58
 
@@ -129,7 +164,7 @@ Top-level arguments:
129
164
  - Do not pass field titles, aliases, or guessed ids.
130
165
  - If `completeness.statement_scope=returned_groups_only` or `completeness.rows_truncated=true`, downgrade wording to returned groups only.
131
166
  - One DSL per question. Multiple small DSLs > one overloaded request.
132
- - `record_list` is NEVER the basis for final statistics.
167
+ - `record_list` is not the default basis for final statistics. Use it only in an explicit fallback mode and disclose that fallback in the final answer.
133
168
  - Set `alias` for any metric you will sort by, compare, or quote.
134
169
 
135
170
  ---
@@ -137,12 +172,18 @@ Top-level arguments:
137
172
  ## OUTPUT
138
173
 
139
174
  - Final answer must show concrete numbers.
175
+ - Final answer must state which execution mode was used whenever the answer is not a straightforward `server_aggregate`
140
176
  - If `result.rows` exists, list each returned row; if there are more than 20 rows, show Top 20 and say so.
141
177
  - 占比 = 行指标值 / `result.totals.metric_totals` 总值;如 `metric_totals` 缺失,用各行之和作分母。
142
178
  - Prefer the structured `ranking` block when it exists.
143
179
  - `safe_for_final_conclusion=true` → `全量可信结论`
144
180
  - Otherwise → `初步观察`
145
181
  - `rows_truncated=true` → 用 `前 N 个分组`, 不用 `全部`/`所有`
182
+ - If you used a fallback mode, explicitly disclose:
183
+ - whether this is full-scope or a manually curated subset
184
+ - which time field was used
185
+ - which organization scope was used
186
+ - whether any historical department aliases or cross-app joins were applied
146
187
 
147
188
  ## Feedback Escalation
148
189
 
@@ -152,6 +193,7 @@ Top-level arguments:
152
193
 
153
194
  ## Resources
154
195
 
196
+ - Shared public-surface baseline: [public-surface-sync.md](../qingflow-app-user/references/public-surface-sync.md)
155
197
  - DSL templates: [references/dsl-templates.md](references/dsl-templates.md)
156
198
  - Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
157
199
  - Confidence reporting: [references/confidence-reporting.md](references/confidence-reporting.md)
@@ -36,6 +36,8 @@ metadata:
36
36
  13. If the write returns `status="needs_confirmation"`, stop and surface the candidates
37
37
  14. Retry with explicit ids / objects only after the user confirms
38
38
  15. Keep `verify_write=true` for production inserts
39
+ 16. If post-write readback consistency matters, prefer `record_get(..., output_profile="normalized")` and surface `normalized_ambiguous_fields` instead of pretending same-title columns are unambiguous
40
+ 17. Treat nested schema shape as guidance, not a brittle contract; do not hard-code transient implementation details like optional nested `field_id` shape when composing inserts
39
41
 
40
42
  ## Field Notes
41
43
 
@@ -56,3 +58,4 @@ metadata:
56
58
  - Do not invent missing required fields
57
59
  - Do not flatten subtable leaf fields to the top level
58
60
  - Do not silently guess member / department / relation ids
61
+ - Do not bind logic to a transient nested schema serialization detail when the field title and parent table already identify the legal payload shape
@@ -33,6 +33,8 @@ metadata:
33
33
  11. If the write returns `status="needs_confirmation"`, stop and surface the candidates
34
34
  12. Do not assume any arbitrary combination of writable fields will succeed; one single matched accessible view still has to cover the payload
35
35
  13. Do not look for any extra context bucket in update schema; lookup behavior stays inline on the field definitions themselves
36
+ 14. When update context feels unstable, trust `record_update_schema_get`'s route-aware matched-view result over guessed `view_id` or remembered UI scope
37
+ 15. If readback consistency matters, prefer `record_get(..., output_profile="normalized")` after the write and surface `normalized_ambiguous_fields` instead of hiding same-title conflicts
36
38
 
37
39
  ## Do Not
38
40
 
@@ -40,3 +42,4 @@ metadata:
40
42
  - Do not update fields missing from `writable_fields`
41
43
  - Do not resolve lookup fields against a guessed record context
42
44
  - Do not ignore `linkage.affects_fields` when changing source-like fields on complex forms
45
+ - Do not fall back to guessed browse scopes when `record_update_schema_get` already tells you which matched route can or cannot execute the payload
@@ -11,6 +11,7 @@ metadata:
11
11
 
12
12
  This skill is for task workflow operations only.
13
13
  Assumes MCP is connected, authenticated, and on the correct workspace.
14
+ Before executing, skim the shared maintenance baseline: [public-surface-sync.md](../qingflow-app-user/references/public-surface-sync.md).
14
15
 
15
16
  ## Default Paths
16
17
 
@@ -28,6 +29,9 @@ Use exactly one of these default paths:
28
29
  4. Execute workflow action
29
30
  `task_list -> exact target -> task_get -> task_action_execute`
30
31
 
32
+ 5. Execute a user-specified action on an already-clear target
33
+ `task_list -> exact target -> (optional task_get) -> task_action_execute`
34
+
31
35
  ## Core Tools
32
36
 
33
37
  - `task_list`
@@ -43,16 +47,25 @@ Use exactly one of these default paths:
43
47
 
44
48
  ## Standard Operating Order
45
49
 
46
- 1. Ensure auth exists
47
- 2. Ensure workspace is selected
48
- 3. Discover the exact target with `task_list`
49
- 4. Read node context with `task_get`
50
- 5. Before giving any approval recommendation, read `task_workflow_log_get`
51
- 6. If `task_get` returns any `associated_reports`, read every visible report through `task_associated_report_detail_get`
52
- 7. Give an approval recommendation only after reviewing the node context, workflow log, and associated report details
53
- 8. Wait for explicit user confirmation before `task_action_execute`
54
- 9. Execute through `task_action_execute`
55
- 10. After actions, report the exact `app_key`, `record_id`, `workflow_node_id`, and executed action
50
+ Use one of these two modes:
51
+
52
+ 1. Recommendation mode
53
+ 1. Ensure auth exists
54
+ 2. Ensure workspace is selected
55
+ 3. Discover the exact target with `task_list`
56
+ 4. Read node context with `task_get`
57
+ 5. Before giving any approval recommendation, read `task_workflow_log_get`
58
+ 6. If `task_get` returns any `associated_reports`, read every visible report through `task_associated_report_detail_get`
59
+ 7. Give a recommendation only after reviewing node context, workflow log, and associated reports
60
+ 8. Wait for explicit user confirmation before `task_action_execute`
61
+
62
+ 2. User-directed execution mode
63
+ 1. Ensure auth exists
64
+ 2. Ensure workspace is selected
65
+ 3. Discover the exact target with `task_list`
66
+ 4. If the target or action requirements are ambiguous, read `task_get`; otherwise go straight to `task_action_execute`
67
+ 5. Execute through `task_action_execute`
68
+ 6. After actions, report the exact `app_key`, `record_id`, `workflow_node_id`, executed action, and any warnings
56
69
 
57
70
  ## Task-Center Rules
58
71
 
@@ -74,6 +87,7 @@ Use exactly one of these default paths:
74
87
  - `unread`
75
88
  - `ended`
76
89
  - `task_list` is the only public task discovery path in this MCP surface
90
+ - `task_list --query` uses backend `searchKey` first; only when backend returns zero rows does MCP apply a local fallback match on normalized `app_name / workflow_node_name / app_key / record_id`
77
91
  - Treat `task_id` as a locator only; the action primary key is `app_key + record_id + workflow_node_id`
78
92
  - Default box usage:
79
93
  - `todo`: `task_list -> task_get -> task_workflow_log_get / task_associated_report_detail_get -> recommendation -> explicit user confirmation -> task_action_execute`
@@ -91,15 +105,20 @@ Use exactly one of these default paths:
91
105
  - `rollback`
92
106
  - `transfer`
93
107
  - `urge`
108
+ - `save_only`
94
109
  - Before any approve/reject/rollback/transfer recommendation, always review `task_workflow_log_get` when `task_get.visibility.audit_record_visible=true`
95
110
  - If `task_get` returns visible `associated_reports`, review each one with `task_associated_report_detail_get`; do not rely on report summary alone
96
111
  - Do not give an approval recommendation based only on `task_get`
97
112
  - Do not execute `task_action_execute` until the user explicitly confirms the chosen action
113
+ - Exception: if the user has already explicitly authorized a concrete action on exact targets, you may execute directly after exact target resolution
98
114
  - Avoid actions on ambiguous tasks or records
99
115
  - Summarize the final action and the exact `app_key / record_id / workflow_node_id`
116
+ - `reject` requires `payload.audit_feedback`
117
+ - `save_only` requires non-empty `fields` and is only available when the backend exposes editable fields for the current node
100
118
  - `task_action_execute` now distinguishes action execution from workflow continuation. Read `verification.runtime_continuation_verified` before claiming the workflow actually moved on.
101
119
  - If `task_action_execute` returns `partial_success` with `WORKFLOW_CONTINUATION_UNVERIFIED`, report the action as sent but the downstream continuation as unverified.
102
120
  - If `task_action_execute` returns `TASK_CONTEXT_VISIBILITY_UNVERIFIED` after a `46001`-style context loss, do not claim the task was already processed unless the workflow log or record state proves it.
121
+ - If `task_action_execute` returns `TASK_RUNTIME_CONSUMED_AFTER_ACTION`, treat that as a normal post-success state: the current node runtime was consumed, the workflow likely continued, and `46001` does not by itself mean the action failed
103
122
 
104
123
  ## Feedback Escalation
105
124
 
@@ -110,11 +129,13 @@ Use exactly one of these default paths:
110
129
  ## Response Interpretation
111
130
 
112
131
  - `task_list` returns normalized todo rows and is the only default discovery path
132
+ - `task_list` may return `TASK_LIST_QUERY_FALLBACK_APPLIED`; this means backend search missed the query and MCP recovered the result through local exact-field fallback
113
133
  - `task_get` returns node context summary, not full historical report data
114
134
  - `task_associated_report_detail_get` may return either:
115
135
  - `result_type=view_list`
116
136
  - `result_type=chart_data`
117
137
  - `task_workflow_log_get` returns workflow log detail only when the node grants log visibility
138
+ - A successful approve/reject/rollback/transfer may still lose the current-node runtime immediately; treat `record_state_readable=false + backend 46001` as a post-action runtime loss unless continuation verification says otherwise
118
139
  - Treat `request_route` as the source of truth for live route debugging
119
140
  - If only part of the requested work is completed, explicitly disclose which parts are done and which are not
120
141
 
@@ -5,7 +5,7 @@ from pathlib import Path
5
5
 
6
6
  __all__ = ["__version__"]
7
7
 
8
- _FALLBACK_VERSION = "0.2.0b985"
8
+ _FALLBACK_VERSION = "0.2.0b987"
9
9
 
10
10
 
11
11
  def _resolve_local_pyproject_version() -> str | None: