doa-harness — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited doa-harness (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Copilot 的上限不取决于提示词,而取决于它运行在怎样的工程轨道上。 三层公式:Context(给什么)→ Constraints(守什么)→ GC(清什么)。
| 模式 | 触发方式 | 行为 |
|---|---|---|
| 初始化 | 首次运行(默认) | 完整探测 → 交互确认 → 生成全部 5 类文件 |
| 增量更新 | 参数含 --update | 扫描已有文件 → 仅 patch 新增部分(如新模块),保留用户自定义内容 |
| 预览模式 | 参数含 --dry-run | 执行探测和模板渲染,输出预览但不写入文件 |
调用 skill
→ Step 0: 判断运行模式(初始化 / 增量更新 / 预览)
→ Step 1: 深度探测项目结构与技术栈
→ Step 2: 交互确认关键信息
→ Step 3: 生成 / 更新 5 类配置文件
→ Step 4: 注入 GC 指令
→ Step 5: 验证完整性 & 一致性
→ Step 6: 输出 Day-1 验证指令--update 或 --dry-run.github/copilot-instructions.md 是否已存在--update:提示用户 "Harness 已初始化,是否切换到增量更新模式?"不再只看根目录。用 list_dir 递归扫描根目录及一级子目录,收集所有包含信号文件的子项目:
扫描策略:
1. list_dir 根目录 → 识别子目录
2. 对每个子目录 list_dir → 查找信号文件
3. 构建子项目列表: [{name, path, stack, signals}]| 信号文件 | 技术栈大类 | 需要进一步读取 |
|---|---|---|
package.json + tsconfig.json | Node/TypeScript | 读 package.json → 判断具体框架 |
*.csproj / *.sln | .NET | 读 .csproj → 判断 SDK 版本和项目类型 |
pyproject.toml / requirements.txt | Python | 读依赖列表 → 判断框架 |
go.mod | Go | 读 go.mod → 判断主要依赖 |
Cargo.toml | Rust | 读 Cargo.toml |
pom.xml / build.gradle | Java/Kotlin | 读构建文件 |
当检测到 package.json 时,必须读取其 dependencies / devDependencies 来判断:
| 依赖关键字 | 识别为 | 典型配套 |
|---|---|---|
umi / @umijs/* | UmiJS | Ant Design Pro · dva · umi-request |
next | Next.js | App Router / Pages Router |
nuxt | Nuxt | Vue 3 |
vue (无 nuxt) | Vue SPA | Vue Router · Pinia · Axios |
react (无 umi/next) | React SPA | React Router · 状态管理待探测 |
@angular/core | Angular | RxJS · NgRx |
svelte / @sveltejs/kit | Svelte/SvelteKit | — |
同时检测:
yarn.lock → Yarn | pnpm-lock.yaml → pnpm | package-lock.json → npmtailwind.config.* → Tailwind | .less 文件 → Less | *.module.css → CSS Moduleszustand / dva / redux / pinia / vuex / ahooksaxios / umi-request / @tanstack/react-query / swrvitest / jest / @testing-library/* / cypresseslint / prettier / biome.NET 项目(检测到 .csproj / .sln):
.csproj 的 <TargetFramework> → 判断 .NET 版本<Sdk> 属性 → Microsoft.NET.Sdk.Web 为 Web 项目,Microsoft.NET.Sdk.Worker 为后台服务Program.cs / Startup.cs → 判断 Minimal API / MVC / 传统分层Python 项目:
pyproject.toml 或 requirements.txt → FastAPI / Django / Flask扫描以下文件以识别 CI 平台:
| 信号文件 | CI 平台 |
|---|---|
.github/workflows/*.yml | GitHub Actions |
azure-pipelines.yml | Azure DevOps |
.gitlab-ci.yml | GitLab CI |
Jenkinsfile | Jenkins |
.circleci/config.yml | CircleCI |
通过 .git/config 或目录特征推断:
| 信号 | 平台 |
|---|---|
存在 .github/ 目录 | GitHub |
存在 .gitlab/ 目录 | GitLab |
remote URL 含 dev.azure.com | Azure DevOps |
| 无法确定 | 在 Step 2 交互中询问 |
将所有探测结果汇总为结构化数据,供后续步骤使用:
project:
name: "{项目名}"
type: "monorepo" | "single"
hosting: "github" | "gitlab" | "azure-devops"
ci: "github-actions" | "azure-pipelines" | "gitlab-ci"
subprojects:
- name: "{子项目名}"
path: "{相对路径}"
stack: "react-ts" | "vue-ts" | "dotnet" | "python" | ...
framework: "{具体框架}"
package_manager: "yarn" | "pnpm" | "npm" | null
css: "less" | "tailwind" | "css-modules" | null
state: "dva" | "zustand" | "pinia" | null
request: "umi-request" | "axios" | "react-query" | null
test: "vitest" | "jest" | "xunit" | "pytest" | null
lint: "eslint" | "prettier" | "biome" | "dotnet-format" | null
entry: "{入口文件路径}"
verify_chain: ["{cmd1}", "{cmd2}", "{cmd3}"]使用 vscode_askQuestions 向用户确认以下关键信息(一次性收集):
@user1 @user2,默认 @todo-fill-team增量更新模式下:跳过已确认的信息,仅询问新增部分(如新发现的子项目)
按以下顺序依次生成 5 类文件。
初始化模式:生成前检查是否已存在,已存在则跳过并提示。 增量更新模式:读取已有文件,仅 patch 新增内容(如新模块加入模块地图),不覆盖用户自定义段落。 预览模式:渲染模板内容输出到聊天窗口,不写入文件。
每个生成的文件头部加注版本标记:
# Generated by doa-harness v2.0 on {YYYY-MM-DD}路径:.github/copilot-instructions.md
读取 templates/copilot-instructions.md 获取骨架模板。
模板采用骨架 + 占位符模式,不硬编码任何特定框架:
段落结构(固定):
1. 项目概述 — {project.name} + 各子项目入口
2. 技术栈 — 按子项目分段,每段由探测结果填充
3. 安全边界 — 按子项目分段
4. 前后端联动(仅 monorepo)
5. 验证命令 — 从 verify_chain 生成
6. 代码约定 — 按语言生成
7. 操作安全 — 合并 CI 平台 + 核心目录
8. 垃圾回收(固定段落)占位符清单:
{project_description} — 用户输入的项目描述{sub.name} / {sub.entry} — 子项目名和入口{sub.framework} — 具体框架(UmiJS / Next.js / ASP.NET Core...){sub.state} — 状态管理方案{sub.css} — CSS 方案{sub.request} — 请求层方案{sub.package_manager} — 包管理器{ci_platform} — CI 平台名及配置文件路径{hosting_platform} — 代码托管平台路径:.github/AGENTS.md
读取 templates/agents-md.md 获取骨架模板。
生成规则:
docs/、README.md、CHANGELOG.md 等是否存在并列出rules/ 目录列出权限标注规则(按目录名模式匹配):
| 目录名模式 | 标注 | 含义 |
|---|---|---|
core kernel foundation framework Framework | 🔒 需审批 | 核心 / 底层框架 |
auth security identity Authorization License | 🔒 需审批 | 认证 / 安全 |
infra infrastructure deploy ActionFilter | 🔒 需审批 | 基础设施 |
migrations database SQL_Script | 🔒 需审批 | 数据库变更 |
app layouts (前端配置目录) | 🔒 需审批 | 前端核心配置 |
Program.cs Startup.cs (入口文件) | 🔒 需审批 | 启动入口 |
shared common lib tools components | ⚠️ 注意复用 | 共享模块 |
api contracts interfaces Controllers ExternalApi ExternalService | ⚠️ 有契约约束 | 接口层 |
config settings appsettings ScheduleJobs | ⚠️ 需确认 | 配置 / 定时任务 |
features modules pages Service | ✅ 可自由修改 | 业务功能 |
components (非共享) views Dto Model | ✅ 可自由修改 | UI / 数据模型 |
tests __tests__ spec | ✅ 可自由修改 | 测试文件 |
assets public static locales | ✅ 可自由修改 | 静态资源 |
生成后通过交互让用户确认或修正权限标注,避免误判。 总行数控制在 200 行以内。
路径:.vscode/tasks.json
读取 templates/tasks-json.md 获取骨架模板。
支持 N 个子项目,生成逻辑:
对每个子项目 sub:
1. 根据 sub.verify_chain 生成对应 task 列表
2. 每个 task 的 label 格式: "{sub.name}:{step}"
3. 每个 task 添加 options.cwd = "${workspaceFolder}/{sub.path}"
4. 生成子验证任务: "verify:{sub.name}" dependsOn 该子项目所有 step
最后生成总验证任务:
"verify" dependsOn 所有 "verify:{sub.name}"包管理器感知:
yarn.lock → 命令用 yarnpnpm-lock.yaml → 命令用 pnpmnpm runproblemMatcher 映射:
["$tsc"]["$eslint-stylish"]["$msCompile"][]路径:根据代码托管平台决定
| 平台 | 默认路径 | 说明 |
|---|---|---|
| GitHub | CODEOWNERS(项目根目录) | 也支持 .github/CODEOWNERS 和 docs/CODEOWNERS |
| GitLab | CODEOWNERS(项目根目录) | 支持 [Section] 分组语法 |
| Azure DevOps | 不生成 | 提示用户通过分支策略配置审阅者规则 |
读取 templates/codeowners.md 获取骨架模板。
生成规则:
@todo-fill-team)copilot-instructions.md、AGENTS.md)纳入 CODEOWNERS[Section] 分组语法增强可读性路径:rules/ 目录
读取 templates/rules.md 获取各技术栈的规则模板。
每条规则文件包含:
根据技术栈生成核心规则 + 通用规则:
按技术栈生成:
| 技术栈 | 规则文件 |
|---|---|
| React/TS | react-patterns.md、no-direct-fetch.md |
| Vue/TS | vue-patterns.md、no-direct-fetch.md |
| .NET | dotnet-data-access.md、no-lazy-load.md |
| Python | python-imports.md、no-raw-sql.md |
| Go | go-error-handling.md |
通用规则(所有项目都生成):
| 规则文件 | 内容 |
|---|---|
no-secrets-in-code.md | 禁止硬编码密钥、token、连接字符串 |
用户自定义规则: 如果用户在 Step 2 提供了额外规约,为每条生成一个独立 rules/{name}.md 文件。
在 copilot-instructions.md 的末尾追加 GC 段落:
# 垃圾回收
每次完成任务后,检查是否有:
- 临时文件、未使用的 import / using
- 重复代码或重复函数
- 过期的 TODO / FIXME 注释
如有,顺手清理。生成完成后执行以下检查:
确认 5 类文件全部存在(Azure DevOps 项目跳过 CODEOWNERS)。
| 校验项 | 检查逻辑 |
|---|---|
| 验证链一致 | tasks.json 的 verify 链 ↔ copilot-instructions.md 的验证命令段落,两者引用的命令必须匹配 |
| 模块地图覆盖 | AGENTS.md 模块地图 ↔ 实际目录结构,不遗漏核心目录 |
| CODEOWNERS 语法 | 根据平台校验语法格式(GitHub: path @owner,GitLab: [Section] + path @owner) |
| rules 引用 | AGENTS.md 关键约束段落引用的 rules/ 文件 ↔ 实际生成的 rules/*.md 文件 |
在 tasks.json 中追加一个 verify:harness 任务,检查 5 类文件的存在性:
{
"label": "verify:harness",
"type": "shell",
"command": "echo Checking harness files... && test -f .github/copilot-instructions.md && test -f .github/AGENTS.md && test -f .vscode/tasks.json && test -f CODEOWNERS && test -d rules/ && echo 'All harness files OK' || echo 'MISSING harness files!'",
"problemMatcher": []
}输出生成文件清单,并给出 Day-1 验证指令:
打开 Copilot Agent 模式,输入:
"读一下项目指令,然后告诉我:
1. 哪些目录不能修改?
2. 验证命令是什么?
3. 哪些操作需要先确认?"如果 Copilot 能准确回答这 3 个问题,说明 Harness 已生效。
当以 --update 模式运行时:
| 文件 | 用途 | 核心内容 |
|---|---|---|
copilot-instructions.md | Agent 指令 | 技术栈 + 安全边界 + 验证命令 |
AGENTS.md | 知识索引 | 快速入口 + 模块地图 + 约束清单 |
tasks.json | 验证链 | 每子项目独立链 → verify 总汇 |
CODEOWNERS | 审批钩子 | 核心目录 → 团队 owner(多平台适配) |
rules/*.md | 编码规则 | 正例 + 反例 + 检测方式 |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.