-
Notifications
You must be signed in to change notification settings - Fork 0
Concepts
The core ideas behind SpecGit:
evidence not assertion — acceptance is derived from git, PR, and CI facts
fail-closed not hopeful — anything unverifiable is "unknown", never "accepted"
git is the contract — the branch, the PR, and the checks are the deliverable
SpecGit does not manage plans, specs, or task lists. By the time it looks at your work, the work already exists as a branch, issues, a pull request, and CI checks. Its only job is to verify — from real evidence — that the delivery is complete.
SpecGit's entire footprint is three tiers of files:
| Tier | Files | Committed? |
|---|---|---|
| Authoritative |
spec_git/policy.yaml (required checks, created by init), .specgit.yaml (this delivery's binding, created by issue), optional spec_git/providers.yaml (declared GitLab host) |
Yes |
| Derived harness |
.github/workflows/specgit-accept.yml (the SpecGit Acceptance job) and the managed block in AGENTS.md/CLAUDE.md — regenerate with init --force, never hand-edit |
Yes |
| Local integration | Guard hooks (.git/hooks/pre-push, .opencode/hooks/*) and setup entry points — agent conveniences, merged non-destructively, never acceptance inputs |
Your choice |
No artifact folders, no caches, no global stores. Verdicts are never persisted — they are computed on every run, so nothing can lie about itself.
Every delivery is one aggregate, declared in the record file .specgit.yaml:
| Part | What it is |
|---|---|
| Delivery | A kebab-case id (add-login-flow) |
| Execution context | A branch, or a linked worktree plus its branch — always resolved from live git at evaluation time |
| Issues | 1..N forge issue numbers the delivery closes |
| Pull request | Exactly one PR (or MR) that merges the delivery |
| Required checks | CI check names that must pass at the PR head (from the policy) |
One PR may close N issues (Closes #123, Fixes #124, …). Every bound issue must be closed by the PR's closing references — missing any one fails acceptance with the missing numbers listed.
The unit of scope is the issue: each one must be verifiable on its own evidence. If a deliverable cannot be verified on its own, split it before binding. One delivery binds N issues to one PR that closes them all.
Delivery states — unbound, draft, bound, accepted, rejected, unknown — are computed on every invocation, never stored. Evaluation runs eleven gates in order, from cheapest local facts to live forge evidence:
- Record present and valid
- Policy present and valid
- Completeness (≥1 issue, exactly 1 PR)
- Context matches live git
- Origin resolves to a forge repository
- Provider reachable and authenticated
- Issues exist (and are issues, not PRs)
- Sequence (when ordered issues is on)
- PR exists, open or merged, head matches the context branch, same repository
- PR body closes every bound issue
- Every required check is green at the PR head commit
Outcomes:
- All evidence gathered, ≥1 gate failed → rejected (exit 1) with complete evidence
- Evidence could not be gathered → unknown (exit 3) — never
accepted - Every gate passed with evidence → accepted (exit 0)
Consequences: finish offline can return unknown, never accepted; a dirty working tree never fails acceptance (acceptance is about the PR head, not local edits); a draft PR always fails (pr_draft).
Not a spec framework (no proposal/task artifacts), not a git wrapper (reads facts, never rewrites history), not an issue tracker or CI system (verifies against your forge and existing CI), not a plugin platform.
SpecGit 的核心理念:
证据而非断言 —— 验收结论从 git、PR、CI 事实推导
fail-closed —— 无法验证的一律是 "unknown",绝不 "accepted"
git 即契约 —— 分支、PR、检查就是交付物本身
SpecGit 不管理计划、规格或任务清单。当它审视你的工作时,工作已经以分支、issue、PR 和 CI 检查的形式存在。它唯一的职责是凭真实证据验证交付是否完成。
SpecGit 的全部文件足迹分三层:
| 层级 | 文件 | 是否提交 |
|---|---|---|
| 权威文件 |
spec_git/policy.yaml(必需检查项,init 创建)、.specgit.yaml(本次交付的绑定,issue 创建)、可选 spec_git/providers.yaml(声明的 GitLab 主机) |
是 |
| 派生护栏 |
.github/workflows/specgit-accept.yml(SpecGit Acceptance 任务)和 AGENTS.md/CLAUDE.md 中的受管区块 —— 用 init --force 重新生成,切勿手工编辑 |
是 |
| 本地集成 | 守卫 hooks(.git/hooks/pre-push、.opencode/hooks/*)和 setup 入口 —— agent 便利设施,非破坏性合并,不作为验收输入 |
自定 |
没有产物目录、缓存或全局存储。结论永不持久化 —— 每次运行都重新计算,因此任何状态都无法自证为完成。
每次交付是一个聚合体,声明在记录文件 .specgit.yaml 中:
| 部分 | 含义 |
|---|---|
| Delivery | kebab-case 标识(如 add-login-flow) |
| 执行上下文 | 分支,或 linked worktree 加分支 —— 评估时始终从实际 git 状态解析 |
| Issues | 本次交付关闭的 1..N 个 forge issue 编号 |
| Pull request | 恰好一个合并该交付的 PR(或 MR) |
| 必需检查 | 必须在 PR head 通过的 CI 检查名(来自策略) |
一个 PR 可以关闭 N 个 issue(Closes #123、Fixes #124 等)。每个绑定的 issue 都必须被 PR 的关闭引用关闭 —— 缺少任何一个都会验收失败,并列出缺失的编号。
范围的基本单位是 issue:每个 issue 必须能凭自身证据独立验证。如果一个交付物无法独立验证,绑定前先拆分。一次交付把 N 个 issue 绑定到一个关闭它们的 PR。
交付状态 —— unbound、draft、bound、accepted、rejected、unknown —— 每次调用都重新计算,永不存储。评估按顺序运行十一个门禁,从最廉价的本地事实到实时 forge 证据:
- 记录存在且有效
- 策略存在且有效
- 完整性(≥1 个 issue,恰好 1 个 PR)
- 上下文与实际 git 匹配
- Origin 能解析为 forge 仓库
- Provider 可达且已认证
- Issues 存在(且是 issue 而非 PR)
- 顺序性(开启 ordered issues 时)
- PR 存在、open 或 merged、head 与上下文分支一致、同一仓库
- PR 正文关闭每个绑定的 issue
- 每个必需检查在 PR head commit 上为绿
结果:
- 证据全部收集、至少一个门禁失败 → rejected(退出 1),附完整证据
- 证据无法收集 → unknown(退出 3)—— 绝不
accepted - 所有门禁凭证据通过 → accepted(退出 0)
推论:离线运行 finish 可能返回 unknown,但绝不返回 accepted;脏工作区不会导致验收失败(验收针对 PR head,不是本地改动);draft PR 必然失败(pr_draft)。
不是规格框架(没有提案/任务产物),不是 git 封装(只读事实,不改写历史),不是 issue 跟踪器或 CI 系统(对着你的 forge 和现有 CI 做验证),不是插件平台。