promote-learnings
Skill9 starsChanged 24 days agoMITView on GitHub
Reviews LEARNINGS.md's UNPROMOTED rows as a fresh, no-implementation-history reader and proposes where each durable one belongs. Report-only, except that in a consumer project it writes the proposals you confirm to PROMOTED.md. Run it by hand, in a fresh session, when the UNPROMOTED queue needs triage.
In this repository22 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- ai-auditSkill
- bulk-readSkill
- canon-slidesSkill
- captureSkill
- context-checkSkill
- context-doctorSkill
- dead-code-cleanupSkill
- doc-auditSkill
- learnings-sweepSkill
- mikadoSkill
- mutation-testSkill
- output-validatorSkill
- pr-reviewSkill
- repo-auditSkill
- repo-workflow-auditSkill
- sdlc-auditSkill
- skill-evalSkill
- skill-exportSkill
- sprintSkill
- wrapupSkill
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 1 is distinctive, and 10 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.
10
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 47
Read root LEARNINGS.md. For each row with Status: UNPROMOTED, read its linked .tickets/<id>/learnings.md in full (not just the one-line …
- Very specific: line 77
Choosing between them: ask "at what moment would a future session make this mistake?" and pick the narrowest home that is read at that …
- Very specific: line 86
Only bites at one workflow step or in one skill → that step's reference doc or SKILL.md.
- Very specific: line 89
Before proposing, grep the destination for the same rule and extend it instead of adding a second copy.
- Distinctive: line 92
Keep any always-loaded rule to one or two lines.
- Very specific: line 94
Never edit LEARNINGS.md, any file under standards/, critique/canon-learnings.md, CLAUDE.md, or AGENTS.md.
- Very specific: line 100
After presenting the report, ask the user which PROMOTED.md proposals to apply.
- Very specific: line 103
Entry form: Every PROMOTED.md entry is one trigger and one action, one or two lines, never the ticket's story (the ticket id already points …
- Very specific: line 117
Only after that write, flip the row's Status in LEARNINGS.md to ` promoted → PROMOTED.md .
- Very specific: line 172
If LEARNINGS.md has zero UNPROMOTED rows, say so plainly in the report — an empty queue is a valid, unremarkable result, not an error.
- Very specific: line 174
When recording or backfilling a promoted → <file> target, the lesson itself must appear in a real content line of that file.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill 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
Promote Learnings
Proposes first. In canon itself the actual write into critique/canon-learnings.md,
standards/, or (rarely) CLAUDE.md/AGENTS.md stays a separate, later, human-confirmed act. In a
consumer project the one exception is the Apply step below: it writes to PROMOTED.md only what
the user explicitly confirms, and only in an interactive session.
This skill exists because learnings-sweep (aggregation) and tkt learn (candidate generation)
explicitly refuse to make the promote/dismiss judgment call themselves — this is that judgment
call, made fresh, then handed back as a report, not an edit.
Distinct from learnings-sweep: that skill keeps LEARNINGS.md's index current and never reads
a candidate's full detail. This skill reads each UNPROMOTED row's source
.tickets/<id>/learnings.md in full and judges whether it's durable enough to promote.
Why this must run fresh, every time
The non-self-promote rule (learnings-sweep's own SKILL.md) exists because the sprint that
produced a learning has no perspective on whether it generalizes — everything looks load-bearing
to the agent that just lived through it. This skill must run with no memory of the sprint(s) that
produced the candidates it's reviewing. Start a fresh session for it — do not run it in the same
conversation that just closed the sprint(s) in question.
Canon or consumer
The destinations depend on which project the session is in:
- canon itself.
critique/canon-learnings.mdexists at the project root. Use the destinations in step 3 and leave every write to a human. - A consumer project (any other project that added canon's sprint skill). The destination is
PROMOTED.mdat the project root.skills.sh add sprintandrefreshseed it, and the project'sAGENTS.mdloads it every session with@PROMOTED.md. Rarely, when a lesson must override the defaults of every session, the destination is the project's ownAGENTS.md. Never propose or write anything under.claude/skills/,.agents/skills/, or outside the project root. Those paths resolve into canon's shared tree, so a write there would push one project's lesson into every project.
Process
- Read root
LEARNINGS.md. For each row withStatus: UNPROMOTED, read its linked.tickets/<id>/learnings.mdin full (not just the one-lineFindingcell — that's a terse distillation, the source file has the actual evaluator findings, reviewer findings and deviations). - For each row, judge: is this durable and general enough that a different future sprint would benefit from knowing it, or is it a one-off specific to that ticket's exact circumstances? A learning tied to one ticket's specific bug is not durable; a learning about a class of mistake (a testing anti-pattern, a doc-drift shape, a protocol gap) usually is.
For each durable row, propose exactly one destination. In a consumer project that destination is always
PROMOTED.md(or, rarely, the project's ownAGENTS.md). The options below apply to canon itself:standards/<file>.md— when the learning generalizes into a reusable rule (a checklist item, a naming convention, a "never do X, always do Y"). Propose the target file and a starting-point example of the rule text (not a final draft — a human still writes it).critique/canon-learnings.md— when the learning is better told as a narrative (a concrete incident, why the naive fix failed, what worked instead) — that file's own voice is essay-style, not a bullet list (see its existing entries for the register to match). Propose a suggested outline/key points to hit, not full prose — authoring that narrative needs a human's judgment on tone and framing.CLAUDE.md/AGENTS.md— rarely, only when the lesson must apply on every session regardless of what the session is doing (these are always-loaded, so cost is paid on every turn). Say explicitly why a narrower home (standards/ or a scoped reference) doesn't fit.- The reference doc for the workflow step where the mistake happens (e.g.
skills/sprint/reference/shared-gate-protocol.mdfor gate mechanics, the skill's ownSKILL.mdgotchas for a single-skill quirk) — when the lesson only matters at one step. Propose the file and the section. - A regression case in
skills/<name>/evals/evals.json— when the defect was traced to a skill's own instructions (the instruction let an agent do the wrong thing, e.g.t-b0e5's partial flip), not to one ticket's code. Propose the skill, the case'sprompt(the situation that produced the wrong behaviour) and theexpectationsthat would have failed. The next sprint that edits that skill then runs it (complete.md's advisory skill-eval step).
Choosing between them: ask "at what moment would a future session make this mistake?" and pick the narrowest home that is read at that moment (owner:
standards/skill-setup-std.md## Where a lesson goes).- Applies to every session whatever it is doing →
CLAUDE.md/AGENTS.md. - Needed in nearly every session, whatever the work →
standards/efficiency.md(always loaded in every project; keep it to one line). - A coding, testing, shell, security or platform rule that bites only in its domain →
standards/efficiency-notes.md, under that domain's section (on demand; efficiency.md's index line names each section, so a new domain also gets added there). - Only bites at one workflow step or in one skill → that step's reference doc or
SKILL.md. - Needs its incident to be understood (why the obvious fix failed) →
critique/. - A skill's own instruction caused it, and a prompt can reproduce it → that skill's
evals/evals.json. Before proposing, grep the destination for the same rule and extend it instead of adding a second copy. If the grep finds the rule already there, the row needs no write: propose it as`dismissed (covered: <file>)`, never as promoted. A row that spans two moments may be split into two proposals (ast-6328was). Keep any always-loaded rule to one or two lines; its cost is paid every session.
- For each non-durable row, recommend dismissal with a one-line reason.
- Never edit
LEARNINGS.md, any file understandards/,critique/canon-learnings.md,CLAUDE.md, orAGENTS.md. In canon this skill's report is its only output. In a consumer project, the Apply step below is the one exception.
Apply (consumer projects, interactive only)
After presenting the report, ask the user which PROMOTED.md proposals to apply. Skip this step
entirely in a headless run (claude -p), where the report is the only output.
Entry form. Every PROMOTED.md entry is one trigger and one action, one or two lines, never the
ticket's story (the ticket id already points to it), then the ticket id in brackets:
- When <situation>, <do this>. (<ticket-id>). One trigger per entry: a row with two lessons becomes
two entries. The report shows each proposed entry in this exact form, and Apply writes that text
unchanged for every proposal the user confirms.
Carry out every decision the user gives, the ticked proposals and any typed as free text (a dismissal, a reword, a split). A decision you cannot apply is named in the summary, never dropped. For each:
- Grep
PROMOTED.mdfor the same rule. If the rule is already there, write nothing: the row becomes`dismissed (covered: PROMOTED.md)`(step 3). Extend an existing entry only when the lesson adds a case to a related rule, and then the row ispromoted → PROMOTED.md. - Otherwise append the entry between
<!-- canon:promoted:BEGIN -->and<!-- canon:promoted:END -->. If the file is missing, runskills.sh refresh, which seeds it. - Only after that write, flip the row's
StatusinLEARNINGS.mdto`promoted → PROMOTED.md`. A dismissal becomesdismissed; a row whose rule already exists becomes`dismissed (covered: <file>)`(no write happened, so it is neverpromoted).
Then re-read LEARNINGS.md and PROMOTED.md and print one summary: N promoted, M dismissed, K still
waiting (their ticket ids, and why), and the managed block's line count against the 60-line cap.
PROMOTED.md is loaded on every session. When the managed block passes 60 lines, tell the user
to consolidate or retire entries. The cap is advisory and never blocks a write.
Report format
# Promote Learnings Report
## Reviewed
<N> UNPROMOTED rows read in full from their source .tickets/<id>/learnings.md files.
## Proposals
### <ticket-id>: <one-line summary of the learning>
- **Durable:** yes/no — <why>
- **Proposed destination:** standards/<file>.md | critique/canon-learnings.md | CLAUDE.md/AGENTS.md | <workflow reference doc>#<section> | dismiss | dismissed (covered: <file>)
- **Starting point:** <example rule text, or outline/key points, or the dismissal reason>
- **Entry (PROMOTED.md only):** the exact text Apply will write, `- When <situation>, <do this>. (<ticket-id>)`; one entry per trigger
<repeat per row>
## PROMOTED.md size
<Consumer project: the managed block's current lines plus the proposed entries as written = <N> of 60.>
## Next Steps
> In canon, this skill never writes these changes itself. (In a consumer project, confirmed
> `PROMOTED.md` proposals go through the Apply step instead, so this section is omitted there; in canon the
> report's `PROMOTED.md` lines read "not applicable".) Apply them by hand: edit the destination
> file below, bump that file's frontmatter `version` and set `updated` to today (if it has
> them), then flip each promoted row's Status in LEARNINGS.md away from UNPROMOTED. Record the
> target in the cell — `` `promoted → standards/efficiency.md` `` (whole value in backticks so
> editors highlight it; or `dismissed`) — so where a lesson went is readable from the row without
> git archaeology.
<Include the frontmatter bump ("bump `version` 1.0.5 → 1.0.6, `updated` → <today>") in each
destination's action. Concrete, per-proposal actions a human can take — e.g. "Add the following to
standards/efficiency.md: ..." or "Consider writing a critique/canon-learnings.md section
covering: ...". Never performed by this skill itself.>Gotchas
- A row this skill proposes for promotion is not confirmed — a human (or a later, separate,
non-builder pass) still decides. Do not mark a row promoted anywhere until the actual write has
happened. In canon that write happens outside this skill. In a consumer project the only write
this skill makes is the Apply step's confirmed
PROMOTED.mdentries. - If
LEARNINGS.mdhas zero UNPROMOTED rows, say so plainly in the report — an empty queue is a valid, unremarkable result, not an error. - When recording or backfilling a
promoted → <file>target, the lesson itself must appear in a real content line of that file. Read each grep hit: a ticket-ID match in a template or example row (e.g. the sample row inskills/learnings-sweep/SKILL.md) is not evidence. With no real hit, leave the row plainpromotedrather than guessing. - A row that carries more than one lesson flips only when every part has a real destination line or the
report explicitly dismissed it. Until then it stays
UNPROMOTEDwith a note naming the pending part (t-b0e5: four rows were flipped on one half and the other halves dropped out of review).
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.

