Skip to content

CLAUDE.md becomes a pointer to AGENTS.md — the inlined never-miss digest leaves; check-governed-prose reads the pointer form #17162

Description

@os-justin

Maintainer direct instruction to the skills seat (session session_01MoTv7pn338AZ71owsp19gQ, GitHub os-justin), given in that PM session's chat on 2026-09-09 at 13:3xZ and 13:4xZ, verbatim, untranslated:

「看一下 hotcrm 的agents.md 写的太乱了。只留下必要的。包括同时同时审核 hotcrm 的skills 任务,合并派发处理。」

「首先要明确 hotcrm 是元数据应用,平台功能应该在 objectstack中开发。 其次 claude.md 是不是直接让他阅读 agents.md 即可,没必要维护两套。所有仓库都有类似的问题」

Program anchor: #17161 (the shape, the four-axis note and the known cost are recorded there once).

This repo

CLAUDE.md (41 lines on origin/main) restates four prime directives with their hooks. After this card it says one thing: AGENTS.md is the source of truth, read it before anything else — and nothing more (no rule, no hook roster, no digest). The hooks in .claude/hooks/ keep enforcing worktree-first, the stash ban and the process-kill ban exactly as now; AGENTS.md already carries every rule the digest inlined (verify each of the four survives there by grep before deleting; a rule that does not survive is moved into AGENTS.md, not kept in CLAUDE.md).

scripts/pm/check-governed-prose.mjs counts CLAUDE.md as one of two instruction surfaces that must name all five governed surfaces; a pointer file cannot, so the gate adapts in the same PR — a CLAUDE.md that is a pure pointer to AGENTS.md satisfies the check through its target — with the self-test case that pins it and a red case for a CLAUDE.md that carries prose but no pointer. ⛔ Not a weakening: the enforcement moves to the one file that carries the enumeration.

