docs: reduce CLAUDE.md to a pointer at AGENTS.md (objectui#8840) - #8848
docs: reduce CLAUDE.md to a pointer at AGENTS.md (objectui#8840)#8848os-justin wants to merge 1 commit into
Conversation
CLAUDE.md restated worktree-first and the stash ban with their hook roster. Both rules live in AGENTS.md 9. Operational Rules (paragraph 多 agent 协作纪律) and in .claude/hooks/, so the restatement was a second instruction set that can lag the first. It now says one thing: AGENTS.md is the source of truth, read it before your first edit. No gate required prose here: the shell-escape-residue row is a file-existence floor (0 fences before and after), check-doc-links only resolves the links the file carries, check-bash32-floor never reaches it, check-upstream-port-parity pins three ported files and CLAUDE.md is not among them, and check-governed-queue-guard still lists it as governed. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ
维护者速读 — objectui PR #8848(objectui#8840,skills 席终稿,2026-09-09T14:08Z)改了什么 — objectui 根 为什么改 — 同一套规程此前两份: 风险与代价(含回滚) — 已知代价:Claude Code 只自动加载 席位意见 — 接受。本席在分支头复核:diff +1/−23 一文件;两条被删规则各自的原句在 你要做的 — 看一眼那三行是否就是你要的形态;CI 全绿后人工合并,或由 os-zhuang / hotlong 批准后本席入队(受管面,席位不翻 ready、不入队、不挂 auto-merge)。 Generated by Claude Code |
Fixes #8840
Part of the program card objectstack-ai/objectstack#17161 — one
CLAUDE.mdshape per repo, landed one repo per sub-issue.Maintainer direct instruction (2026-09-09), 原文照录、不翻译:
What this does
CLAUDE.md: 25 lines to 3. It now carries exactly one proposition —AGENTS.mdis the source of truth, read it before your first edit. The two inlined rules (worktree-first, nevergit stash), their hook roster and the closing digest line leave the file..claude/hooks/**is untouched:guard-main-checkout.sh,guard-main-checkout-bash.shandguard-shared-stash.shkeep enforcing both rules exactly as before, and the hook self-test workflow is unchanged.Both deleted rules verified present in
AGENTS.mdbefore deletionGrep-verified in
AGENTS.md〈9. Operational Rules〉, paragraph 多 agent 协作纪律. Anchoring sentences, quoted (the worktree command example is elided at the ellipsis — it contains a placeholder in a shape GitHub's body sanitizer eats, see AGENTS.md 〈GitHub 会改写你写进 issue/PR 正文的字节〉):worktree-first —
AGENTS.md:249:never
git stash—AGENTS.md:250andAGENTS.md:258:Both rules, both hook names, both override variables and the self-test instruction survive there. One element does not, and it is not a rule: the name
guard-main-checkout-bash.shand the clause "the same writes as Bash".AGENTS.md:249namesguard-main-checkout.shonly and enumeratesEdit/Write/NotebookEdit. The rule it enforces survives in full and is stated there as 强制而非「首选」, independent of which tool performs the write; what is missing is one half of an enforcement roster, and ruling 1 removes the roster fromCLAUDE.mdin any case. Recorded under Acceptance notes rather than fixed here — this PR's declared file surface isCLAUDE.md, andAGENTS.mdis itself governed.Gates re-run — none required prose in
CLAUDE.mdMeasured, not assumed. Every exit code captured before any pipe.
check-governed-queue-guard.mjs --self-testOK check-governed-queue-guard self-test: 132 cases passcheck-governed-queue-guard.mjs --test CLAUDE.md⛔ GOVERNED — 1 of 1 path(s) are on a governed surface: CLAUDE.md x1 — the repo-root Claude instruction filecheck-doc-links.mjsLinks are valid across 17 scan roots.check-shell-escape-residue.mjsOK (5/5 root(s) resolved -- … CLAUDE.md: 1 file(s), 0 fence(s) …)check-bash32-floor.mjs13 tracked shell file(s) under scripts/**, .claude/hooks/**, e2e/** name no bash 4+ construct …check-upstream-port-parity.mjs3 ported file(s) match objectstack-ai/objectstack modulo their declared divergencescheck-control-bytes.mjsOK (scanned 7041 tracked text file(s); skipped 85 binary)check-changeset-presence.mjsNo source or published contract of a released package changed in this range, so no changeset is owed.What each one actually wants of this file:
check-governed-queue-guard.mjs— registersCLAUDE.mdas a governed surface ({ id: 'claude-md', exact: 'CLAUDE.md', … },check-governed-queue-guard.mjs:232). Unchanged, and it still answers GOVERNED for this diff. That is the ruling's requirement that it keep doing so, met.check-doc-links.mjs— the row is{ path: 'CLAUDE.md', rule: 'disk' }(:696): it resolves the links the file carries. The pointer carries exactly one,./AGENTS.md, and it resolves.check-shell-escape-residue.mjs— the row is{ spec: 'CLAUDE.md', kind: 'file', minFiles: 1 }(:260): a file-existence floor, not a prose requirement. Fence count is 0 after — and was already 0 on the base commite9d92120(git show e9d92120:CLAUDE.md | grep -c '```'returns 0), so this gate's reading of the file is byte-for-byte the same verdict before and after.check-bash32-floor.mjs—POPULATION_ROOTS = ['scripts/**', '.claude/hooks/**', 'e2e/**'](:286).CLAUDE.mdappears in this file only inside a header comment describing a sibling gate's population (:52). This gate never opensCLAUDE.md.check-upstream-port-parity.mjs— see the falsified assumption below.check-changeset-presence.mjs— objectui has noskip-changesetlabel, and none was applied. This gate's own 「no changeset owed」 verdict is the declaration.⇒ No gate was adapted, because none required prose here. A pointer file has no fences, no shell, and one link that resolves — the expected reading, now measured.
PM mechanism assumption A: falsified
The dispatch asked whether
check-upstream-port-parity.mjspinsCLAUDE.mdparity with objectstack's copy, and whether the pointer form would then need pinning on both sides. It does not, and it would not:scripts/upstream-port-pin.json, and the ported set is exactly three files, printed by the gate itself:scripts/pm/check-half-states.mjs,scripts/invoked-as.mjs,.claude/hooks/guard-main-checkout.selftest.sh.CLAUDE.mdis not among them.CLAUDEhits in that ledger areCLAUDE_PROJECT_DIR(an environment variable inside the hook self-test matrix) and one prose comment — neither isCLAUDE.md.CLAUDE.mdoccurs in the gate script only at:120, in a header comment enumerating this repo's governed surfaces; the gate importsGOVERNED_SURFACESfromcheck-governed-queue-guard.mjsso that its--rewrite-governed-filepath refuses to rewrite a governed file. That is a refusal, not a parity pin.⇒ objectstack's parallel sub-issue and this one are independent on this axis; neither needs to pin the other's pointer wording.
Ablation — the file-existence floor is live, not a phantom check
Run from the committed state (
7dd3aaa1), one leg each, both proven on disk,trap … EXIT INT TERMarmed with an absolute path before the mutation:Direction predicted before running: turns red. Observed: red, naming the file. So the green above means "the declared root resolved and was scanned", not "nothing was looked at" — which is the whole question a pointer file raises for that gate. Restore verified by blob-hash equality against the
HEADblob and by an emptygit diff HEAD, not by an exit code. No test file was left behind.维护者速读(草稿)
改了什么 ——
CLAUDE.md从 25 行缩到 3 行,只剩一句话:AGENTS.md是唯一事实源,动手改任何文件之前先读它。原先内联的两条规则(一任务一 worktree、绝不git stash)连同它们的钩子清单一起删除。AGENTS.md、.claude/hooks/**、任何门禁脚本都没有改动。为什么改 —— 同一套规程此前维护两份:
AGENTS.md里的原文,和CLAUDE.md里的摘要。两份就会漂移,而漂移的方向是固定的 —— 摘要落后于原文,读摘要的 agent 拿到的是过期规程,并且看不出它过期。指针不会漂移:它不复述任何规则,所以没有任何东西可以过期。这也正是维护者裁定的那一句:「没必要维护两套」。风险与代价(含回滚) —— 已知代价,如实说明:Claude Code 只自动加载
CLAUDE.md,AGENTS.md要靠这条指针才被读到,所以一个跳过指针的会话在钩子响之前手上没有任何规则。兜底是钩子本身 ——guard-main-checkout.sh、guard-main-checkout-bash.sh、guard-shared-stash.sh三个 PreToolUse 钩子这次一个字都没动,写共享 checkout 和git stash照样在工具调用那一刻被拦下,不依赖任何人读过文档。回滚成本近似为零:单文件、单次提交(7dd3aaa1),git revert即可还原原文,没有任何生成物、锁文件或已发布内容随之变动。席位意见 ——
你要做的 —— 这是受管面(
CLAUDE.md在本仓五项受管面之列),PR 停在 draft 等你合并;你的那次合并动作本身就是审核记录。只需确认一件事:缩到这一句是否就是你要的形态。若认为该保留「钩子会兜底」这类提示,请直说,我把它写进AGENTS.md(而不是写回CLAUDE.md)。Acceptance notes
CLAUDE.mdis on this repo's five-item governed register. This PR stays a draft: not flipped ready, not enqueued, no auto-merge armed, no approving review submitted from this seat.AGENTS.md:249namesguard-main-checkout.shand enumeratesEdit/Write/NotebookEdit, but never namesguard-main-checkout-bash.sh, which guards the same writes performed through Bash. After this PR no document in the repo names that hook (.github/workflows/hook-selftests.ymlnames it in a comment, as a hook, not as coverage prose). The rule survives intact and is stated as mandatory regardless of tool, and the hook keeps firing, so this is an incomplete enforcement roster rather than a lost rule or a reproducible defect — outside all three filing classes. Carrier named: the program card [program] CLAUDE.md is a pointer to AGENTS.md in every repo — no second instruction set to maintain (maintainer 2026-09-09) objectstack#17161, whose sibling repos are reducing the same digests this week..github/workflows/hook-selftests.yml:8says the two guards stand behind "the rule bothCLAUDE.mdfiles state as binding … (see those files' '⛔' sections)". Those sections are gone from this one, and objectstack's sub-issue removes them from the other, so the citation goes stale on both sides in the same program. It is a comment in a workflow, reads nothing, and gates nothing; repairing it here would put a file outside this PR's declared surface into a governed-terminal PR. Same carrier: [program] CLAUDE.md is a pointer to AGENTS.md in every repo — no second instruction set to maintain (maintainer 2026-09-09) objectstack#17161.scripts/pm/. It does:scripts/pm/check-half-states.mjs, one file, the ported half-state patrol. The operative conclusion is unaffected — there is noscripts/pm/os-verify-lock.shin this repo, so no verify lock was owed, and this change is docs-only in any case.pnpm lint/pnpm testare CI's. No gate script was edited, so no gate's own suite is owed either. The fourscripts/__tests__/*files that mentionCLAUDE.mdbuild it as a fixture in a temp directory (FIXTURE_ROOTS), and none reads the real root file.Generated by Claude Code