career-corpus-kit
CLAUDE.md4 starsChanged 2 months agoMITView on GitHub
A Claude Code plugin. .claude-plugin/plugin.json is the manifest; skills/ is discovered by convention. Change the kit from the kit repo, not from a corpus session. A session that has just hit a problem carries that problem in context, and everything it writes gets shaped by it — the incident's numbers become thresholds, the corpus's own vocabulary becomes kit vocabulary, and the narrative arrives as prose. All three read as method and none of it is. The test: a rule must…
The file
We split this CLAUDE.md into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 141
Commit without asking, but don't push.
- Distinctive: line 148
Before fixing a reported defect, reproduce its mechanism in a scratch case.
- Very specific: line 165
No bump for changes users never load: this file, CI, .gitignore, comments.
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
career-corpus-kit
A Claude Code plugin. .claude-plugin/plugin.json is the manifest; skills/ is
discovered by convention.
Where kit changes get made
Change the kit from the kit repo, not from a corpus session. A session that has just hit a problem carries that problem in context, and everything it writes gets shaped by it — the incident's numbers become thresholds, the corpus's own vocabulary becomes kit vocabulary, and the narrative arrives as prose. All three read as method and none of it is.
The test: a rule must be justifiable by reading the kit alone. If explaining why
it exists requires recounting what happened to one person, it is not method yet. It
may be a real defect — record it in BACKLOG.md, which is a defect tracker and can
hold evidence — but the rule waits for a separate pass, made here, on kit-internal
grounds.
This is the same split the skills' Lessons sections enforce: a lesson goes in the user's
private corpus/LESSONS.md, never in the kit, and never as an edit to a SKILL.md. The method
is public and stable; the scar tissue is private. evals/static_checks.py bans gendered singular pronouns in
skills/ because leaked incident prose almost always carries one.
Promote — moving a rule up from a live corpus
The method improves where it meets real material and breaks, which is inside somebody's private corpus. Moving what's learned there into the kit is the point; doing it without dragging the material along is the constraint. Call it promote, not sync: it is one-way, it is lossy, and most lessons should never make the trip.
Run it from here. The kit session reads the corpus; a corpus session never writes the kit. That direction is the whole safeguard — see the section above for what happens when it reverses.
The intake is three files, and nothing else:
| Read | Yields | Rate |
| the corpus's lesson log | dated, one-lesson-each entries — interview technique, attribution traps, how to ask | high; most entries generalise |
| the corpus repo's own instructions | rules about the repo and its artifacts — lifecycle, commits, manifests | medium, and these are the design ports |
| the corpus's work backlog | parked designs written up before they were built, often with their own known weaknesses | low volume, high value — port the design, not the parking |
Not story files, not applications/. Those hold the raw personal detail and a promote
pass has no use for it. Per-fact markers in a story file are calls about one person's career;
read them only if a whole class of them implies a mechanism the kit lacks. This matters more
than it looks: the commit stays clean either way, but whatever gets read enters the session
transcript. Scoping the read is the privacy control, not scoping the write.
Two gates, and a candidate needs both:
- Recurrence. One instance is an anecdote. Promote what recurred across different material — "third time now", "same family as" — because that is what will recur for a stranger.
- Generalisation. Two questions, at two stages. Of the entry: would this still be true for someone with a completely different career? Of the rule you'd write from it: the test above — justifiable by reading the kit alone.
Sorting entries against that first question gives three piles, and the middle one is the biggest:
- Port — the entry names a tell and a move: an observable signal in how someone talks, and a specific thing to do about it. That has nothing to do with whose corpus it is.
- Leave — the entry is calibration for one person: which numbers they round up, what their files are called, how often their corrections have proved right. That last shape is the trap, because the rule is portable while the evidence for it is private, and the kit would get the rule with no evidence at all.
- In between, and usually — a portable rule welded to the instance that proves it. Keep the opening claim and the move; bin the paragraph in the middle.
Pin a commit, not a date. Record the corpus sha you reviewed up to, and start the next
pass from git log -p <sha>..HEAD -- <intake paths>. A date can't be diffed and doesn't say
which of several same-day commits it means. A sha also catches the case a date scan misses
entirely: an amendment to an older entry, which never appears in a list of new entries and
usually means a rule got broader — which is exactly what porting wants.
Check the kit first, and check the clone rather than the cache. Much of the kit is already
there under different wording, and a corpus's notes about it go stale fast. Two copies carry a
version and they disagree — the development clone, and
~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/, which is what a running session
actually loads and which lags. The loaded copy governs a session; the clone is what gets
ported. Read the clone, or a rule already landed and unreleased looks like a gap.
Redact mechanically. Port the claim and the move. Cut the instance — company,
project, quoted speech, numbers. Keep the cross-references ("sibling to", "same family
as"); they carry nothing private and they are the structure of the method. If a rule
genuinely needs an example, write a fresh one or use the fictional corpus in examples/.
A lightly disguised instance is still a leak, and it reads as one to anyone who knows
the person. Before proposing: could a reader of this repo name the employer, the product,
or the person? Then it isn't redacted.
Propose before landing, with the diff, which skill file, why it generalises, and what
it replaces. Verification is the usual ./evals/run.sh, plus a grep of the diff for names
that shouldn't be in it.
Record what you declined and why, in PROMOTE.md, and advance the cursor sha there so
the next pass can scope its diff. Ported
rules need no record — they're in the skills. Declines do, and not only to save effort:
a rule rejected on purpose leaves no trace, so the next pass reads it again, sees the kit
disagreeing with the corpus, and quietly reverts a deliberate divergence.
Consolidate — when a rulebook grows
The skills grow the way scar tissue does: an incident earns a rule, the next incident
qualifies it, and the qualification lands beside the rule it qualifies rather than
inside it. That is how one principle ends up stated four times — and a model follows a
dozen sharp rules better than it follows twice that many hedged with counterweights and
exceptions. The corpus gets compact to fight this; the kit gets this section.
Patching a rule around its own text is a consolidation pass, not an append. When a change would add a qualification, a counterweight, or a second justification to a rule that already carries one, restate the rule so it covers the new case — in fewer words than the append would have cost. New rules and wording fixes are exempt; the trigger is a rule being amended for the second time.
A new hard rule arrives with a case that tempts its failure, or it replaces a rule.
evals/README.md sets the bar in its first paragraph: every hard rule exists to prevent one
specific failure, so the test is a case that tempts it. A rule that lands without one is
unfalsifiable from that day — nothing can later tell whether it changes behaviour or only
costs attention, and attention is what the rules compete for. So the commit that adds a rule
carries one of three things:
- a trip-wire case, proved able to fail the way Adding a case in
evals/README.mdsays; - the rule it replaces or absorbs, deleted in the same diff, so the count does not grow;
- a line under What isn't here yet in
evals/README.mdnaming the rule as uncovered — only when the failure is a judgement no regex can assert. That keeps the debt a list rather than a feeling, and it is the list a judge layer would start from.
A rule that can offer none of the three waits in BACKLOG.md. Rewording, moving and
consolidating existing rules are exempt: this gates the count, not the prose.
A new rule goes in at its right place in the order, and gets an id. The order is
priority, not history, so appending to the end is a decision about ranking made by
default. Nothing renumbers, because there are no numbers: rules are addressed by the
stable [LIKE-THIS] id after their heading, every rule carries one whether or not
anything cites it yet, and evals/static_checks.py fails an untagged rule and a
citation by number alike.
Working in this repo
- Commit without asking, but don't push. This repo is public, so ask before every push. A hook in
.claude/settings.jsonenforces this. - Stage files by name, never
git add -Aorgit add .. The root can hold untracked personal notes, and a file swept into a commit is published on the next push. - Kit changes often arrive as handoff docs written in a private corpus repo. Read them where they are and never write back to that repo. Each one ends with a "Not proposed" section: port the rule, drop the instance, and stay inside that fence.
- Before fixing a reported defect, reproduce its mechanism in a scratch case. A one-line summary is someone's conclusion, and a fix aimed at it can miss the real cause.
Versioning
Bump version in .claude-plugin/plugin.json on every user-visible change —
skill behaviour, prompts, templates, README instructions, install steps.
Why: installs are cached at ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/.
Users get new content on /plugin marketplace update regardless, since identity
tracks the commit sha. But version is the only signal they see in /plugin,
and an unchanged version overwrites the cache dir in place instead of creating a
new one. Silent updates look like nothing shipped.
Semver: patch for wording and fixes, minor for new skills or new behaviour, major for anything that breaks an existing corpus layout.
No bump for changes users never load: this file, CI, .gitignore, comments.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

