Skip to content

Move the local-environment section out of CLAUDE.md, which every bot stage loads on every turn - #651

Merged
johanzander merged 2 commits into
mainfrom
worktree-issue-650-trim-ci-preamble
Aug 18, 2026
Merged

Move the local-environment section out of CLAUDE.md, which every bot stage loads on every turn#651
johanzander merged 2 commits into
mainfrom
worktree-issue-650-trim-ci-preamble

Conversation

@johanzander

Copy link
Copy Markdown
Owner

Summary

  • CLAUDE.md 45,488 B → 11,926 B (−74%), by relocating one section to docs/agents/local-agent-environment.md
  • Nothing deleted or condensed — the content moves verbatim and is reached through the existing Agent Documentation Index
  • quality-check.sh gains a byte-budget gate so it cannot creep back inline
  • Five inbound references repointed

Root cause

Every bot stage loads CLAUDE.md before it does anything, on the main agent and again on its sub-agent, and re-sends it on every turn. 74% of it was one section describing this machine — the macOS sandbox knobs, podman, the permission deny/ask/allow rules, worktree layout, the Playwright install hang.

None of it can apply in CI. All five stages run on a fresh ubuntu-latest checkout under --permission-mode bypassPermissions: no prompt to avoid, no sandbox, no podman VM, no worktrees, no .venv symlinks. The git stash prohibition's own reasoning is "~20 worktrees share one refs/stash" — a runner has one checkout and no other agents. Grep confirms no workflow references it.

Stage 2's fixed floor, before it reads the issue, the bundle, or any source:

Loaded Bytes
CLAUDE.md 45,488
.claude/agents/bess-analyst.md 25,681
docs/agents/rules.md 10,548
inline prompt: 7,098
docs/agents/architecture.md 3,623
total 92,438

The relocated section was 36% of that, twice over (main agent + sub-agent), on every turn.

Fix

Move ## Worktree Conventions to docs/agents/local-agent-environment.md, linked from the Agent Documentation Index — the mechanism CLAUDE.md already uses for rules.md, architecture.md, patterns.md. The new file opens with a header saying what it covers and that it does not apply to the CI stages.

One wording change was forced by the move: the text said "CLAUDE.md itself teaches git -C .claude/worktrees/<name>", which stops being true once the text is the teacher. Now "this document itself". That is the only altered word; everything else is byte-identical.

Test plan

  • ./scripts/quality-check.sh — Errors: 0, Warnings: 0
  • .venv/bin/pytest -m slow — 554 passed, 8 skipped
  • Every link target resolves on disk; the heading worktree-setup.sh names ("Why each non-default knob is there") exists in the new doc
  • Rendered worktree-setup.sh's blocked-cache message and confirmed it now names the right file
  • bash -n on both edited scripts

Step 8's mock-HA E2E has no surface here — this change has no runtime behaviour. What was observed instead is the gate's RED→GREEN transition and the rendered script guidance.

Evidence the test discriminates

The gate was written before the move and watched fail:

  • Added CLAUDE_MD_MAX_BYTES=16000 to quality-check.sh while CLAUDE.md was still 45,488 B
  • Result: gate FAILED (45,488 > 16,000)
  • After the move: ✅ CLAUDE.md within context budget (11926 B / 16000 B)

Its failure message points at the relocate-and-link mechanism rather than at raising the cap — raising the cap is how this grew in the first place.

Outcome-level coverage

  • quality-check.sh's context-budget gate pins the byte size, which is the outcome this issue is about. No optimizer fixture or golden is involved — the diff touches no runtime code.
  • /code-review independently extracted the 574 removed lines and diffed them against the new doc: identical except the header and the one deliberate rewrite. It also confirmed the load-bearing prohibitions (never git stash, worktree-before-edit, the cross-checkout patch recipe) are independently stated in docs/agents/rules.md, the always-read file — so no safety content moved further from an agent that needs it.

Review findings fixed

/code-review found four dangling pointers, all fixed in this branch. Two only surface on a failure path, which is the worst place to send someone to a file that no longer has the answer:

Finding Note
worktree-setup.sh:261 prints on the way to exit 1 when a blocked cache stops setup
verify-sandbox.sh:111, :139, :141 assertion-failure messages
sweep-prs/SKILL.md ×2, skill-architecture.md markdown links
new doc untracked staged with git add -A

Documentation check

Neither docs/agents/bess-knowledge.md nor docs/SOFTWARE_DESIGN.md mentions anything this diff touches — no mechanism, formula, threshold or code path changed.

No CHANGELOG entry

Deliberate: zero user-visible effect, agent-facing documentation only. #649 changed the same pipeline and added none.

Scope assessment

