Skip to content

docs: CLAUDE.md is a pointer to AGENTS.md - #283

Draft
os-litant wants to merge 1 commit into
mainfrom
claude/issue-17164-claude-md-pointer
Draft

docs: CLAUDE.md is a pointer to AGENTS.md#283
os-litant wants to merge 1 commit into
mainfrom
claude/issue-17164-claude-md-pointer

Conversation

@os-litant

@os-litant os-litant commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Fixes objectstack-ai/objectstack#17164

Program: objectstack-ai/objectstack#17161CLAUDE.md becomes a pointer to AGENTS.md in every repository, so there is one instruction set per repo, maintained once. objectos is the fourth of five repos; objectstack, hotcrm and objectui have landed.

What this adds

objectos had no CLAUDE.md at all, so Claude Code loaded no instructions until a reader found AGENTS.md unaided. This adds the pointer in the program's fixed shape: it says where the truth lives and that the reader must read it, and carries no rule, no hook roster and no digest.

CLAUDE.md, verbatim and complete — 5 lines:

# CLAUDE.md

**[AGENTS.md](./AGENTS.md) is the source of truth for working in this repository — read it in full before your first edit.**

One instruction set for every agent, maintained in one place: ⛔ no rule is restated here, and none is added here later.

The second sentence is kept rather than dropped to objectui's three-line shape because AGENTS.md:3 already addresses every agent by name — "Guidance for AI agents (Claude Code, Codex, Cursor, etc.) working in this repository". A file that did not exist until this PR is exactly where a future session would start appending Claude-specific rules, and one line closes that. Wording follows AGENTS.md's own voice: "this repository", and ⛔ as it uses it.

Measurements

Both re-verified in the worktree at this branch's tip. Neither is carried from the dispatch.

1. There was no prior CLAUDE.md

At the branch point 6505ac10, no CLAUDE.md existed anywhere in the tracked tree — not at the root, not in a subdirectory:

$ ls CLAUDE.md
ls: cannot access 'CLAUDE.md': No such file or directory
$ git ls-files | grep -i 'claude\.md'
(no output)

So there was no pair to reduce and nothing to delete: the deliverable is the pointer's creation. AGENTS.md is 140 lines and is the repo's only instruction file. A .claude/ directory does exist, holding launch.json only — a run-configuration file, not instructions.

After this PR: CLAUDE.md is 5 lines, AGENTS.md is unchanged at 140 lines.

2. Nothing reads CLAUDE.md, so no gate adapts

The program rule is that a gate reading CLAUDE.md as an instruction surface adapts to the pointer form in the same PR. No such gate exists here, measured two ways.

Narrow population, the dispatch's own: every tracked *.md, *.yml, *.yaml, *.mjs, *.js, *.ts, *.tsx, *.json, node_modules excluded — zero files name CLAUDE.md. Broad population, every tracked file at any extension, case-insensitive on claude — the only hits are prose about "Claude Code", claude.ai links in docs content, and the .claude/ directory path. Not one names the filename CLAUDE.md.

Positive control, same command, same population, AGENTS.md instead: 30 tracked files name it, AGENTS.md itself among them. The grep can find an instruction filename when one is referenced; it found no reference to this one.

At this branch's tip the reader-grep hits exactly one file — CLAUDE.md, matching its own heading. Still zero readers.

3. The new file is in no build input — measured, not read off the config

turbo.json declares build.inputs as ["$TURBO_DEFAULT$", "$TURBO_ROOT$/content/docs/**"], and AGENTS.md warns in its own words that a wrong inputs glob is not an error — "turbo exits 0, matches nothing". So the claim was measured rather than inferred, with the file present and then removed:

turbo task hash with CLAUDE.md hash without it
build 1d6009513037543d 1d6009513037543d
type-check 59aafae9a3d555c8 59aafae9a3d555c8