Governed (CLAUDE.md, .claude/** untouched) ⇒ draft PR at the human terminal, skip-changeset. Serial: CLAUDE.md is free (no open PR touches it at filing).


Generated by Claude Code

Activity

  1. added theissue type on Sep 9, 2026
  2. added
    documentationImprovements or additions to documentation
    pm:queueReady for the PM dispatch loop
    domain:skillsDomain lane — seat card indexed by label:pm:seat
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 9, 2026
  3. self-assigned this
    on Sep 9, 2026
  4. os-justin commented on Sep 9, 2026

    @os-justin
    CollaboratorAuthor

    Claim: PM loop round 2 — CLAUDE.md becomes a pointer to AGENTS.md (nothing else in it); the four inlined never-miss rules leave (each verified surviving in AGENTS.md: worktree 19 hits, stash 8, kill 23, releases/ 2); scripts/pm/check-governed-prose.mjs adapts to the pointer form with a self-test pair (pointer satisfies through its target; prose without a pointer is red). Program: #17161; authority verbatim: 「首先要明确 hotcrm 是元数据应用,平台功能应该在 objectstack中开发。 其次 claude.md 是不是直接让他阅读 agents.md 即可,没必要维护两套。所有仓库都有类似的问题」
    Session: session_01MoTv7pn338AZ71owsp19gQ
    Branch: claude/issue-17162-claude-md-pointer
    Worktree: objectstack-issue-17162
    Domain: domain:skills
    File surface: CLAUDE.md + scripts/pm/check-governed-prose.mjs (its instruction-surface read and self-test); ⛔ no AGENTS.md edit unless a digest rule is measured missing there, ⛔ no .claude/hooks/** (stop on breach; explain in the report)
    Container & model: S–M (one governed file reduced to a pointer + one gate adaptation), mode:subagent, model: opus — --tier at 2026-09-09T13:51Z on origin/main for CLAUDE.md + scripts/pm/check-governed-prose.mjs: "no path-derived mandate: the surface hits none of the 3 declared glob(s) … floor sonnet · default opus · ceiling fable"; a ruled shape with a gate-judged acceptance ⇒ default-tier build, reviewed in the seat at claude-fable-5-1
    Clause-②: no
    Thread-read: none
    Serial constraints cleared: no open objectstack PR touches CLAUDE.md, AGENTS.md or check-governed-prose.mjs (20 open PRs' file lists read 2026-09-09T13:51Z); newest CLAUDE.md touch a814bdb8 (#16843); H17 index intersects neither path; no verify lock (no build). PR #17136 (SKILL.md) and PR #17138 (contract-review.md / director.md / check-half-states.mjs) are disjoint.


    Generated by Claude Code

  5. os-justin commented on Sep 9, 2026

    @os-justin
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 17162,
      "status": "done",
      "branch": "claude/issue-17162-claude-md-pointer",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/17168",
      "premise_still_valid": false,
      "summary": "CLAUDE.md is now a 5-line pointer at AGENTS.md and carries nothing else; the four inlined never-miss rules left the file, each verified surviving in AGENTS.md by its own sentence (claim-first AGENTS.md:393 'Claim the issue BEFORE you write any code.'; worktree-first AGENTS.md:217 Prime Directive 11 'Worktree-first — never edit on the shared main checkout.'; the stash ban AGENTS.md:318 'git stash is the sharpest thing the worktree does NOT isolate — never run a bare git stash push/pop.'; the kill-by-name ban AGENTS.md:528 'One process table per container: kill only a PID you recorded, never a name'; the releases ban AGENTS.md:679 Documentation Guardrails row 'content/docs/releases/ RELEASE-OWNED — Never edit in a code PR.'). Nothing had to be moved into AGENTS.md: all five sentences were already there and each is strictly longer than the digest's version, so AGENTS.md is not in the diff. .claude/hooks/** untouched. PREMISE FALSIFIED, ruling 4: scripts/pm/check-governed-prose.mjs does NOT read CLAUDE.md — its PROSE_SURFACES are AGENTS.md (Prime Directive 14) and .claude/skills/pm-dispatch/SKILL.md, and CLAUDE.md appears there only as a register ENTRY those two must name. Its verdict line is byte-identical before and after this PR. Three self-restoring ablation legs measured it: positive control (drop skills/** from the AGENTS.md PD14 region) exit 1 so the gate is live and CAN red; prose-only CLAUDE.md with no pointer exit 0 where the ruling predicted red; CLAUDE.md DELETED ENTIRELY exit 0, decisive because the gate reds on an unreadable input by design. Taking the ruling literally would also turn check:pm-dispatch-gates red: scripts/pm/dispatch-gates.mjs pins 'a one-root declaration does not reach the other root file' against exactly that gate reaching CLAUDE.md, with a comment saying to DELETE such a case rather than re-point it. So check-governed-prose.mjs is not in the diff and the ruling's intent holds unweakened — the five-surface enumeration stays enforced on the two files that carry it. The one gate that DID need this PR is the line ratchet: scripts/pm/check-skill-line-ratchet.mjs pinned CLAUDE.md at 41 with headroom 0; lowered 41 to 5, since 36 lines of slack on the file that existed to inline must-never-miss rules is exactly the budget a future digest re-accretes into. Assignee was already set by the PM dispatch (os-justin); I posted no claim and never wrote it.",
      "gates": "33 derived, 33 run, 0 NOT-MEASURED, 0 UNRUN, all exit 0 at final commit 41329812. Verdict: 'dispatch-gates --ran: 33 derived famil(ies) accounted for — 33 run, 0 NOT-MEASURED.' Named for this card: check:pm-governed-prose green BEFORE and AFTER with the identical line 'check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md) and claim no others.'; check:pm-governed-merges exit 0; check:nul-bytes exit 0; check:pm-skill-ratchet exit 0 with 'check-skill-line-ratchet: CLAUDE.md is 5 lines (ceiling 5; headroom 0).' check:pm-dispatch-gates run detached with its exit captured to a file and waited on in the foreground with tail --pid: exit 0, 'dispatch-gates self-test: 1624 cases pass.' Repo-wide pnpm lint (eslint . --no-inline-config) also run in full: exit 0, so no narrowing to declare. Governed terminal: node scripts/pm/check-governed-merges.mjs --test CLAUDE.md scripts/pm/check-skill-line-ratchet.mjs exits 3, 'GOVERNED — a human merge is the review record for this PR'. Draft PR, never flipped ready. skip-changeset applied by additive REST POST and read back: ['skip-changeset'].",
      "line_budget": "CLAUDE.md 41 -> 5 lines (net -36, a pure deletion; no re-wrap筹行, no content added). Ratchet ceiling for CLAUDE.md lowered 41 -> 5 (headroom 0, the map's own convention; a LOWERING needs no ruling). scripts/pm/check-skill-line-ratchet.mjs +9 comment lines recording the lowering and quoting the maintainer ruling. skills/** untouched, so the published-skill net-increase budget does not apply. Repo instruction-surface net: -36 lines.",
      "deviations": "1) ruling 4 NOT executed as written — check-governed-prose.mjs is not in the diff, because it provably does not read CLAUDE.md and editing it to would red check:pm-dispatch-gates. Measured, three ablation legs, all in the PR body. 2) scripts/pm/check-skill-line-ratchet.mjs edited, one path beyond the claim's declared file surface (CLAUDE.md + check-governed-prose.mjs). In-scope-by-consequence: it pins CLAUDE.md's line count, the fix is mechanical and its shape is pinned by every other entry in the map, no open PR touches it (checked: all 20 open objectstack PRs' file lists), and check:pm-skill-ratchet was already in the derived family list so it adds no verification surface. Named in the PR body with its before/after verdict lines. 3) origin/main advanced to f801e7d7 (#17142, scripts/pm/dispatch-gates.mjs) mid-run; the derivation tool reported it as a STALE TREE. Merged and re-derived on the current tool — the 33-command list is byte-identical to the pre-merge one. 4) The dispatch's lead was 34 commands including check:pm-governed-prose; re-derivation on the real diff gives 33 and drops that one. Ran it anyway, both before and after.",
      "files_changed": ["CLAUDE.md", "scripts/pm/check-skill-line-ratchet.mjs"],
      "tests": "No package tests are in scope: the diff is one root markdown file and one repo-tooling script, neither in any package. Gate evidence above. Ablation (three legs, one self-restoring script with trap RESTORE_FN EXIT INT TERM, absolute paths, restore by git checkout HEAD -- PATH, HEAD blob hashes captured non-empty first): LEG B positive control, drop `skills/**` from the AGENTS.md PD14 region, on-disk proof occurrences 2 -> 1, gate exit 1, 'AGENTS.md:255-289 … does not name `skills/**` — the register governs it and this prose under-claims'; LEG A1, CLAUDE.md replaced by prose with no pointer, on-disk proof 0 occurrences of the string AGENTS.md, gate exit 0 where the ruling predicted red; LEG A2, CLAUDE.md deleted entirely, on-disk proof file absent, gate exit 0 — decisive, since the gate treats an unreadable input as 'cannot read — Red, not a skip (#4690)'. Every leg restored and proven: git diff HEAD empty and the blob hash back to the HEAD blob after each. Final tree state 0 modified paths. No temporary test file left behind. Ablation legs ran on the COMMITTED tree (commit 898425ec) so the restore leg had a HEAD to point at.",
      "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST (probe returned HTTP 200 in this container); zero MCP GitHub calls for the whole run.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: eight script/agent comments cite CLAUDE.md as the place a rule is STATED — scripts/check-vendor-version-stamps.mjs:226 and :911, scripts/check-docs-single-h1.mjs:109 and :117, scripts/import-prerequisite.mjs:12 and :382, scripts/pm/ci-failure.mjs:215, .claude/agents/os-dev.md:35, .claude/workflows/docs-accuracy-audit.js:41. After this PR those rules are stated in AGENTS.md. Not a defect: CLAUDE.md still exists and points at AGENTS.md, so every citation still routes a reader to the rule — one hop longer, never a dead end, and no gate reads them. Who picks it up: the sibling sub-issues of #17161 do the same rewrite in objectui and cloud; whoever lands the last of them is the natural single pass to re-point these citations across all repos.",
        "noted, not filed: confirms an existing platform-readings reading rather than adding one — the raw REST PATCH on this PR's body appended a bare footer under the session-URL footer, leaving two, exactly as references/platform-readings.md line 318 records ('裸 REST PATCH /pulls 追加一个裸页脚并保留既有 session-URL 页脚'). Left as-is: AGENTS.md forbids re-sending a body that already carries an appended footer. The REST POST that CREATED the PR stored the session-URL block byte-identically (readback diff: trailing newline only)."
      ]
    }

    Generated by Claude Code

  6. os-justin commented on Sep 9, 2026

    @os-justin
    CollaboratorAuthor

    ACCEPT — #17162 (skills seat, session session_01MoTv7pn338AZ71owsp19gQ, review taken 14:25–14:30Z at claude-fable-5-1, comment posted 2026-09-09T14:28Z)

    PR #17168 (Fixes #17162, head 41329812 = a merge of origin/main f801e7d7 into the branch, base f801e7d7), draft, targets main, two files (+12/−40): CLAUDE.md 41 → 5 lines, scripts/pm/check-skill-line-ratchet.mjs (the CLAUDE.md ceiling 41 → 5 with a comment quoting the ruling). Verified against GitHub and the fetched head in this seat's own worktree, not the report (5603496981):

    • Path face: node scripts/pm/check-governed-merges.mjs --test CLAUDE.md scripts/pm/check-skill-line-ratchet.mjs — GOVERNED (CLAUDE.md) ⇒ draft at the human terminal; this seat does not flip, queue, arm or approve. git merge-tree --write-tree origin/main (70261410) × head: clean.
    • CLAUDE.md read on the head: a title and one bold two-sentence pointer — AGENTS.md is the single source of truth, read it in full before the first edit; one instruction set, no rule, hook roster or guardrail restated here and none added later. Nothing else. The maintainer's ruling is quoted verbatim at the head of the PR body and in the ratchet comment.
    • The five deleted rules each survive as their own sentence in AGENTS.md, read on the head by this seat: worktree-first at :217 (Prime Directive 11), the stash ban at :318, claim-first at :393, kill-only-a-recorded-PID at :528, the content/docs/releases/ ban at :679 — so AGENTS.md is correctly not in the diff. .claude/hooks/** untouched.
    • Premise falsified and accepted: my dispatch wrote 「check-governed-prose.mjs adapts to the pointer form」 as a ruling; that was a mechanism reading of mine and it was wrong — the gate's PROSE_SURFACES are AGENTS.md and SKILL.md, CLAUDE.md is only a register entry those two must name, and its verdict line is byte-identical before and after (re-run by this seat: 「2 instruction surface(s) name all 5 registered governed surfaces … and claim no others」). The dev's three ablation legs (positive control red; prose-only CLAUDE.md green; CLAUDE.md deleted green) settle it, and the dispatch-gates.mjs pin that forbids exactly that reach is the second reason not to edit the gate. Recorded as this seat's own error: a gate reading belongs in the mechanism-assumption zone, not the ruling zone.
    • In-scope-by-consequence edit accepted: the line ratchet pinned CLAUDE.md at 41 with headroom 0 and would have gone red on a 5-line file only in the raising direction — the ceiling is LOWERED to 5 (a lowering needs no ruling), re-pinned at headroom 0 so a digest cannot re-accrete silently; re-run by this seat on the head: check-skill-line-ratchet.mjs exit 0, 「CLAUDE.md is 5 lines (ceiling 5; headroom 0)」.
    • Gates from the report, spot-checked: 33 derived / 33 run / 0 NOT-MEASURED on 41329812 (the re-derivation drops check:pm-governed-prose because the real diff does not touch it; run anyway, green twice); check:pm-dispatch-gates 1624 cases (detached, tail --pid); repo-wide pnpm lint exit 0. CI on 41329812 at 14:27Z: 30 distinct checks, 19 success / 10 skipped / 1 in progress (Lint & Repo Gates) — honest in_progress, watched; the maintainer's merge waits on green regardless.
    • Closing keywords: Fixes #17162 is the first line; no other keyword-number pair. skip-changeset read back. Clause-②: no. Report 5603496981 first line os-dev-report, JSON parses. Two footers on the body — the documented bare-REST PATCH append (platform-readings :318), left as-is per AGENTS.md.
    • ## Acceptance notes read: eight script/agent comments cite CLAUDE.md as where a rule is stated (check-vendor-version-stamps.mjs :226/:911, check-docs-single-h1.mjs :109/:117, import-prerequisite.mjs :12/:382, pm/ci-failure.mjs :215, .claude/agents/os-dev.md :35, .claude/workflows/docs-accuracy-audit.js :41) — one hop longer, never a dead end, no gate reads them; carried to 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) #17161 for the last sibling to re-point in one pass. Not inside the three filing classes.

    Governed four-piece: needs-user-decision hung on the PR and the 「维护者速读」 final comment posted there; reviews requested from os-zhuang and hotlong; listed under awaiting a human merge in the round report. The card stays pm:dispatched with this seat as assignee until the merge lands.


    Generated by Claude Code

  7. os-justin commented on Sep 9, 2026

    @os-justin
    CollaboratorAuthor

    Landing record — PR #17168 (Fixes this card; sub-issue of program #17161) MERGED 2026-09-09T15:55:08Z through the merge queue, squash commit d18b7607 on origin/main (read at 2026-09-09T16:0xZ: CLAUDE.md is the 5-line pointer; the ratchet row reads ['CLAUDE.md', 5]). GOVERNED (CLAUDE.md): approved, flipped ready, auto-merge armed and enqueued by os-zhuang (review APPROVED 15:30:25Z, ready_for_review 15:30:29Z, auto_merge_enabled 15:30:54Z, added_to_merge_queue 15:33:27Z; merged_by os-zhuang) — this seat did none of them. In-seat review ACCEPT 5603535625. Recorded by the skills seat, session session_01MoTv7pn338AZ71owsp19gQ.

    Same stroke: pm:dispatched removed and the assignee (os-justin, this seat) cleared on this auto-closed card; domain:skills and documentation stay. The seat's own error recorded on this card stands as recorded (the dispatch order's 「ruling 4」 was a mechanism assumption, refuted by the dev with ablations; check-governed-prose.mjs was correctly left untouched).


    Generated by Claude Code

  8. removed their assignment
    on Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationdomain:skillsDomain lane — seat card indexed by label:pm:seat

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions