跳到正文

GSD Core

「Git. Ship. Done.」——一个元提示、上下文工程与规格驱动开发的框架,每个里程碑都重复同一条五步回路:讨论、计划、执行、验证、发版。重活被推给上下文全新的子 agent,主会话因此保持轻量;每一项决定都写进规划目录下的 Markdown 与 JSON,而不是留在对话里。

Screenshot of GSD Core
编辑截图, 30 Sep 2026GSD Core ↗

这是什么

一个夹在人和他所用的编码 agent 之间的框架,它让 agent 走的是一条有纪律的回路,而不是一场聊天。每个里程碑都按阶段重复五步:先讨论实现决定,再计划、并检查这份计划能不能装进它将要运行的那个上下文;然后让计划分波并行执行,每个执行者都从干净的窗口开始;接着逐项走查做出来的东西;最后发版。它针对的问题是上下文腐坏——agent 把窗口填满时累积起来的质量下降——所以研究、计划与执行都发生在上下文全新的子 agent 里,主会话被刻意留薄。所有状态都以文件形式放在一个规划目录下,是人和 agent 都能读的 Markdown 与 JSON:项目简述、需求、路线图、状态与配置,没有数据库也没有服务端,因此它能挺过一次上下文重置,也能提交进 git。安装只有一条命令,之后安装器会问你要装进哪个 runtime、装到全局还是装进某个项目。

谁做的这是一个组织账号,不是某个人——署名因此分得极不均匀。仓库有 6,046 次提交、50 位列出的贡献者:trek-e 的提交署名 Tom Boucher、邮箱 trekkie@nomorestars.com,他名下 3,742 次;glittercowboy 945 次;其后是 davesienkowski 133 次、Tibsfox 127 次、jeremymcs 122 次、github-actions[bot] 95 次、0xdhx 82 次。6,046 次提交里有 5,829 次关联到了账号,217 次没有。3,143 条共同作者尾注里最大的单个条目不是模型而是「sim」,540 条;另有跨 19 个不同名字的 Claude 模型共 2,309 条,其中最大的一项是 Claude Sonnet 4.6 的 465 条。

它是怎么搭起来的

组成 · 6

用户和 agent runtime 之间有四层:命名命令的提示文件、负责编排的工作流文件、各自拿到全新上下文的 agent 定义,以及一个掌管状态的命令行工具——全都压在一个由 Markdown 与 JSON 组成的规划目录之上。因为产品本身就是提示词文本和生成它的代码,这个架构的绝大部分是在让散文变得有界、可测:每套词汇只有一个所有者,每个文件有字节上限,一旦被禁止的写入或已退役的 runtime 名字回来,lint 守卫就让测试套件挂掉,棘轮的上限只许收紧。状态刻意不做成服务,它就是文件——所以上下文重置弄不丢它,git 能带着它走,同一套框架也因此能装进十几种 runtime,而不必为其中某一种重写一遍。

commands/gsd/ 与 skills/
72 个命令文件、185 KB,每个都是 frontmatter 加一段提示正文,由安装器转成目标 runtime 接受的形式——斜杠命令、技能或 agent 文件。六个 ns-*.md 命名空间路由压在这些具体命令之上,另有一个并行的 skills/ 目录,为这 72 个命令各放一份 SKILL.md。
gsd-core/workflows/
182 个文件、2,357 KB,其中 89 个在顶层。最重的三个是 plan-phase 的 96,328 字节、execute-phase 的 87,727 和 review 的 51,996;字节预算直接写在目录形态上——超出自己档位的工作流长出了 modes/、steps/、detail/ 和 templates/ 子目录,只有那一步需要时才会被读到。
agents/ 与 gsd-core/references/
64 份 agent 定义、1,025 KB,其中 29 份有 .compact.md 的孪生版本;其下是一个 132 个文件、738 KB 的参考目录。参考文档存在的意义是被按需按名读取;执行者存在的意义是从空开始,定义说的是它「可以」做什么,而不是它「应该」知道什么。
gsd-core/bin/ 与 hooks/
gsd-tools.cjs 有 290,161 字节,铺在 24 个文件上,另有内嵌的解析器——re2js 252,184 字节、js-yaml 131,632 字节——以及模型目录、配置 schema 和退出码的共享 JSON 清单。42 个钩子文件,其中十二个在 hooks/lib/ 下,覆盖状态栏、上下文告警、密钥与注入守卫,以及 Cursor、Windsurf 和 shell 这几类 runtime。
src/、tests/ 与 scripts/
215 个编译出来的 .cts 模块,合计 7,228 KB,其中 state.cts 一个就 376,952 字节、phase.cts 267,763 字节;1,247 个测试文件;以及 143 个脚本、2,195 KB,装着守卫、生成器和发布工具。安装器是单独一个 714,827 字节的文件。
docs/ 与规划记录
98 份决策记录、1,827 KB,外加一份 34 KB 的索引;183 份特性笔记;贡献、分支、版本与测试指南;.out-of-scope/ 里二十份写明的不做;464 份归档 changeset;以及整套翻译过的文档,分放在 docs/ja-JP/、docs/ko-KR/、docs/pt-BR/ 和 docs/zh-CN/ 下。922 KB 的 changelog 是把发布史重新写了一遍。

取舍,以及它替代了什么

  • 用字节来量工作流预算 替代 沿用 agent 预算那套按行数计的做法

    理由写在架构文档里:按行计会高估散文、漏掉 token 密集的表格和代码块,而字节是确定性的,也对得上厂商自己设限的单位。数值取自某家厂商的截断阈值,但只取单位、刻意不取那个数字,因为这些是被 agent 读取的编排者,不是从文件里贴过来的指令文档。

  • 只有被抽出去的文件确实按需读取,才算省下 替代 把「被测量到的文件变小」当成「上下文变小」

    写明的理由是这样会操纵代理指标而不是服务目标:把散文挪进一个仍被急切导入的文件,缩小的只是被测量到的体积,不是被载入的上下文。规划者与执行者的 MVP 正文因此改成按名引用,只在需要那条路径时读取。

  • 加载器不递归的 runtime 用嵌套,其余保持平铺 替代 所有 runtime 共用一套技能布局

    两级布局只在加载器不递归的 runtime 上落地;Claude 被改回平铺,因为它的技能工具遇到未知名字会直接报错而不是交给路由;Antigravity 从嵌套改成平铺,因为它只扫技能目录的顶层,嵌在里面的子技能根本够不着。

  • 上限只许下降 替代 固定限额、工作流长大了就放宽

    在「只许收紧」的棘轮下,每个上限追着自己档位当前的高水位、只留一小段宽限带,于是预算可以被调低,却不会被悄悄调高。同一种形态在仓库里反复出现:测试数量、lint 例外和变异分数各有一份提交进仓库的上限文件。

  • 以磁盘上的事实为准,并把不一致报出来 替代 让路线图里那个打勾的复选框说了算

    维护者对一次不一致报告做出的裁决,是让选择器继续以磁盘为准,同时新增一个恒定存在的冲突字段,逐条列出路线图复选框与阶段目录不一致的阶段及其计划数和摘要数。他们选择让人看见这处不一致,而不是悄悄替它裁决;而一次字节级不变的重构里唯一的行为改变,是带着一份写明的 changeset 发布的。

依据docs/ARCHITECTURE.md(82,825 字符,含工作流字节预算与技能路由两节);完整的 3,630 个文件树及其体积,以及两级目录汇总;docs/adr/ 下 99 个文件;.changeset/ 下 27 份现存与 464 份归档;.out-of-scope/ 里二十份「不做」;.github/workflows/ 下 31 条工作流;README.md;以及三十个最新 issue 与 pull request 的全文。

制作过程