Identical. A hash that never moves is indistinguishable from a probe that cannot move, so the control AGENTS.md prescribes was run too — mutate a real input, then revert:

leg build type-check
baseline 1d6009513037543d 59aafae9a3d555c8
content/docs/build/agents.mdx mutated feff3b9d25464029 d19d1f1257870c1b
restored 1d6009513037543d 59aafae9a3d555c8

The probe moves on a real input and comes back, so the unchanged reading above is a measurement. Both mutation legs restored via git checkout HEAD -- path, proven by the restored blob matching the HEAD blob and by git diff HEAD being empty; no probe file is left behind.

Consequence: the docs site this PR builds is byte-identical in inputs to what main builds, and every gate downstream of the build reads the same artifacts it reads on main.

What CI runs on this PR

ci.yml declares no paths: filter, so both its PR jobs run on a root-level .md addition. translations.yml does filter — content/docs/**, apps/docs/lib/i18n.ts, .github/scripts/**, .github/workflows/translations.yml — and a root CLAUDE.md matches none of them, so the Translations workflow is not triggered at all. Independently of the trigger, check-translation-ownership.mjs:53 scopes its population to paths that startsWith('content/docs/') and carry a locale suffix, which this file does not. deploy-docs is push to main only.

Every step of both PR jobs was run in the worktree at this tip, except the one with no local equivalent:

job / step exit
node-floor / Self-test 0 — 17 rule, 24 satisfies, 18 range cases; every rule shown able to fail
node-floor / Check 0 — four declarations agree, floor 22.12.0 clears the tree's 22.0.0
build / pnpm install --frozen-lockfile 0
build / Half-state sweeper self-test 0 — 1551 cases
build / Generated zh-Hant is current 0 — 73 generated files match byte for byte
build / turbo run type-check --continue 0
build / turbo run build 0 — 56.3s
build / Locale surface 0 — 409 sitemap URLs, 0 findings
build / turbo run test 0 — 7 self-tests
build / Package the Worker (--skipNextBuild) 0
build / Worker bundle fits the size budget 0 — 58544.29 KiB against a 61440 KiB budget and a 65536 KiB limit
build / smoke-check a local preview 0 — replicated; /docs, /zh-Hans/docs, /llms.txt, /sitemap.xml answered 200, / 307
build / Upload the Worker bundle NOT RUN — an actions/upload-artifact step with no local equivalent; left to CI

Observed on this PR after the push: the head carries exactly two check runs — Node floor (completed, success) and build (in progress at the time of writing). No Translations check appears, which confirms the path-filter reading above from the platform rather than from the file.

No changeset: objectos has no .changeset/ directory and no changeset tooling, so neither a changeset nor a skip-changeset label exists in this repo to add.

Acceptance notes

Noted, not filed — an observation, not a defect:

  • ci.yml carries no paths: filter, so a root-level documentation-only PR pays the full build job: install, Next build, Worker packaging, dry-run weigh-in and a preview boot. The measurement above shows the turbo hash does not move for such a change, so the compile itself is cache-eligible, but the packaging, weigh-in and preview steps are not turbo tasks and re-run unconditionally. This is a runner-cost observation with no correctness consequence, and the absence of filters is also what guarantees no docs change slips past the build — worth weighing rather than reflexively fixing. Reader who meets it: whoever next edits objectos .github/workflows/ci.yml.

维护者速读(草稿)

改了什么 — 给 objectos 仓库根新增一个 5 行的 CLAUDE.md,内容只有一句话:真正的规则在 AGENTS.md,请先读完它。没有删除、修改任何现有文件,AGENTS.md 一个字节没动。

为什么改 — 你 09-09 的指示:「claude.md 是不是直接让他阅读 agents.md 即可,没必要维护两套。所有仓库都有类似的问题」。objectos 的情况和其他仓库相反:它压根没有 CLAUDE.md,而 Claude Code 只自动加载 CLAUDE.md。也就是说,在这个仓库里开一个 session,agent 默认读不到任何规则——140 行的 AGENTS.md 全靠它自己碰巧发现。这个指针把这条路补上,同时从第一天就把「只维护一套」写进文件里,免得以后有人往这里加规则。这是五个仓库计划里的第四个,前三个(objectstack、hotcrm、objectui)已合并。

风险与代价(含回滚) — 风险接近于零:新增文件,无删除,仓库里没有任何脚本或 workflow 读 CLAUDE.md(已实测,并带正向对照)。已实测该文件不进入任何 turbo 构建输入,构建产物与 main 完全一致。已在本地跑完 CI 两个 PR job 的每一个步骤(唯一没跑的是 CI 专属的产物上传),全部退出 0。已知的代价写在计划卡上,不是本 PR 引入的:session 若跳过这个指针,在 hook 触发前就没有规则可依——hook 是这个方案的地板。回滚 = 删掉这一个文件,git revert 一次即可,没有任何东西依赖它。

席位意见 — (留空,待席位定稿)

你要做的 — 一个动作:人工合并本 draft PR。


Generated by Claude Code

objectos had no CLAUDE.md, so Claude Code loaded no instructions at all
until a reader found AGENTS.md on their own. Add the pointer in the shape
the program fixes: it says where the truth lives and that the reader must
read it, and carries no rule, no hook roster and no digest of its own.

Nothing in the repository reads CLAUDE.md, so no gate adapts. AGENTS.md
already addresses every agent ("Claude Code, Codex, Cursor, etc."), which
is why the pointer keeps one instruction set rather than opening a second.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YKEjmbYNvYWJvWGSWx26zK

Copy link
Copy Markdown
Collaborator Author

维护者速读

改了什么 —— objectos 仓库根新增一个 5 行的 CLAUDE.md:标题、一句加粗的指针(规则在 AGENTS.md,先读完再动手)、一句「一套指令只维护一处,这里不复述也不新增规则」。只加这一个文件;AGENTS.md(140 行)一个字节没动。

为什么改 —— 你 09-09 的指示「claude.md 是不是直接让他阅读 agents.md 即可,没必要维护两套。所有仓库都有类似的问题」,五仓计划(objectstack#17161)的第四仓。objectos 与其它仓相反:它原本根本没有 CLAUDE.md,而 Claude Code 只自动加载 CLAUDE.md,所以在这个仓开 session 的 agent 默认读不到任何规则。指针补上这条路,并从第一天起把「只维护一套」写在文件里。

风险与代价(含回滚) —— 接近零:纯新增;仓内没有任何脚本或 workflow 读 CLAUDE.md(dev 实测,带 AGENTS.md 正向对照 30 个文件);turbo 构建输入的 hash 在文件存在/删除两态相同,且对照 mutation 能让 hash 移动;CI 两个 PR job 在 head f5a7cfa6 上全绿(build、Node floor 成功,Deploy docs 跳过)。已知代价在计划卡上:session 若跳过指针,在 hook 触发前无规则可依,hook 是地板。回滚 = 删这一个文件,一次 revert。

席位意见 —— 通过。本席对照 diff 自读:5 行,形状与 objectstack/objectui 已落地的指针同构,措辞用 AGENTS.md 自己的口吻(this repository、⛔);保留第二句的理由成立(AGENTS.md:3 已点名 Claude Code/Codex/Cursor,这个新文件正是日后有人往里塞 Claude 专属规则的地方)。无 changeset 工具、无标签门,不欠任何东西。受管面:本席不翻 ready、不入队、不批准。

你要做的 —— 一个动作:人工合并本 draft PR。

skills 席,session session_01YKEjmbYNvYWJvWGSWx26zK,2026-09-10T09:29Z。


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[objectos] CLAUDE.md becomes a pointer to AGENTS.md — measure the pair first, then reduce to the pointer

2 participants