Adds no parameter, flag, default-fallback, second construction site or extra trigger. Scope is local — the destination is the doc structure CLAUDE.md already establishes. Explicitly out of scope: deleting or condensing any relocated content, and dropping project from --setting-sources (it would cut more, but .claude/agents/bess-analyst.md is discovered through project settings, so it would break Stage 2's delegation).

Closes #650

Every bot stage loads CLAUDE.md before it does anything, on the main agent
and again on its sub-agent, and re-sends it on every turn. It was 45,488 B,
of which 33,743 B (74%) was one section describing this machine: the macOS
sandbox knobs, podman, the permission deny/ask/allow rules, worktree layout,
the Playwright install hang.

None of it can apply in CI. All five stages run on a fresh ubuntu-latest
checkout under `--permission-mode bypassPermissions`, so there is no prompt
to avoid, no sandbox, no podman VM, no worktrees and no .venv symlinks. The
`git stash` prohibition's own reasoning is "~20 worktrees share one
refs/stash"; a runner has one checkout and no other agents. No workflow
references the section.

Measured on Stage 2, whose floor before it reads the issue, the bundle or any
source was 92,438 B: CLAUDE.md 45,488 + bess-analyst.md 25,681 + rules.md
10,548 + the inline prompt 7,098 + architecture.md 3,623. The relocated
section alone was 36% of that, twice over, on every turn.

So it moves to docs/agents/local-agent-environment.md and is reached through
the Agent Documentation Index, which is the mechanism CLAUDE.md already uses
for rules.md, architecture.md, patterns.md and the rest. Nothing is deleted
or condensed -- the content is hard-won, much of it marked (measured), and it
is still required reading for autonomous local work. CLAUDE.md goes
45,488 B -> 11,926 B.

One wording change was forced by the move: the text said "CLAUDE.md itself
teaches `git -C .claude/worktrees/<name>`", which stops being true once the
text is the teacher. It now says "this document itself".

quality-check.sh gains a byte-budget gate so the section cannot creep back
inline, written RED first (45,488 B against a 16,000 B cap) and green after
at 11,926 B. Its failure message points at the relocate-and-link mechanism
rather than at raising the cap, because raising the cap is how this grew.

Five inbound references repointed, two of which only surface on a failure
path and would have sent the reader to a file that no longer had the answer:
worktree-setup.sh's blocked-cache diagnostic and verify-sandbox.sh's two
assertion messages, plus sweep-prs/SKILL.md and skill-architecture.md.

No CHANGELOG entry: zero user-visible effect, agent-facing documentation
only, matching #649 which changed the same pipeline and added none.

Closes #650
@bess-agent

Copy link
Copy Markdown
Collaborator

@claude-bot review

@bess-manager-claude-bot bess-manager-claude-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Root cause match: Yes. This closes #650 exactly — #650 measured CLAUDE.md at 45,488 B with ## Worktree Conventions (incl. Permissions/sandbox/podman/Playwright) accounting for 33,743 B (74%), loaded on every bot-stage turn on both the main and sub-agent. The PR relocates that section verbatim to docs/agents/local-agent-environment.md, reached through the existing Agent Documentation Index. Verified independently against the PR branch:

  • git show origin/worktree-issue-650-trim-ci-preamble:CLAUDE.md | wc -c11,926 B, matching the PR description exactly.
  • Diffed the removed CLAUDE.md section against the new file's content — byte-identical except the one deliberate rewrite ("CLAUDE.md itself teaches" → "this document itself teaches"), which is correctly forced by the relocation.
  • bash -n on all three touched scripts (quality-check.sh, verify-sandbox.sh, worktree-setup.sh) — no syntax errors.

Would the added test catch a regression? Yes. scripts/quality-check.sh's new CLAUDE_MD_MAX_BYTES=16000 gate (lines ~538–548 of the PR version) fails the build if the moved content creeps back inline, and the PR's RED→GREEN evidence (45,488 B failing against the cap, 11,926 B passing after the move) is a legitimate regression test for the stated problem — bot-stage context bloat.

Minimal / no scope creep? Yes. Every touched file is either the relocated content itself, the gate that pins it, or a reference that pointed at the moved section. No unrelated cleanup, no parameter/flag/fallback added — matches the PR's own scope-assessment statement (rules.md Debugging Protocol step 9 satisfied).

Architecture/style checklist: N/A for this diff — no Python/TS code, no sensor access, no new classes, no exception handling touched.

Finding (nit, not a blocker)

gh api is unavailable to me in this run, so posting this as a summary note per the review instructions rather than an inline comment.

  • .claude/skills/release/SKILL.md:29 — still reads:

    "e.g. it was cut fresh via git worktree add ... origin/main, per the Worktree Conventions in CLAUDE.md"

    This is a fifth dangling reference to "Worktree Conventions in CLAUDE.md" that the PR's cleanup sweep missed. CLAUDE.md no longer has a Worktree Conventions section at all after this PR (confirmed: grep -n "Worktree Conventions" CLAUDE.md on the PR branch returns nothing) — it moved entirely into docs/agents/local-agent-environment.md. The PR description says "/code-review found four dangling pointers, all fixed in this branch," and lists worktree-setup.sh, verify-sandbox.sh (×3), sweep-prs/SKILL.md (×2), and skill-architecture.mdrelease/SKILL.md isn't in that list and wasn't updated. Not a functional break (the release skill still works; the pointer is just stale), but worth a one-line follow-up fix: `CLAUDE.md``docs/agents/local-agent-environment.md` (or drop the CLAUDE.md citation entirely per the Agent Documentation Index pattern).

Everything else — the doc move, the byte-budget gate, the four other repointed references, the test plan evidence — checks out. Approving; the one stale reference above is small enough to fix in a follow-up rather than block this PR.

The Stage 4 review found one more dangling pointer the sweep missed:
release/SKILL.md:29 still cited "the Worktree Conventions in CLAUDE.md",
a section that no longer exists there.

The sweep missed it because the exclusion pattern was wrong, not because
the search was too narrow. It filtered `\.venv` to skip the vendored tree,
but grep -v applies to the whole line, and this line's TEXT contains
`.venv` ("If this branch/worktree has no `.venv` yet"), so a real hit was
dropped silently. Same shape as the earlier `head -20` truncation: a filter
that reads as coverage while removing results.

Re-swept with path exclusions anchored to path separators. Four references
to "Worktree Conventions" remain and all four resolve; every other file
citing CLAUDE.md points at a section still in it (Verification Before
Action, Cost Discipline, Release Workflow, General bot rules, the index).
@johanzander
johanzander marked this pull request as ready for review August 18, 2026 21:12
@johanzander
johanzander merged commit dd47d59 into main Aug 18, 2026
8 checks passed
@johanzander
johanzander deleted the worktree-issue-650-trim-ci-preamble branch August 18, 2026 21:19
johanzander added a commit that referenced this pull request Aug 18, 2026
main moved the local-environment section out of CLAUDE.md (#651), so the gh
scopeless-token note lands in docs/agents/local-agent-environment.md instead.

The backlog/board half of this branch is removed here, not lost: it is
preserved at eb4d00e and moves to its own PR, per the review's primary
blocker (undescribed, orthogonal changes making up over half the diff).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vHvj9qtD1jDYVnm3LjTnt
johanzander added a commit that referenced this pull request Aug 18, 2026
…655)

Stage 2's main agent listed `.claude/agents/bess-analyst.md` (25,681 B) as
REQUIRED READING item 3. That file IS the bess-analyst sub-agent's system
prompt -- frontmatter `name: bess-analyst`, `tools: Read, Grep, Glob, Bash,
WebFetch` -- so the main agent was loading a second copy of another agent's
instructions into its own context, on every turn.

Nothing consumed it. The six PROCESS steps are: get issue context, identify
the current problem, delegate, verify the cited file:line, publish, label.
No step applies a "domain expertise checklist". The one distinctive task,
step 4, needs the cited code -- not a triage procedure the main agent never
runs.

The content was in fact loaded three times. The section that could plausibly
serve as a judging standard, "Separate Evidence from Claims", is already
restated almost verbatim in the sub-agent task the same prompt passes:
hypothesis-not-diagnosis, triage-the-bundle-first, verify-the-code-path-
matches-this-user's-setup, intentional-design-is-not-a-bug. Sub-agent system
prompt, main-agent file read, and inline paraphrase.

All four landed Stage 2 analyses (#118, #252, #624, #627) use the workflow's
four headings, never bess-analyst.md's seven-item Output Format or its
six-item type-B shape -- the main agent follows the prompt, not the file.

So item 3 is removed, with an explicit note saying why, and step 4 gains the
check that was missing: a report fails verification if it claims a CODE bug
with no file:line, if a cited location does not say what is claimed, or if
it blends P-optimality / forecast error / control noise into one verdict
when actual behavior diverged from plan. Dead weight becomes an instruction
that fires.

Three things the first draft got wrong, found in review:

- "cites no file:line" alone would have rejected CORRECT diagnoses. The same
  prompt tells the analyst that unavailable sensors, wrong inverter type or
  an HA integration mismatch are likely the real cause, and those cite no
  code. Now qualified to code-bug claims only.
- The inconclusive path never removed `ready-for-analysis`, and
  backlog-digest.sh checks that label BEFORE `needs-human-review`, so the
  backlog pass reports the issue as un-analysed and re-dispatches analyze --
  re-billing the stage. Widening that path without fixing it would have made
  a cost bug worse. It now clears the label.
- The new criterion used vocabulary defined only in the file this diff stops
  the agent reading. P-optimality had a gloss; P≠R never expanded P or R and
  control noise had no definition. All three are now glossed inline.

quality-check.sh gains a context contract gate, written RED first: no
workflow may list a `.claude/agents/*.md` file as a numbered required read,
and Stage 2 must still delegate. Both assertions were mutation-tested --
removing the delegation reddens it, and reformatting `subagent_type` with
backticks or quotes does not, which the first bare-substring version got
wrong in both directions.

Saving is up to 25,681 B off the main agent per turn; the prompt itself grew
7,098 -> 7,821 B, so net is roughly -24.9 KB. "Up to", because whether a run
obeyed the read instruction is not observable -- #646 showed it need not.

No CHANGELOG entry: agent-facing, zero user-visible effect, as #649 and #651.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bot stages load 34 KB of local-machine context on every run, on every turn

2 participants