[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69BFAS2GHW4CCQJR1PAXZPD":3,"skill-same:01M69BFAS2GHW4CCQJR1PAXZPD":91},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":20,"linkOnly":21,"markdownContent":22,"markdownBody":23,"frontMatter":24,"refName":25,"commitSha":26,"skillDirectory":27,"forksCount":28,"repositoryHtmlUrl":29,"repositoryHomepageUrl":30,"ownerHtmlUrl":31,"ownerBlogUrl":32,"ownerDescription":33,"updatedAt":34,"install":35,"resources":48},"01M69BFAS2GHW4CCQJR1PAXZPD","path-safety",null,"服务端路径安全与文件访问编码规范。在编写文件下载路由、Agent 工具（文件读取\u002F目录列出）、数据连接器\u002FLoader、Workspace 路径操作、沙箱配置时使用。","microsoft\u002Fdata-formulator","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M69BF44TK0TP41QE6EZXBGRY",17677,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator\u002Fblob\u002Fmain\u002F.cursor\u002Fskills\u002Fpath-safety\u002FSKILL.md",[],[19],"path safety","2026-11-10 10:12:30",false,"---\r\nname: path-safety\r\ndescription: 服务端路径安全与文件访问编码规范。在编写文件下载路由、Agent 工具（文件读取\u002F目录列出）、数据连接器\u002FLoader、Workspace 路径操作、沙箱配置时使用。\r\n---\r\n\r\n# Path Safety — 服务端安全编码规范\r\n\r\n> **来源**：`docs\u002Fdev-guides\u002F8-path-safety.md`（正式开发规范）+ `design-docs\u002Fissues\u002F002-arbitrary-file-read-audit.md`（安全审计复核）。\r\n> 本文档提炼了 6 条必须遵守的编码规范。违反任一条即可能引入路径穿越（LFI）漏洞。\r\n\r\n---\r\n\r\n## R1. 文件下载：用 `ConfinedDir.resolve()` + `send_file`，禁用 `send_from_directory`\r\n\r\n**原因**：`send_from_directory(dir, user_input)` 内部会对 `user_input` 二次解析路径，与前置安全检查形成 TOCTOU 不一致。\r\n\r\n```python\r\n# ❌ BAD — 安全检查用 resolved target，发送用原始 filename，两次解析不一致\r\ntarget = (scratch_dir \u002F filename).resolve()\r\ntarget.relative_to(scratch_dir.resolve())  # 检查通过\r\nreturn send_from_directory(str(scratch_dir), filename)  # 再次解析\r\n\r\n# ✅ GOOD — 检查和发送用同一个 resolved path\r\nscratch_jail = workspace.confined_scratch\r\ntarget = scratch_jail.resolve(filename)\r\nreturn send_file(target)  # 直接用已验证的路径\r\n```\r\n\r\n`send_file(Path)` 会根据扩展名自动推断 MIME type，无需额外处理。\r\n\r\n---\r\n\r\n## R2. 路径安全检查：用 `ConfinedDir`，禁止 `str.startswith`\r\n\r\n**原因**：`str(path).startswith(str(root))` 存在前缀碰撞缺陷（如 `\u002Fworkspace` vs `\u002Fworkspace_evil`）。\r\n\r\n```python\r\n# ❌ BAD\r\nif not str(resolved).startswith(str(root_resolved) + os.sep):\r\n    raise ValueError(\"escape\")\r\n\r\n# ✅ GOOD — 统一走 ConfinedDir，内部使用 Path.is_relative_to()\r\njail = ConfinedDir(root_resolved, mkdir=False)\r\ntarget = jail.resolve(user_input)\r\n```\r\n\r\n---\r\n\r\n## R3. Agent 工具复用 `Workspace.confined_*`\r\n\r\n**原因**：Agent 工具参数由 LLM 生成，必须视为间接用户输入。不要在工具内手写 `Path(root) \u002F rel_path` 或 `resolve() + relative_to()`；入口处复用 Workspace 暴露的 `ConfinedDir`。\r\n\r\n```python\r\n# ❌ BAD — 手写路径拼接和校验\r\ndef _tool_read_file(self, args, workspace_path):\r\n    target = (workspace_path \u002F rel_path).resolve()\r\n    target.relative_to(workspace_path)\r\n\r\n# ✅ GOOD — 入口拿到 ConfinedDir，工具只调用 jail.resolve()\r\ndef _execute_tool(self, name, args):\r\n    workspace_jail = self.workspace.confined_root\r\n    scratch_jail = self.workspace.confined_scratch\r\n    return self._tool_read_file(args, workspace_jail)\r\n\r\ndef _tool_read_file(self, args, workspace_jail):\r\n    target = workspace_jail.resolve(args.get(\"path\", \"\"))\r\n```\r\n\r\n---\r\n\r\n## R4. 优先使用 `ConfinedDir`，禁止裸路径拼接\r\n\r\n**原因**：`Path(root) \u002F user_input` 是路径穿越的高频入口。`ConfinedDir` 封装了三层防御（拒绝绝对路径 → 拒绝 `..` 段 → `resolve` + `is_relative_to`）。\r\n\r\n```python\r\nfrom data_formulator.security.path_safety import ConfinedDir\r\n\r\n# ❌ BAD — 手动拼接 + 手动校验，容易遗漏\r\nlocal_file = tmp_path \u002F blob_relative_name\r\nlocal_file.parent.mkdir(parents=True, exist_ok=True)\r\nlocal_file.write_bytes(data)\r\n\r\n# ✅ GOOD — ConfinedDir 自动校验 + 创建父目录\r\njail = ConfinedDir(tmp_path, mkdir=False)\r\njail.write(blob_relative_name, data)  # 自动校验 + 写入\r\n```\r\n\r\n### 已有安全 API 的层次关系\r\n\r\n```\r\n用户输入（filename \u002F relative_path \u002F blob key）\r\n    │\r\n    ▼\r\nsafe_data_filename() \u002F secure_filename()     ← 第一层：输入清洗\r\n    │\r\n    ▼\r\nConfinedDir.resolve()                        ← 第二层：路径约束\r\n    │\r\n    ▼\r\n安全的 Path 对象\r\n```\r\n\r\n使用 `Workspace.get_file_path()` 的场景不需要手动调用 `ConfinedDir`，因为它内部已包含等价的校验。\r\n\r\n---\r\n\r\n## R5. 宿主文件系统访问必须设部署模式守卫\r\n\r\n**原因**：桌面单用户模式允许访问本机文件系统（预期行为），但多用户\u002F云部署下等于开放服务器读权限。\r\n\r\n**规范**：任何新的 Loader \u002F Connector 如果涉及直接读取宿主文件系统（不通过 Workspace API），必须：\r\n\r\n1. 在 `data_loader\u002F__init__.py` 的 `_enforce_deployment_restrictions()` 中注册禁用规则\r\n2. 确保 `create_connector()` 会拒绝已禁用的类型\r\n\r\n```python\r\n# data_loader\u002F__init__.py — 参考 local_folder 的处理方式\r\ndef _enforce_deployment_restrictions():\r\n    backend = os.environ.get(\"WORKSPACE_BACKEND\", \"local\")\r\n    if backend != \"local\":\r\n        for key in (\"local_folder\", \"your_new_local_loader\"):\r\n            if key in DATA_LOADERS:\r\n                del DATA_LOADERS[key]\r\n                DISABLED_LOADERS[key] = f\"{key} disabled in multi-user mode\"\r\n```\r\n\r\n**判断标准**：如果 Loader 的构造函数接受一个用户可控的本机路径（如 `root_dir`），它就需要部署守卫。\r\n\r\n---\r\n\r\n## R6. 多用户部署必须启用沙箱\r\n\r\n**原因**：`not_a_sandbox` 模式下 LLM 生成的代码在宿主进程直接执行，可绕过所有路径检查。\r\n\r\n`app.py` 已在启动时检测此配置并输出 `logger.critical` 警告。新增的沙箱模式或部署脚本应确保：\r\n\r\n- `WORKSPACE_BACKEND != \"local\"` 时，`SANDBOX` 必须为 `docker` 或 `local`\r\n- CI\u002FCD 部署模板中默认设置 `SANDBOX=docker`\r\n\r\n---\r\n\r\n## 速查：新增代码时的安全检查清单\r\n\r\n| 场景 | 必须做的事 |\r\n|------|-----------|\r\n| 新增文件下载路由 | 用 `ConfinedDir.resolve()` 得到路径，再 `send_file(resolved_path)`；不用 `send_from_directory` |\r\n| 新增 Agent 工具（读文件\u002F列目录） | 入口复用 `workspace.confined_root` \u002F `workspace.confined_scratch`，工具内只调用 `jail.resolve()` |\r\n| 路径包含判断 | 用 `ConfinedDir.resolve()`，不要手写 `Path.is_relative_to()` 或 `str.startswith()` |\r\n| `Path(root) \u002F variable` 模式 | 改用 `ConfinedDir` 或 `Workspace.get_file_path()` |\r\n| 新增本机文件系统 Loader | 在 `_enforce_deployment_restrictions()` 中注册多用户禁用 |\r\n| 部署配置 | 多用户模式必须 `SANDBOX=docker` 或 `SANDBOX=local` |\r\n\r\n---\r\n\r\n## 参考文档\r\n\r\n- `docs\u002Fdev-guides\u002F8-path-safety.md` — 服务端路径安全开发规范\r\n- `design-docs\u002F6-path-safety-confined-dir.md` — 剩余未完成实现项状态页\r\n- `design-docs\u002Fissues\u002F002-arbitrary-file-read-audit.md` — 安全审计复核报告\r\n- `py-src\u002Fdata_formulator\u002Fsecurity\u002Fpath_safety.py` — ConfinedDir 源码\r\n","# Path Safety — 服务端安全编码规范\r\n\r\n> **来源**：`docs\u002Fdev-guides\u002F8-path-safety.md`（正式开发规范）+ `design-docs\u002Fissues\u002F002-arbitrary-file-read-audit.md`（安全审计复核）。\r\n> 本文档提炼了 6 条必须遵守的编码规范。违反任一条即可能引入路径穿越（LFI）漏洞。\r\n\r\n---\r\n\r\n## R1. 文件下载：用 `ConfinedDir.resolve()` + `send_file`，禁用 `send_from_directory`\r\n\r\n**原因**：`send_from_directory(dir, user_input)` 内部会对 `user_input` 二次解析路径，与前置安全检查形成 TOCTOU 不一致。\r\n\r\n```python\r\n# ❌ BAD — 安全检查用 resolved target，发送用原始 filename，两次解析不一致\r\ntarget = (scratch_dir \u002F filename).resolve()\r\ntarget.relative_to(scratch_dir.resolve())  # 检查通过\r\nreturn send_from_directory(str(scratch_dir), filename)  # 再次解析\r\n\r\n# ✅ GOOD — 检查和发送用同一个 resolved path\r\nscratch_jail = workspace.confined_scratch\r\ntarget = scratch_jail.resolve(filename)\r\nreturn send_file(target)  # 直接用已验证的路径\r\n```\r\n\r\n`send_file(Path)` 会根据扩展名自动推断 MIME type，无需额外处理。\r\n\r\n---\r\n\r\n## R2. 路径安全检查：用 `ConfinedDir`，禁止 `str.startswith`\r\n\r\n**原因**：`str(path).startswith(str(root))` 存在前缀碰撞缺陷（如 `\u002Fworkspace` vs `\u002Fworkspace_evil`）。\r\n\r\n```python\r\n# ❌ BAD\r\nif not str(resolved).startswith(str(root_resolved) + os.sep):\r\n    raise ValueError(\"escape\")\r\n\r\n# ✅ GOOD — 统一走 ConfinedDir，内部使用 Path.is_relative_to()\r\njail = ConfinedDir(root_resolved, mkdir=False)\r\ntarget = jail.resolve(user_input)\r\n```\r\n\r\n---\r\n\r\n## R3. Agent 工具复用 `Workspace.confined_*`\r\n\r\n**原因**：Agent 工具参数由 LLM 生成，必须视为间接用户输入。不要在工具内手写 `Path(root) \u002F rel_path` 或 `resolve() + relative_to()`；入口处复用 Workspace 暴露的 `ConfinedDir`。\r\n\r\n```python\r\n# ❌ BAD — 手写路径拼接和校验\r\ndef _tool_read_file(self, args, workspace_path):\r\n    target = (workspace_path \u002F rel_path).resolve()\r\n    target.relative_to(workspace_path)\r\n\r\n# ✅ GOOD — 入口拿到 ConfinedDir，工具只调用 jail.resolve()\r\ndef _execute_tool(self, name, args):\r\n    workspace_jail = self.workspace.confined_root\r\n    scratch_jail = self.workspace.confined_scratch\r\n    return self._tool_read_file(args, workspace_jail)\r\n\r\ndef _tool_read_file(self, args, workspace_jail):\r\n    target = workspace_jail.resolve(args.get(\"path\", \"\"))\r\n```\r\n\r\n---\r\n\r\n## R4. 优先使用 `ConfinedDir`，禁止裸路径拼接\r\n\r\n**原因**：`Path(root) \u002F user_input` 是路径穿越的高频入口。`ConfinedDir` 封装了三层防御（拒绝绝对路径 → 拒绝 `..` 段 → `resolve` + `is_relative_to`）。\r\n\r\n```python\r\nfrom data_formulator.security.path_safety import ConfinedDir\r\n\r\n# ❌ BAD — 手动拼接 + 手动校验，容易遗漏\r\nlocal_file = tmp_path \u002F blob_relative_name\r\nlocal_file.parent.mkdir(parents=True, exist_ok=True)\r\nlocal_file.write_bytes(data)\r\n\r\n# ✅ GOOD — ConfinedDir 自动校验 + 创建父目录\r\njail = ConfinedDir(tmp_path, mkdir=False)\r\njail.write(blob_relative_name, data)  # 自动校验 + 写入\r\n```\r\n\r\n### 已有安全 API 的层次关系\r\n\r\n```\r\n用户输入（filename \u002F relative_path \u002F blob key）\r\n    │\r\n    ▼\r\nsafe_data_filename() \u002F secure_filename()     ← 第一层：输入清洗\r\n    │\r\n    ▼\r\nConfinedDir.resolve()                        ← 第二层：路径约束\r\n    │\r\n    ▼\r\n安全的 Path 对象\r\n```\r\n\r\n使用 `Workspace.get_file_path()` 的场景不需要手动调用 `ConfinedDir`，因为它内部已包含等价的校验。\r\n\r\n---\r\n\r\n## R5. 宿主文件系统访问必须设部署模式守卫\r\n\r\n**原因**：桌面单用户模式允许访问本机文件系统（预期行为），但多用户\u002F云部署下等于开放服务器读权限。\r\n\r\n**规范**：任何新的 Loader \u002F Connector 如果涉及直接读取宿主文件系统（不通过 Workspace API），必须：\r\n\r\n1. 在 `data_loader\u002F__init__.py` 的 `_enforce_deployment_restrictions()` 中注册禁用规则\r\n2. 确保 `create_connector()` 会拒绝已禁用的类型\r\n\r\n```python\r\n# data_loader\u002F__init__.py — 参考 local_folder 的处理方式\r\ndef _enforce_deployment_restrictions():\r\n    backend = os.environ.get(\"WORKSPACE_BACKEND\", \"local\")\r\n    if backend != \"local\":\r\n        for key in (\"local_folder\", \"your_new_local_loader\"):\r\n            if key in DATA_LOADERS:\r\n                del DATA_LOADERS[key]\r\n                DISABLED_LOADERS[key] = f\"{key} disabled in multi-user mode\"\r\n```\r\n\r\n**判断标准**：如果 Loader 的构造函数接受一个用户可控的本机路径（如 `root_dir`），它就需要部署守卫。\r\n\r\n---\r\n\r\n## R6. 多用户部署必须启用沙箱\r\n\r\n**原因**：`not_a_sandbox` 模式下 LLM 生成的代码在宿主进程直接执行，可绕过所有路径检查。\r\n\r\n`app.py` 已在启动时检测此配置并输出 `logger.critical` 警告。新增的沙箱模式或部署脚本应确保：\r\n\r\n- `WORKSPACE_BACKEND != \"local\"` 时，`SANDBOX` 必须为 `docker` 或 `local`\r\n- CI\u002FCD 部署模板中默认设置 `SANDBOX=docker`\r\n\r\n---\r\n\r\n## 速查：新增代码时的安全检查清单\r\n\r\n| 场景 | 必须做的事 |\r\n|------|-----------|\r\n| 新增文件下载路由 | 用 `ConfinedDir.resolve()` 得到路径，再 `send_file(resolved_path)`；不用 `send_from_directory` |\r\n| 新增 Agent 工具（读文件\u002F列目录） | 入口复用 `workspace.confined_root` \u002F `workspace.confined_scratch`，工具内只调用 `jail.resolve()` |\r\n| 路径包含判断 | 用 `ConfinedDir.resolve()`，不要手写 `Path.is_relative_to()` 或 `str.startswith()` |\r\n| `Path(root) \u002F variable` 模式 | 改用 `ConfinedDir` 或 `Workspace.get_file_path()` |\r\n| 新增本机文件系统 Loader | 在 `_enforce_deployment_restrictions()` 中注册多用户禁用 |\r\n| 部署配置 | 多用户模式必须 `SANDBOX=docker` 或 `SANDBOX=local` |\r\n\r\n---\r\n\r\n## 参考文档\r\n\r\n- `docs\u002Fdev-guides\u002F8-path-safety.md` — 服务端路径安全开发规范\r\n- `design-docs\u002F6-path-safety-confined-dir.md` — 剩余未完成实现项状态页\r\n- `design-docs\u002Fissues\u002F002-arbitrary-file-read-audit.md` — 安全审计复核报告\r\n- `py-src\u002Fdata_formulator\u002Fsecurity\u002Fpath_safety.py` — ConfinedDir 源码\r\n",{"name":5,"description":7},"main","5477f0e236426dc8f74a498ec400414fba7fbc0f",".cursor\u002Fskills\u002Fpath-safety",1739,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator","https:\u002F\u002Fdata-formulator.ai\u002F","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-09 22:13:49",{"source":8,"skillName":5,"commands":36,"prompt":46,"zipAvailable":47},[37,40,43],{"tool":38,"command":39},"npx","npx skills add microsoft\u002Fdata-formulator --skill path-safety",{"tool":41,"command":42},"bunx","bunx skills add microsoft\u002Fdata-formulator --skill path-safety",{"tool":44,"command":45},"pnpm","pnpm dlx skills add microsoft\u002Fdata-formulator --skill path-safety","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator\u002Fblob\u002Fmain\u002F.cursor\u002Fskills\u002Fpath-safety\u002FSKILL.md",true,[49,55,59,63,67,71,75,79,83,87],{"path":50,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":53,"sourceHtmlUrl":54},"backends\u002Fproject-board.md","REFERENCE","参考文档",1249,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Fbackends\u002Fproject-board.md",{"path":56,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":57,"sourceHtmlUrl":58},"backends\u002Fvetted-ops.md",717,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Fbackends\u002Fvetted-ops.md",{"path":60,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":61,"sourceHtmlUrl":62},"examples.md",1885,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Fexamples.md",{"path":64,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":65,"sourceHtmlUrl":66},"outcomes\u002Fbody-fields.md",2681,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Foutcomes\u002Fbody-fields.md",{"path":68,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":69,"sourceHtmlUrl":70},"outcomes\u002Fmixed-scope.md",2315,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Foutcomes\u002Fmixed-scope.md",{"path":72,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":73,"sourceHtmlUrl":74},"outcomes\u002Fsibling.md",828,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Foutcomes\u002Fsibling.md",{"path":76,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":77,"sourceHtmlUrl":78},"pre-pr-adversarial-review.md",5058,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Fpre-pr-adversarial-review.md",{"path":80,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":81,"sourceHtmlUrl":82},"reference.md",2927,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Freference.md",{"path":84,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":85,"sourceHtmlUrl":86},"tracker-backend.md",2778,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Ftracker-backend.md",{"path":88,"resourceType":51,"resourceTypeDesc":52,"sizeBytes":89,"sourceHtmlUrl":90},"tracker-body-template.md",963,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Fblob\u002Fmain\u002Fplugins\u002Fmagpie-security\u002Fskills\u002Fissue-import-from-pr\u002Ftracker-body-template.md",[92,122,134,140,149,158],{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":117,"publishedAt":20},"01M69BFJ823DGYDZQMYBFSPJAW","report","Turn an exploration (threads, findings, charts) into a single Markdown report — note, blog post, executive summary, KPI dashboard, slide brief, or multi-section analytical report, with embedded charts.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator\u002Fblob\u002Fmain\u002Fpy-src\u002Fdata_formulator\u002Fanalyst\u002Fskills\u002Freport\u002FSKILL.md",[98,103,106,111,114],{"categoryNo":99,"categoryName":100,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000013","分析与可视化","SCENARIO","使用场景",{"categoryNo":104,"categoryName":105,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":107,"categoryName":108,"taxonomyType":109,"taxonomyTypeDesc":110},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",{"categoryNo":112,"categoryName":113,"taxonomyType":109,"taxonomyTypeDesc":110},"01JBSEEDCAT000000000000034","行政与办公人员",{"categoryNo":115,"categoryName":116,"taxonomyType":109,"taxonomyTypeDesc":110},"01JBSEEDCAT000000000000036","内容创作者",[94,118,119,120,121],"executive summary","dashboard","visualize","summarize",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":129,"publishedAt":20},"01M69BFGGPGA5AK2V3N6PM2EXY","data-loading","Discover connected data sources, add new data connectors through a user-confirmed form, inspect table metadata, and run bounded read-only probes when the current workspace data is insufficient.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator\u002Fblob\u002Fmain\u002Fpy-src\u002Fdata_formulator\u002Fanalyst\u002Fskills\u002Fdata_loading\u002FSKILL.md",[128],{"categoryNo":107,"categoryName":108,"taxonomyType":109,"taxonomyTypeDesc":110},[130,131,132,133],"data loading","run","connect","connectors",{"skillNo":135,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":139,"publishedAt":20},"01M69BFEDNAV78CW1QBH8AFEVT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator\u002Fblob\u002Fmain\u002Fpy-src\u002Fdata_formulator\u002Fanalyst\u002Fskills\u002Fdata-loading\u002FSKILL.md",[138],{"categoryNo":107,"categoryName":108,"taxonomyType":109,"taxonomyTypeDesc":110},[130,131,132,133],{"skillNo":141,"name":142,"nameZh":6,"description":143,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":144,"categories":145,"keywords":147,"publishedAt":20},"01M69BFCDH9Z63K4ND9MXB07H5","core","The analyst's built-in capabilities: data-inspection tools and the always-available actions (visualize and ask_user).","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator\u002Fblob\u002Fmain\u002Fpy-src\u002Fdata_formulator\u002Fanalyst\u002Fskills\u002Fcore\u002FSKILL.md",[146],{"categoryNo":107,"categoryName":108,"taxonomyType":109,"taxonomyTypeDesc":110},[142,120,148],"python",{"skillNo":150,"name":151,"nameZh":6,"description":152,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":153,"categories":154,"keywords":155,"publishedAt":20},"01M69BF8TAXKYRA9J8HY978H0H","language-injection","LLM Agent 多语言注入规范。在修改 Agent 提示词、添加新的 Agent 端点、处理用户可见的后端消息（message_code）时使用。","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator\u002Fblob\u002Fmain\u002F.cursor\u002Fskills\u002Flanguage-injection\u002FSKILL.md",[],[156,157],"language injection","code",{"skillNo":159,"name":160,"nameZh":6,"description":161,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":162,"categories":163,"keywords":173,"publishedAt":20},"01M69BF6N55FCZ9Y10Q9BJE5VN","error-handling","统一错误处理系统。在添加 API 端点、修改错误处理、添加前端 API 调用、编写错误相关测试时使用。","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fdata-formulator\u002Fblob\u002Fmain\u002F.cursor\u002Fskills\u002Ferror-handling\u002FSKILL.md",[164,167,170],{"categoryNo":165,"categoryName":166,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":168,"categoryName":169,"taxonomyType":101,"taxonomyTypeDesc":102},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":171,"categoryName":172,"taxonomyType":109,"taxonomyTypeDesc":110},"01JBSEEDCAT000000000000030","开发工程师",[174,175,176],"error handling","testing","frontend"]