6 个阶段
  1. 01

    一段比装它的仓库更老的历史

    元数据说仓库建于 2026-05-22,属于 open-gsd 组织;但它带着的最早一次提交日期是 2025-12-14,标题是「Initial commit: Get Shit Done - meta-prompting system for Claude Code」——项目是在另一个名字下开始的,历史跟着一起搬了过来。改名没有被当作仓库设置处理:它以安装器迁移 003-rename-get-shit-done-to-gsd-core.cts、一份归档的 changeset 文件、以及 docs/cleanup-get-shit-done-cc.md 的形式留在树里——当用户磁盘上已经装好文件之后,改名就必须变成这些东西。默认分支是 next 而不是 main。十个月里这个仓库落了 6,046 次提交:2025 年 12 月 101 次,此后任何一个月都不少于 276 次,峰值是它被创建的那个月的 1,028 次。周围是 10,038 个星、719 个 fork、43 个 watcher、186 个打开着的 issue,树是 3,630 个文件、76 MB。最新一次提交落在本记录的最后一天,修的是「让每个接受参数的命令模板都标明用户的参数」。

  2. 02

    流程本身就是这个仓库里最大的产物

    口号是「Git. Ship. Done.」,而这个项目把这条回路公开地跑在自己身上。docs/adr/ 下有 98 份架构决策记录,每一份都按产生它的 issue 编号,从一份 1,405 字节的短记,到长达 126,874 字节的「规划语义模型的唯一所有者」;其余的长篇讲的是「以构造来强制」「可嵌入的编排引擎」和「每个工作流产出一个裁决者」。它们上面的索引由一个脚本生成、由一份 87 KB 的测试把关,所以新写的记录没被索引进去就会挂掉构建。记录之上是拆成编号阶段的 epic:epic #5056 由 ADR-5057 设计、至少分七期交付,而每一期都自带一个 issue、一个 pull request,和一份先失败测试——它先被写成在当前代码上失败,等修复落地才关闭。pull request 正文会点名引用 ADR 的章节和期号,任何改变行为的期都要带一条 changeset。仓库还留着自己的产出:.gsd/phase/feat-3677-quick-batch-hardening-acceptance/ 里放着一份 29 KB 的设计文档、一份测试矩阵和 12 KB 的验收证据。

  3. 03

    31 条工作流,一条对着一条「不再靠约定」的规则

    .github/workflows/ 下有 31 条工作流,它们的名字读起来就是一份「哪些事不再靠自觉」的清单。pr-target-validator 会在一个从普通修复分支指向 main 的 pull request 下留言,说多数 pull request 应该指向 next,然后列出四种例外:release 分支、hotfix 分支、生产事故用的 critical-fix 分支,以及 back-merge。pr-template-format 要求三种带类型模板之一,正文里没有对应的小标题就打回;当一位贡献者的补丁本身没问题时,机器提出的异议在一个小时内就被答复:把分支改了目标、补上小标题,并注明补丁本身没动。auto-branch 负责建分支,并把检出它的两条命令贴在评论里。此外还有 require-issue-link、changeset-required、docs-required、duplicate-check、duplicate-sweep、dismiss-unauthorized-pr-approvals、auto-close-unsolicited-prs、branch-cleanup、stale 和一条 version-gate。其中一条自己坏了:Dependabot 自动合并那个 job 只声明了 pull-requests: write,于是每一个依赖 pull request 上 gh pr merge --auto 都失败,直到那个 job 被补上 contents: write。

  4. 04

    测试套件是这棵树里最大的目录

    tests/ 有 1,247 个文件、约 29 MB,比它测试的源码还大:其中 997 个文件直接放在该目录下,其余分在 146 个夹具、35 个 helper 和一个 55 文件的 QA 集里。跑测试的脚本本身有 119 KB。普通测试文件旁边还有 property 测试、九个 unit.test.cjs,以及一个 adversarial/ 夹具目录,为 frontmatter、路线图、安全和 TOML 解析各备了一套语料。静态强制是第二道墙:eslint-rules/ 下有 32 条自定义 ESLint 规则,包括 no-adhoc-markdown-parsing、no-source-grep、no-tautological-assert、no-magic-sleep-in-tests、no-posix-mode-bit-assert 和 no-rendered-text-length-assert——每一条都是因为那个错误已经被犯过一次才写出来的。scripts/ 里另有 55 个 lint-* 脚本、22 个 gen-* 生成器和七个 check-* 守卫,各自带着提交进仓库的白名单文件。其中好几个是带上限文件的棘轮,数字只许往下走:变异分数棘轮、白名单棘轮、测试文件数棘轮,以及一份把每个 CI job 的墙钟时间和它的超时并排记下来的历史文件——它由唯一一个滚动 pull request 持续发布。

  5. 05

    以字节计的预算,而且只能收紧

    这个仓库里最有辨识度的工程不是冲着代码去的,而是冲着提示词文本去的。工作流文件在对应命令每次运行时都会被原样读进 agent 的上下文,所以它们被一份测试把着的字节预算管着:三个顶层编排者 90,000 字节、大型工作流 54,000、单一用途的 38,000,而上限只许下降。理由写在文档里:用字节而不是行数,因为按行计会高估散文、又漏掉 token 密集的表格和代码块;单位取自某家厂商的截断阈值,但刻意不采用那个数字;还有一条附加说明——抽取只有在被抽出去的文件在该步骤按需读取时才算省,因为把散文挪进一个仍然被急切导入的文件里,缩小的是被测量到的体积,而不是上下文。同一种压力催生了 workflows/discuss-phase/:父文件变成调度器,按 flag 分的行为挪进九个 mode 文件;也催生了 29 份 agent 定义的 .compact.md 版本。另有一套预算管着技能:一份平铺的 86 个技能清单每一轮都要花掉大约 2,150 个 token,于是在它们之上加了六个命名空间路由,成本约 120 个 token,用的是竖线分隔的关键词标签,依据是公开的路由研究。

  6. 06

    哪些事被禁掉,以及用户照样找到了什么

    这个仓库里有异常大的一部分在讲「不许做什么」。.out-of-scope/ 下放着二十份文件,每一份都是写明「不做」的决定——把别的 runtime 放进核心、给计划文档做人可读的渲染、给子 agent 加看门狗——另有一份 72 KB 的决策记录主张「以构造来强制」,而不是靠评审。落到实处的是一组托管钩子:十一个注册钩子,其中包括一个 53 KB 的秘密读取守卫,它硬拦 Read、Grep 和 Bash 去碰密钥文件,并取代了安装器原先写入的一条 deny 规则;还有提示注入守卫,以及扫描工具输出里被注入的指令、拒绝编辑本次会话还没读过的文件的守卫。真正到了用户手上的 bug 才是有教益的。一个纯装饰的状态栏每次渲染都去跑 git status,又没关掉 git 可选的索引锁,于是一个装饰品可能让别人的提交失败——修法是在两个读取接缝上设 GIT_OPTIONAL_LOCKS=0。命令模板把用户输入的参数塞进指令散文中间,于是一个 flag 被当成普通文本读掉、被忽略;同一段文本又被代进双引号的 shell 片段里,于是一个含命令替换的参数在用户自己的 shell 里跑了起来。与此同时,社区那一侧则在逐行读集成分支的源码:一位贡献者在相隔数秒内连开三个 bug——一处 include 在某个 runtime 上会被解析成散文、一份引导文档里的三个前提在别的 runtime 上不成立、以及一个能让命令直接崩掉的符号链接。

相关档案

全部档案 →