- enter_project carries a `family` key, but only when the project has something to answer: counts of unassessed, owed and to-recheck answers, each with the list_family_adoptions call that lists it. It shows on every entry, never by platform touch: entry is when work is chosen, and an unanswered idea is otherwise invisible. - Retrieval: a widened project search (include_global_kinds) now also reaches the canon ideas on the project's platforms. It also reaches their references in the project's languages, or all of them when none matches. An off-platform project gets none, and the plain project filter (the duplicate gate) is unchanged. - Closing a task returns `family_owed`, the owed answers filed while it was open, and the report cue asks for them to be named. - New plugin skill family-canon (moment work.record) covers when to evaluate a promotion, answering in order, what counts as a reason, the precedent reflex and the conflict order. _INSTRUCTIONS, create_note, create_snippet, classify_shapes and reporting-back point at it. The plugin version is minted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.9 KiB
name, description, metadata
| name | description | metadata | ||
|---|---|---|---|---|
| family-canon | Use when family canon reaches the session — a `family_hint` on a create (a record may be a pattern every project on a platform will need), a `family` key from enter_project (ideas this project has not answered, owes, or must recheck), a `family_owed` list when a task closes, or the operator asks whether a pattern is shared between projects. Triggers on "family", "shared between projects", "promote", "canon idea", "owed", "adopt", "every Android app", "every project on". |
|
Family canon — good ideas spread by criteria, not by approval
Some patterns are not one app's: every project on a platform meets the same problem (an Android app that ships its own APK, a Go service behind a reverse proxy). Family canon is how such an idea is recorded once, reaches every project on that platform, and gets an answer from each. Nobody approves anything. You decide, against written criteria, and the decision log keeps you consistent with the last decision like it. The tools quote the criteria, the outcomes and the conflict order in full; this skill is when to reach for them and what a good answer looks like.
The shape is the point, not identical code: the same idea in Kotlin and in Go is one idea with two reference implementations.
When an idea is evaluated for promotion
A family_hint on a create_note / create_snippet response means a trigger
opened an evaluation: the record cites another project's record as its
source, or it repeats a record in a project on a shared platform. The source
is now a candidate. Evaluate it in the same turn, while you know why you
wrote what you wrote:
get_family_idea(id)— the candidate, its decisions, and the precedents (decisions on the ideas nearest it).- Judge the three criteria from
promote_family_idea's description. Each needs support you can name; one criterion with no support vetoes it. - Promote it, or leave it a candidate with the reason. A held candidate is precedent too, so the reason is the record — never skip writing it.
A milestone closing on a platform project hints without recording anything: ask whether what it built is something every project on the platform will face, and if so write the note that carries the idea.
Answering an idea in a project
enter_project's family key counts what this project owes the family:
unassessed, owed, needs_recheck, each with the call that lists them.
Answer an idea when your work reaches its area, not as a chore list at
session start — the count is there so it is never invisible, not so it
preempts the operator's task.
get_family_adoption(project_id, idea_id)first: the idea, the project's current answer, the precedents, and the reference implementations with the project's languages.- Judge the outcomes in the order
assess_family_adoptionlists them, stopping at the first that holds. Every outcome needs a reason;adoptedneeds evidence naming where. - When the code is in the shape ledger, answer there instead:
classify_shapesthe shape withidea_id=as aninstanceor avariant, and the adoption answer moves with it. An answer the shapes contradict is refused — fix the shapes, not the answer. owedfiles a task in THAT project and stops. Nothing here edits another repository; the project's own session picks the task up.
What counts as a reason
A reason names a fact about this project: "the app is installed by a
managed store, never sideloaded", "the service has no user accounts". A
preference, a taste, or "we already did it another way" is not a reason —
that is owed, or, if this project's way is better rather than different, a
conflict. Write the reason so a session in another project can tell whether
the same fact holds there; that is how it becomes precedent.
The precedent reflex
Before answering, read what was answered before: the same idea in other projects, and this project's answers to the nearest ideas. Answer consistently unless this project differs in a way you can name — and then the difference IS the reason. The engine records the precedents it found whether or not you cite them, so an inconsistent answer is visible later.
When two projects disagree
Two projects solving one idea differently, each sure of its way, is a
conflict — settle it with resolve_family_conflict, which states the order.
The first ground that applies wins, and every ground above it must be said
not to apply — you cannot skip to the one you like. The losing side's
reasoning is folded into the idea's note (as a trap, an alternative, or the
branch for its condition) and never dropped; the version moves, so every
other project's answer reads as needing a recheck.
Reporting it
A family_owed list on a closing task is work you filed into other projects
while it was open: name each one in the report, by project and idea — it is
waiting there now.