chore(docs): trim derivable content from CLAUDE.md and lazy-load the task-completion protocol #587
Closed
opened 2026-07-25 11:23:27 +02:00 by timothy
·
2 comments
No Branch/Tag Specified
main
renovate/lucene.net
renovate/dotnet-monorepo
renovate/sqlitepclraw.bundle_e_sqlite3-3.x
renovate/meziantou.analyzer-3.x
renovate/cliwrap-3.x
913-scripted-playout-401
release/v26.15.0-notes
issue-806-guard-populations
scratch/767b-poisoned
scratch/767b-control
release/v26.14.0-notes
release/v26.14.0
docs/510-skill-logo-bug-policy
fix/510-watermark-resolution-policy
fix/629-verdict-classifier-falseopens
fix/609-decisions-edit-token-scope
issue-135-clear-to-none
release/v26.12.0-notes
fix/409b-lastscan-api-parity
fix/401-updatechannel-mirror-422
fix/327-playlist-rename-validation
fix/410-scancancel-log-level
fix/409-447-librariesscreen-neverscanned
fix/338-zap-exit-code
fix/367-plex-budget-message
fix/310-debom-legacy-cs
ci/604-lane-rebalance
feat/388-design-mirror
feat/247-test-ownership
feat/247-primary-action
feat/357-player-owned-playback
feat/357-jellyfin-plugin-poc
fix/289-mcp-hardening
issue58-mcp
feat/244-channels-extract
ci/auto-bump-prod-compose
feat/multi-rerun-collections-api
feat/collections-api
feat/quick-wins
feat/185-docs-part2
feat/140-collections-screen
feat/146-channel-edit
feat/147-classic-ui-link
issue22-renovate-dashboard
feat/91-cutover
feat/63-composite-create
feat/65-library-browse
feat/85-epg
feat/86-schedule-editor
feat/109-dashboard-data
feat/99-session-tracking
fix/dockerfile-node-tag
feat/59-spa-foundation
docs/59-ui-redesign-brief
feat/102-json-guide
feat/111-schedule-durations
feat/104-artwork-upload
feat/103-media-sources-api
feat/playouts-read-api
feat/108-health-api
feat/105-picker-list-endpoints
issue-97-channel-state-api
issue42-jellyfin-musicvideos
issue46-rest-api-error-contract
dependabot/nuget/ErsatzTV.FFmpeg.Tests/multi-d307a2e06f
qsv-improvements
hdr-vulkan-cuda-test
v26.16.0
v26.15.0
v26.14.0
v26.13.0
v26.12.0
v26.11.0
v26.10.0
v26.9.0
v26.8.0
v26.7.0
blazor-final
v26.6.0
v26.5.0
v26.4.0
v26.3.1
v26.3.0
v26.2.0
v26.1.1
v26.1.0
v25.9.0
v25.8.0
v25.7.1
v25.7.0
v25.6.0
v25.5.0
v25.4.0
v25.3.1
v25.3.0
v25.2.0
v25.1.0
v0.8.8-beta
v0.8.7-beta
v0.8.6-beta
v0.8.5-beta
v0.8.4-beta
v0.8.3-beta
v0.8.2-beta
v0.8.1-beta
v0.8.0-beta
v0.7.9-beta
v0.7.8-beta
v0.7.7-beta
v0.7.6-beta
v0.7.5-beta
v0.7.4-beta
v0.7.3-beta
v0.7.2-beta
v0.7.1-beta
v0.7.0-beta
v0.6.9-beta
v0.6.8-beta
v0.6.7-beta
v0.6.6-beta
v0.6.5-beta
v0.6.4-beta
v0.6.3-beta
v0.6.2-beta
v0.6.1-beta
v0.6.0-beta
v0.5.8-beta
v0.5.7-beta
v0.5.6-beta
v0.5.5-beta
v0.5.4-beta
v0.5.3-beta
v0.5.2-beta
v0.5.1-beta
v0.5.0-beta
v0.4.5-alpha
v0.4.4-alpha
v0.4.3-alpha
v0.4.2-alpha
v0.4.1-alpha
v0.4.0-alpha
v0.3.8-alpha
v0.3.7-alpha
develop
v0.3.6-alpha
v0.3.5-alpha
v0.3.4-alpha
v0.3.3-alpha
v0.3.2-alpha
v0.3.1-alpha
v0.3.0-alpha
v0.2.5-alpha
v0.2.4-alpha
v0.2.3-alpha
v0.2.2-alpha
v0.2.1-alpha
v0.2.0-alpha
v0.1.5-alpha
v0.1.4-alpha
v0.1.3-alpha
v0.1.2-alpha
v0.1.1-alpha
v0.1.0-alpha
v0.0.62-alpha
v0.0.61-alpha
v0.0.60-alpha
v0.0.59-alpha
v0.0.58-alpha
v0.0.57-alpha
v0.0.56-alpha
v0.0.55-alpha
v0.0.54-alpha
v0.0.53-alpha
v0.0.52-alpha
v0.0.51-alpha
v0.0.50-alpha
v0.0.49-prealpha
v0.0.48-prealpha
v0.0.47-prealpha
v0.0.46-prealpha
v0.0.45-prealpha
v0.0.44-prealpha
v0.0.43-prealpha
v0.0.42-prealpha
v0.0.41-prealpha
v0.0.40-prealpha
v0.0.39-prealpha
v0.0.38-prealpha
v0.0.37-prealpha
v0.0.36-prealpha
v0.0.35-prealpha
v0.0.34-prealpha
v0.0.33-prealpha
v0.0.32-prealpha
v0.0.31-prealpha
v0.0.30-prealpha
v0.0.29-prealpha
v0.0.28-prealpha
v0.0.27-prealpha
v0.0.26-prealpha
v0.0.25-prealpha
v0.0.24-prealpha
v0.0.23-prealpha
v0.0.22-prealpha
v0.0.21-prealpha
v0.0.20-prealpha
v0.0.19-prealpha
v0.0.18-prealpha
v0.0.17-prealpha
v0.0.16-prealpha
v0.0.15-prealpha
v0.0.14-prealpha
v0.0.13-prealpha
v0.0.12-prealpha
v0.0.11-prealpha
v0.0.10-prealpha
v0.0.9-prealpha
v0.0.8-prealpha
v0.0.7-prealpha
v0.0.6-prealpha
v0.0.5-prealpha
v0.0.4-prealpha
v0.0.3-prealpha
v0.0.2-prealpha
v0.0.1-prealpha
Labels
Clear labels
ad-hoc
api
bug
ci-cd
content
dependencies
enhancement
frontend
in-progress
jellyfin
parked
priority: high
priority: low
priority: medium
review
security
One-off / ad-hoc work not tracked by a dedicated issue
REST API / HTTP endpoints
Something isn't working
Build, test, deploy pipeline
Channel content / schedules / playlists
Dependency updates (Renovate)
New feature or improvement
ChicoryTV React SPA frontend
Claimed by an active session — do not pick up
Jellyfin tuner / IPTV integration
Excluded from automatic queue pickup; work only when explicitly selected
Adversarial review finding
Security / vulnerability fix
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: timothy/ersatztv#587
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Ad-hoc work from a session context/config checkup (
/doctor). Recorded after the fact; the change is onchore/claudemd-trim-lazy-skill.What and why
CLAUDE.mdis loaded into context at the start of every session, so anything in it that a session could reconstruct from the codebase is paid for on every turn. The checkup found ~2.5k chars of that, plus one task-specific workflow that only matters when an issue is being closed.Cut — derivable from the repo:
### Project Layouttable (whatlsshows; roles are evident from the project names)dotnet build/dotnet runinvocations (standard for the toolchain). The non-obviousdocker build -f docker/Dockerfile …line is kept.Directory.Packages.props)Migrated to lazy loading:
## Closing recordtemplate move to.claude/skills/closing-an-issue/SKILL.md. Only its one-line description stays resident; the body loads when the skill (or/done) is invoked.Deliberately kept in
CLAUDE.md: the whole## Done-when/ merge-consent block. It is safety-critical and describes hook behaviour (pretooluse-merge-consent.sh,prepush-donewhen.sh) that fires whether or not a skill happened to be loaded — exactly the kind of rule that must not move somewhere it might not be loaded when it matters. Also kept: the### Key Filespointers, the UI/Blazor-removal history,## Conventions, and## Project Boundaries.CLAUDE.md13,306 → 10,801 chars (~625 est. tokens saved per session).Scope note
The rest of the checkup touched only local, non-repo state and is out of scope for this issue: disabling two unused project MCP servers in the gitignored
.claude/settings.local.json, and a cleanup of this project's Claude memory directory (4 superseded memories deleted — including one that still documented promotion via the deadmedia-serversbumblebee stack — plus index compression, 17.5 KB → 11.5 KB).Done-when
Build & test (.NET)green on the PR — all 8 jobs green ate678e665; image push correctly skipped for a docs-only changeReview-verdict: MERGEABLE @ e678e665); the load-bearing check was reference integrity, since 7 places outsideCLAUDE.mdcite "CLAUDE.md → Task Completion Protocol" and the heading is retaineddocs-updatetable inCLAUDE.md→ Conventions (no convention, route,/api/*endpoint, or decision changed)Drive-by from a parallel session (#436/#440/#583/#592): the H12 qualification audit flagged this as the only OPEN issue with no
priority:label, so I addedpriority: lowperprocess.issue-qualification-audit— an unlabeled issue is invisible toscripts/select-queue.sh.Not claiming or touching the work: it reads as in-flight (change already on
chore/claudemd-trim-lazy-skill), and the tier is a queue-visibility fix, not a judgment on the change. Relabel freely iflowis wrong.One thing worth knowing, since your trim landed in
CLAUDE.mdwhile I was mid-session: I picked up the newclosing-an-issueskill and used it for four closing records today, and the lazy-load worked exactly as intended — the resident one-line description was enough to know to invoke it. The kept-resident decision on the## Done-when/ merge-consent block also proved correct in practice: the H6/H10 gate auto-granted four merges from derived state today, and that only works because the convention is loaded before any skill is.Closing record
Outcome: Merged as #588 (merge commit
0952078c, branch deleted).CLAUDE.md13,306 → 10,801 chars; the 7 completion steps and the## Closing recordtemplate now live in.claude/skills/closing-an-issue/SKILL.md, loaded on invocation instead of on every session start. ~625 est. tokens off each session's resident context.Root cause: Not a bug fix, but the accumulation has an explanation worth recording:
CLAUDE.mdgrew by addition across many sessions with nothing ever pruning it, and no step in the workflow asks "could a session derive this from the repo?" The docs-update table enforces adding documentation when a convention changes; there is no corresponding pressure to remove content that the codebase already teaches.Decisions/conventions changed: None. No
docs/decisions.mdkey added or superseded — this only relocates existing guidance, and the## Task Completion Protocolheading is retained so every external cross-reference still resolves.Reusable knowledge: When trimming or relocating
CLAUDE.mdsections, the load-bearing check is reference integrity, not word count: seven places outside the file (docs/README.md,docs/decisions/release-ci-governance.md×3, two handoff docs, and theaskmessage inside.claude/hooks/pretooluse-merge-consent.sh) cite "CLAUDE.md → Task Completion Protocol" by section name. Keeping the heading while moving its body preserves all of them; deleting the heading would have silently broken a hook's own guidance text. Grep for the section name acrossdocs/,scripts/,.gitea/,.claude/and.husky/before removing anyCLAUDE.mdheading. The complementary rule: never migrate a rule whose enforcement is a hook — the## Done-when/ H6 / H10 block must stay resident because the hook fires whether or not a skill was loaded.Verification: All 8 CI jobs green at
e678e665(Build & test (.NET), EF migration integrity, functional E2E, API-docs-in-sync, formatting, and the three PR Gates); image push correctly skipped as docs-only. Cold review of the full diff posted at pulls/588#issuecomment-15884 withReview-verdict: MERGEABLE @ e678e665. Post-merge,origin/main'sCLAUDE.mdwas confirmed byte-identical to the reviewed version.Deferred: None for this issue. Noted but out of scope:
docs/decisions.mdand two handoff docs mention the## Closing recordtemplate, which now lives in the skill — the retained pointer line and the skill's description keep it findable, so no doc edit was warranted.Docs updated: None required. Checked against the docs-update table in
CLAUDE.md→ Conventions: no route migrated, added or redirected; no/api/*endpoint changed; no SPA screen convention touched; no decision established or reversed. TheDocs update reminderCI gate passed.Out-of-repo changes from the same session (recorded here for traceability; nothing to merge): two unused project MCP servers (
nuget,docker-mcp— zero calls across 400 sessions) disabled in the gitignored.claude/settings.local.json, and a cleanup of this project's Claude memory directory — 4 superseded memories deleted, 11 cross-links repaired, 4 truncated descriptions rewritten, index compressed 17.5 KB → 11.5 KB. The most useful deletion was a memory that still documented prod promotion via the deadmedia-serversbumblebee stack, which would have misdirected a future session now that prod runs on jazz.