332 lines
14 KiB
HTML
332 lines
14 KiB
HTML
<!DOCTYPE html>
|
||||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="utf-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|||
|
|
<title>仓库导览 · harness_coding_docs</title>
|
|||
|
|
<script type="module">
|
|||
|
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
|||
|
|
const dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|||
|
|
mermaid.initialize({ startOnLoad: true, theme: dark ? 'dark' : 'neutral' });
|
|||
|
|
</script>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<style>
|
|||
|
|
:root {
|
|||
|
|
--paper: #f6f7f4;
|
|||
|
|
--card: #ffffff;
|
|||
|
|
--ink: #1e2733;
|
|||
|
|
--ink-soft: #4c5a66;
|
|||
|
|
--line: #dde3dc;
|
|||
|
|
--accent: #0f7b5f;
|
|||
|
|
--accent-soft: #e3f0ea;
|
|||
|
|
--warn: #b7791f;
|
|||
|
|
--warn-soft: #f7edda;
|
|||
|
|
--mono-bg: #eef1ec;
|
|||
|
|
}
|
|||
|
|
@media (prefers-color-scheme: dark) {
|
|||
|
|
:root {
|
|||
|
|
--paper: #141a18;
|
|||
|
|
--card: #1c2422;
|
|||
|
|
--ink: #e8ece9;
|
|||
|
|
--ink-soft: #a3b0aa;
|
|||
|
|
--line: #2e3a35;
|
|||
|
|
--accent: #3fb08c;
|
|||
|
|
--accent-soft: #1e332c;
|
|||
|
|
--warn: #d9a04a;
|
|||
|
|
--warn-soft: #33290f;
|
|||
|
|
--mono-bg: #232d29;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
:root[data-theme="dark"] {
|
|||
|
|
--paper: #141a18;
|
|||
|
|
--card: #1c2422;
|
|||
|
|
--ink: #e8ece9;
|
|||
|
|
--ink-soft: #a3b0aa;
|
|||
|
|
--line: #2e3a35;
|
|||
|
|
--accent: #3fb08c;
|
|||
|
|
--accent-soft: #1e332c;
|
|||
|
|
--warn: #d9a04a;
|
|||
|
|
--warn-soft: #33290f;
|
|||
|
|
--mono-bg: #232d29;
|
|||
|
|
}
|
|||
|
|
:root[data-theme="light"] {
|
|||
|
|
--paper: #f6f7f4;
|
|||
|
|
--card: #ffffff;
|
|||
|
|
--ink: #1e2733;
|
|||
|
|
--ink-soft: #4c5a66;
|
|||
|
|
--line: #dde3dc;
|
|||
|
|
--accent: #0f7b5f;
|
|||
|
|
--accent-soft: #e3f0ea;
|
|||
|
|
--warn: #b7791f;
|
|||
|
|
--warn-soft: #f7edda;
|
|||
|
|
--mono-bg: #eef1ec;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
body {
|
|||
|
|
background: var(--paper);
|
|||
|
|
color: var(--ink);
|
|||
|
|
font-family: -apple-system, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
|
|||
|
|
line-height: 1.75;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0 1.25rem 4rem;
|
|||
|
|
}
|
|||
|
|
main { max-width: 860px; margin: 0 auto; }
|
|||
|
|
|
|||
|
|
h1, h2, h3 {
|
|||
|
|
font-family: "Songti SC", "Noto Serif CJK SC", "SimSun", serif;
|
|||
|
|
text-wrap: balance;
|
|||
|
|
line-height: 1.35;
|
|||
|
|
}
|
|||
|
|
h1 { font-size: 2rem; margin: 2.5rem 0 0.5rem; }
|
|||
|
|
h2 {
|
|||
|
|
font-size: 1.4rem;
|
|||
|
|
margin: 3rem 0 0.75rem;
|
|||
|
|
padding-top: 1.5rem;
|
|||
|
|
border-top: 1px solid var(--line);
|
|||
|
|
}
|
|||
|
|
h2 .no {
|
|||
|
|
color: var(--accent);
|
|||
|
|
font-family: ui-monospace, "SF Mono", Consolas, monospace;
|
|||
|
|
font-size: 0.95rem;
|
|||
|
|
margin-right: 0.6rem;
|
|||
|
|
letter-spacing: 0.05em;
|
|||
|
|
}
|
|||
|
|
h3 { font-size: 1.1rem; margin: 1.75rem 0 0.5rem; }
|
|||
|
|
|
|||
|
|
.lede { color: var(--ink-soft); font-size: 1.05rem; max-width: 42em; }
|
|||
|
|
|
|||
|
|
.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1.25rem 0 0; }
|
|||
|
|
.chip {
|
|||
|
|
background: var(--accent-soft);
|
|||
|
|
color: var(--accent);
|
|||
|
|
border-radius: 999px;
|
|||
|
|
padding: 0.15rem 0.8rem;
|
|||
|
|
font-size: 0.85rem;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
code, .path {
|
|||
|
|
font-family: ui-monospace, "SF Mono", Consolas, "Courier New", monospace;
|
|||
|
|
font-size: 0.88em;
|
|||
|
|
background: var(--mono-bg);
|
|||
|
|
border-radius: 4px;
|
|||
|
|
padding: 0.1em 0.4em;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.diagram {
|
|||
|
|
background: var(--card);
|
|||
|
|
border: 1px solid var(--line);
|
|||
|
|
border-radius: 8px;
|
|||
|
|
padding: 1rem;
|
|||
|
|
margin: 1rem 0 1.5rem;
|
|||
|
|
overflow-x: auto;
|
|||
|
|
}
|
|||
|
|
.diagram figcaption {
|
|||
|
|
color: var(--ink-soft);
|
|||
|
|
font-size: 0.85rem;
|
|||
|
|
margin-top: 0.5rem;
|
|||
|
|
border-top: 1px dashed var(--line);
|
|||
|
|
padding-top: 0.5rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
table {
|
|||
|
|
border-collapse: collapse;
|
|||
|
|
width: 100%;
|
|||
|
|
font-size: 0.92rem;
|
|||
|
|
margin: 1rem 0 1.5rem;
|
|||
|
|
}
|
|||
|
|
.tablewrap { overflow-x: auto; }
|
|||
|
|
th, td {
|
|||
|
|
border: 1px solid var(--line);
|
|||
|
|
padding: 0.5rem 0.75rem;
|
|||
|
|
text-align: left;
|
|||
|
|
vertical-align: top;
|
|||
|
|
}
|
|||
|
|
th { background: var(--accent-soft); color: var(--ink); font-weight: 600; white-space: nowrap; }
|
|||
|
|
td:first-child { white-space: nowrap; }
|
|||
|
|
|
|||
|
|
.note {
|
|||
|
|
border-left: 3px solid var(--warn);
|
|||
|
|
background: var(--warn-soft);
|
|||
|
|
padding: 0.75rem 1rem;
|
|||
|
|
border-radius: 0 6px 6px 0;
|
|||
|
|
margin: 1.25rem 0;
|
|||
|
|
font-size: 0.95rem;
|
|||
|
|
}
|
|||
|
|
.note b { color: var(--warn); }
|
|||
|
|
|
|||
|
|
.tip {
|
|||
|
|
border-left: 3px solid var(--accent);
|
|||
|
|
background: var(--accent-soft);
|
|||
|
|
padding: 0.75rem 1rem;
|
|||
|
|
border-radius: 0 6px 6px 0;
|
|||
|
|
margin: 1.25rem 0;
|
|||
|
|
font-size: 0.95rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ol.first-day { padding-left: 1.5rem; }
|
|||
|
|
ol.first-day li { margin: 0.5rem 0; }
|
|||
|
|
|
|||
|
|
footer {
|
|||
|
|
margin-top: 4rem;
|
|||
|
|
padding-top: 1rem;
|
|||
|
|
border-top: 1px solid var(--line);
|
|||
|
|
color: var(--ink-soft);
|
|||
|
|
font-size: 0.85rem;
|
|||
|
|
}
|
|||
|
|
a { color: var(--accent); }
|
|||
|
|
</style>
|
|||
|
|
|
|||
|
|
<main>
|
|||
|
|
<h1>仓库导览:harness_coding_docs</h1>
|
|||
|
|
<p class="lede">写给刚接手这个项目的你。这<strong>不是一个业务应用</strong>,而是一个<strong>文档模板仓库</strong>:它沉淀了「把项目交给 AI coding agent 开发之前,应该准备哪些文档」的一整套模板。你复制它到新项目、替换占位符,agent 就能靠仓库内的文件(而不是聊天记录)持续推进开发。</p>
|
|||
|
|
<div class="chips">
|
|||
|
|
<span class="chip">纯 Markdown + 少量脚本</span>
|
|||
|
|
<span class="chip">中文模板 · 【占位符】待替换</span>
|
|||
|
|
<span class="chip">不绑定任何技术栈</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<h2><span class="no">01</span>先分清两种身份</h2>
|
|||
|
|
<p>这个仓库同时扮演两个角色,任务编号也分成两套,千万别混:</p>
|
|||
|
|
<div class="tablewrap">
|
|||
|
|
<table>
|
|||
|
|
<tr><th></th><th>维护模板本身</th><th>复制到新项目后使用</th></tr>
|
|||
|
|
<tr><td>任务列表</td><td>根目录 <code>tasks.md</code></td><td><code>docs/tasks/</code> 一任务一文件</td></tr>
|
|||
|
|
<tr><td>任务编号</td><td><code>H-xxx</code>(如 H-412)</td><td><code>T-xxx</code>(如 T-001)</td></tr>
|
|||
|
|
<tr><td>路线图</td><td><code>tasks.md</code> 的 Phase 0–6</td><td><code>docs/06-tasks.md</code>(只读路线图)</td></tr>
|
|||
|
|
<tr><td>你现在的工作</td><td>改进模板、保持一致性</td><td>——(新项目里才用)</td></tr>
|
|||
|
|
</table>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<h2><span class="no">02</span>文档全景图</h2>
|
|||
|
|
<p>所有规则的唯一权威源是 <code>AGENTS.md</code>(<code>CLAUDE.md</code> 只是指向它的薄入口)。文档按职责分层,每一层回答一个问题:</p>
|
|||
|
|
<figure class="diagram">
|
|||
|
|
<pre class="mermaid">
|
|||
|
|
flowchart TD
|
|||
|
|
A["AGENTS.md<br/>仓库级规则 · 唯一权威源"] --> S["docs/00-ai-start-here.md<br/>agent 每轮工作的入口"]
|
|||
|
|
C["CLAUDE.md<br/>薄入口"] -.指向.-> A
|
|||
|
|
|
|||
|
|
S --> P["产品层:做什么"]
|
|||
|
|
S --> E["工程层:怎么做"]
|
|||
|
|
S --> T["任务层:现在做哪件"]
|
|||
|
|
S --> Q["状态与质量层:做得怎样"]
|
|||
|
|
|
|||
|
|
subgraph P["产品层 · 做什么"]
|
|||
|
|
P1["01-vision 愿景"] --> P2["02-requirements 需求"]
|
|||
|
|
P2 --> P3["07-user-stories 用户故事 US"]
|
|||
|
|
P3 --> P4["08-interaction-checklist 交互 IX"]
|
|||
|
|
P4 -.输入素材.- P5["design/ HTML 原型"]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph E["工程层 · 怎么做"]
|
|||
|
|
E1["03-tech-stack 技术栈"]
|
|||
|
|
E2["04-architecture 架构"]
|
|||
|
|
E3["05-coding-rules 编码规则"]
|
|||
|
|
E4["api.md / routes.md 合约"]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph T["任务层 · 现在做哪件"]
|
|||
|
|
T1["06-tasks 只读路线图"] --> T2["docs/tasks/T-xxx.md<br/>一任务一文件"]
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
subgraph Q["状态与质量层 · 做得怎样"]
|
|||
|
|
Q1["current-state 项目快照"]
|
|||
|
|
Q2["clean-state-checklist 收尾清单"]
|
|||
|
|
Q3["evaluator-rubric 评审评分"]
|
|||
|
|
Q4["quality-document 长期健康度"]
|
|||
|
|
end
|
|||
|
|
</pre>
|
|||
|
|
<figcaption>读的顺序就是图的顺序:先规则入口,再产品层建立「做什么」,工程层约束「怎么做」,最后从任务层领活。<code>progress.md</code> 是可选的历史归档,执行记录默认写在各任务文件里。</figcaption>
|
|||
|
|
</figure>
|
|||
|
|
|
|||
|
|
<h2><span class="no">03</span>每轮会话的标准工作流</h2>
|
|||
|
|
<p>agent(或你自己)每次打开这个项目,走的都是同一条固定流程——开工有基线检查,收尾有清单,保证下一轮不需要人工修复就能继续:</p>
|
|||
|
|
<figure class="diagram">
|
|||
|
|
<pre class="mermaid">
|
|||
|
|
flowchart TD
|
|||
|
|
A["开工:确认目录 pwd"] --> B["读 current-state.md<br/>和 DOING 中的任务文件"]
|
|||
|
|
B --> C["git log 看最近改动"]
|
|||
|
|
C --> D["跑 init.sh / init.ps1<br/>安装依赖 + 基础验证"]
|
|||
|
|
D --> E{"基线是绿的吗?"}
|
|||
|
|
E -- 否 --> F["先修基线<br/>不做新功能"]
|
|||
|
|
F --> D
|
|||
|
|
E -- 是 --> G["从 docs/tasks/ 领一个任务<br/>TODO 且依赖全 DONE,一次只领一个"]
|
|||
|
|
G --> H["实现 + 自测"]
|
|||
|
|
H --> I{"验证命令全绿?"}
|
|||
|
|
I -- 否 --> J["如实报告红灯<br/>状态改 DOING / BLOCKED<br/>不提交"]
|
|||
|
|
I -- 是 --> K["把命令和结果写进任务文件<br/>## 执行记录 作为证据"]
|
|||
|
|
K --> L["状态改 DONE · 提交"]
|
|||
|
|
L --> M["收尾:过一遍<br/>clean-state-checklist.md"]
|
|||
|
|
</pre>
|
|||
|
|
<figcaption>核心纪律叫「证据绑定完成」:DONE 必须附带可运行的验证命令和结果,「代码已写」不算完成。</figcaption>
|
|||
|
|
</figure>
|
|||
|
|
|
|||
|
|
<h2><span class="no">04</span>一个任务的一生</h2>
|
|||
|
|
<p>任务管理默认「一任务一文件」:路线图上的条目只是建议,开工时才落成真正的任务文件。文件头部的 frontmatter 状态就是唯一权威状态:</p>
|
|||
|
|
<figure class="diagram">
|
|||
|
|
<pre class="mermaid">
|
|||
|
|
flowchart LR
|
|||
|
|
R["06-tasks.md 路线图<br/>建议拆分清单"] -- 开工时落文件 --> F["docs/tasks/T-xxx.md<br/>status: TODO"]
|
|||
|
|
F -- 领取 --> D["status: DOING<br/>写清 write_paths 防冲突"]
|
|||
|
|
D -- 验证全绿 + 证据入执行记录 --> OK["status: DONE"]
|
|||
|
|
D -- 被阻塞 --> BL["status: BLOCKED<br/>blocker 同步到 current-state"]
|
|||
|
|
BL -- 解除 --> D
|
|||
|
|
</pre>
|
|||
|
|
<figcaption>编号规则:沿用路线图建议的编号,新任务取现有最大 T 编号 +1。多个 agent 并行时,<code>write_paths</code> 重叠的任务不能同时进行。</figcaption>
|
|||
|
|
</figure>
|
|||
|
|
|
|||
|
|
<h2><span class="no">05</span>UI 需求专线:从一句话到可验收</h2>
|
|||
|
|
<p>有界面的需求走一条专门的流水线,把「页面上有什么」和「行为该怎样」分开处理:</p>
|
|||
|
|
<figure class="diagram">
|
|||
|
|
<pre class="mermaid">
|
|||
|
|
flowchart TD
|
|||
|
|
A["用一两句话描述页面"] --> B["AI 生成低保真原型<br/>docs/design/xxx.html 单文件"]
|
|||
|
|
B --> C{"人工看图认可?"}
|
|||
|
|
C -- 调整 --> B
|
|||
|
|
C -- 认可 --> D["AI 据原型枚举交互<br/>产出 IX 总表草稿 · 全标待确认"]
|
|||
|
|
D --> E["人工逐条确认行为决策<br/>优先级 / 状态与异常 / 无障碍"]
|
|||
|
|
E --> F["P0 交互按完整模板展开<br/>10 行状态表 + 无障碍 + 验收证据"]
|
|||
|
|
F --> G["拆成任务文件 · 关联 US / IX 编号"]
|
|||
|
|
G --> H["实现 · 截图进执行记录"]
|
|||
|
|
H --> X["原型即视为过期<br/>不承担同步义务"]
|
|||
|
|
</pre>
|
|||
|
|
<figcaption>权威关系要记牢:行为的权威永远是 <code>08-interaction-checklist.md</code>,原型只是一次性输入物;原型里有但需求没有的功能,不能因为「图上有」就实现;禁止把原型代码直接复制进生产实现。</figcaption>
|
|||
|
|
</figure>
|
|||
|
|
|
|||
|
|
<h2><span class="no">06</span>暗语速查表</h2>
|
|||
|
|
<p>用户会用短指令驱动工作,约定在 <code>docs/tasks/README.md</code>。看到这些词就知道该做什么、不该做什么:</p>
|
|||
|
|
<div class="tablewrap">
|
|||
|
|
<table>
|
|||
|
|
<tr><th>触发词</th><th>含义</th><th>关键边界</th></tr>
|
|||
|
|
<tr><td><code>bug:</code> / <code>需求:</code></td><td>只分析,给结论</td><td>不改任何代码和文档</td></tr>
|
|||
|
|
<tr><td><code>grill:</code></td><td>反方视角严格评审</td><td>专挑毛病,不粉饰</td></tr>
|
|||
|
|
<tr><td><code>落</code> / <code>落task</code></td><td>把结论写成任务文件</td><td>只改文档,写完即提交</td></tr>
|
|||
|
|
<tr><td><code>做 T-xxx</code></td><td>实现该任务</td><td>验证全绿才提交;红灯只报告、不提交</td></tr>
|
|||
|
|
<tr><td><code>审 T-xxx</code></td><td>基于 git 历史核实审核</td><td>对照落任务时的验收原文逐条核对</td></tr>
|
|||
|
|
<tr><td><code>补</code></td><td>把结论补进对应文档</td><td>追加,不重写历史</td></tr>
|
|||
|
|
<tr><td><code>记backlog:</code></td><td>记一行待办</td><td>进待办池,不展开</td></tr>
|
|||
|
|
</table>
|
|||
|
|
</div>
|
|||
|
|
<div class="note"><b>一条铁律:</b>任务的验收要点一经领取就不能改写——完成时只改状态列,证据另记。事后把验收改写成「已完成 X」来自证达标,会架空整个证据机制。</div>
|
|||
|
|
|
|||
|
|
<h2><span class="no">07</span>第一天该做什么</h2>
|
|||
|
|
<ol class="first-day">
|
|||
|
|
<li>按顺序读:<code>AGENTS.md</code> → <code>README.md</code> → <code>docs/README.md</code> → <code>docs/00-ai-start-here.md</code>。这四个文件读完,其余文档按需查即可。</li>
|
|||
|
|
<li>跑一次一致性校验,感受这个仓库的验证方式:<code>python3 scripts/validate_agent_context.py</code>。</li>
|
|||
|
|
<li>用 <code>git log --oneline -20</code> 看最近的提交——commit message 都以任务编号结尾(如 <code>(H-413)</code>),顺着编号在 <code>tasks.md</code> 里能找到每次改动的验收要点,这就是本仓库的「审计线索」。</li>
|
|||
|
|
<li>翻一眼 <code>docs/method-map.md</code>:它是「失败模式 → 修复方法 → 对应工件」的对照表,迷路时从这里找回入口。</li>
|
|||
|
|
<li>想练手,从 <code>tasks.md</code> 里挑一个 <code>TODO</code> 的小任务(如 H-301 系列一致性检查),按第 03 节的流程完整走一遍。</li>
|
|||
|
|
</ol>
|
|||
|
|
|
|||
|
|
<h2><span class="no">08</span>可选层:Gitea 多 Agent 协作</h2>
|
|||
|
|
<p>当前分支(<code>feat/gitea-multi-agent-context</code>)还带了一个可选层:多个 agent 并行开发时,用自建 Gitea 做协调——Issue/PR 管实时状态、<code>agent-context.json</code> 按任务类型路由该读哪些文档、脚本做治理检查。相关文档是 <code>docs/gitea-mcp.md</code> 和 <code>docs/gitea-collaboration.md</code>。<strong>单人 + 单 agent 用不到它</strong>,知道存在即可;启用前先读安全基线(私有配置不入库、Token 不提交)。</p>
|
|||
|
|
|
|||
|
|
<div class="tip">迷路时的两个锚点:规则不确定 → 回 <code>AGENTS.md</code>;现状不确定 → 回 <code>docs/current-state.md</code> 和 <code>git log</code>。聊天记录永远不是事实来源,仓库里的文件才是。</div>
|
|||
|
|
|
|||
|
|
<footer>基于 2026-07-17 的仓库状态生成 · 分支 feat/gitea-multi-agent-context · 最新提交 bc70cb4</footer>
|
|||
|
|
</main>
|
|||
|
|
|
|||
|
|
</body>
|
|||
|
|
</html>
|