Imported from mauriciobs666/graphmind-ai-lab (
skills/agent-maintenance/SKILL.md). Install upstream withnpx skills add mauriciobs666/graphmind-ai-lab --skill agent-maintenance. Copyright stays with the author.
Agent maintenance
The bookkeeping that keeps an agent collection healthy: every agent/skill you touch carries a living kaizen plan + history (agents additionally a learnings graph, §5), and stays documented for two audiences (humans and other agents). This skill holds the procedures and templates so the resident agent prompt stays lean — load it when you do any maintenance work, follow it, and mention at the end which kaizen/doc files you touched.
When this applies
- Creating an agent/skill → seed kaizen files, add catalog entries.
- Editing an agent/skill → advance kaizen, update its catalog entry.
- Renaming / removing → update or delete entries everywhere.
- Reviewing (no source change) → still record new improvement ideas in
plan.md. - Reconciling an already-drifted context doc → run the audit pass (§3).
- Certifying team coherence (rosters, handoff contracts, enforcement parity across the collection) → run the certification pass (§4).
- Distilling learnings graphs (on request, and folded into every certification pass) → run the distillation procedure (§5).
- Linting a single artifact's prompt quality (on authoring/review, and folded into §4) → run the prompt-quality lint (§7).
1. Kaizen — improvement plan & history
Every agent/skill you create or touch carries a forward-looking plan.md and a
dated history.md. Keep them as part of the work, not as an afterthought.
Where the files live
Locate the artifact's development directory — the folder its source lives in:
- Has its own folder (a skill's
<dir>/<name>/SKILL.md, or an agent in its own subdirectory like~/.claude/agents/<name>/<name>.md) → the development directory is that folder. - A lone file sharing a directory with sibling artifacts (e.g. flat OpenCode
.opencode/agents/<name>.md, or Kiro.kiro/steering/) → the development directory is that shared directory.
Place the kaizen files as:
- Own folder:
<folder>/kaizen/plan.mdand<folder>/kaizen/history.md(no extra nesting — the folder is already artifact-specific). - Shared directory:
<dir>/kaizen/<name>/plan.mdand.../history.md(namespace by<name>so siblings don't collide).
Example (per-agent folders): ~/.claude/agents/cobb/kaizen/plan.md and .../history.md.
Procedure
- Creating: create both files. Seed
history.mdwith a dated "created" entry andplan.mdwith improvements you already foresee. In collections that run the learning-capture loop (§5 — graphmind-ai-lab'sclaude/does), point the new agent's Learning-capture prompt section directly at thekaizen_teamproducer-write recipe (§5) — the:Agent/PRODUCEDedge shape, never the legacyauthorstring property. Noinbox.mdis seeded for a new agent —kaizen_teamis a shared graph, already provisioned; a new agent's entries just carry a newagentId, nothing to pre-create. - Modifying: before editing, check
plan.mdfor relevant items; after editing, append a datedhistory.mdentry (what changed and why), and update the status of any plan items you advanced — move completed ones out of the active table intohistory.md. - Reviewing (no change): record new ideas in
plan.mdeven if not implemented now. - Always read existing kaizen files first — don't duplicate items, and respect prior decisions (including things explicitly rejected/deferred).
Use Read/Glob to check for existing files, Write to create, Edit to
update. Keep entries concise.
plan.md template
# Kaizen — Improvement Plan: {name}
> Forward-looking backlog for the `{name}` {agent|skill}.
> Status: 🔵 proposed · 🟡 in-progress · ✅ done (then moved to history.md) · ⚪ rejected/deferred
> Last reviewed: YYYY-MM-DD
## Active
| ID | Added | Priority | Status | Summary |
|------|------------|----------|--------|---------|
| K-001 | YYYY-MM-DD | high/med/low | 🔵 | … |
### K-001 — {title}
- **Status:** 🔵 proposed
- **Priority:** medium
- **Rationale:** why this matters
- **Proposed change:** what to do concretely
- **Notes:** open questions, links
## Parking lot / ideas
- {half-formed ideas not yet prioritized}
history.md template
# Kaizen — Change History: {name}
> Dated log of actual changes to the `{name}` {agent|skill}. Most recent first.
## YYYY-MM-DD — {short title}
- **What:** what changed
- **Why:** motivation / trigger
- **Plan items:** K-00X (if this closed or advanced a planned item)
2. Documentation — keep both audiences informed
Every agent/skill you create, edit, rename, or remove must stay documented for two distinct audiences, as part of the same change — never leave docs trailing the source.
Audience 1 — Humans → README.md
A human-facing catalog README.md at the root of the agents collection (the
directory holding the agent folders/files), or the repo root if there is one.
One entry per agent/skill, kept in sync.
Each entry: the name, a one-line what it does, when to use it, and
links to its source file and its kaizen/ folder. On edits update the
entry; on removal delete it. Don't advertise per-agent deployment choices
(model, tool lists) in the catalog — frontmatter is their single source of
truth and the catalog copy just drifts.
Audience 2 — Agents → the project's context convention(s)
So other agents in the project know this agent exists, also record it in whatever agent-context convention the project uses. Detect what's present and update each that's in use (don't blindly create all of them):
| Ecosystem | File / location | Notes |
|---|---|---|
| Claude Code | CLAUDE.md (nearest in tree, or ~/.claude/CLAUDE.md) |
Claude-specific project rules |
| Open / cross-tool · OpenCode | AGENTS.md (project root, or ~/.config/opencode/AGENTS.md) |
The portable standard |
| Kiro | .kiro/steering/*.md |
e.g. an agents.md steering doc with inclusion: always, or a note in structure.md |
If none exists, create the one matching the active tool — default to
CLAUDE.md inside a .claude/ tree, AGENTS.md otherwise. Keep these entries
concise: name, purpose, pointers to source + kaizen files — do not paste
the whole system prompt; point to it. Keep them in sync on edit/rename/remove.
Don't duplicate the same catalog into two files. When a project would carry
identical content in both CLAUDE.md and AGENTS.md, keep one source of truth
and have the other import it: a CLAUDE.md of just @AGENTS.md pulls the
catalog in (Claude Code @-import; tool-specific, not part of the portable
standard). Put the content in AGENTS.md (broadest reach) and point CLAUDE.md
at it.
In-scope vs. cross-scope (which duty fires when)
Two different obligations with two different correct mechanisms:
- In-scope (per-edit): you edit an agent → update its kaizen + its catalog entry. Fires every time, in the same change. Resident duty.
- Cross-scope (reconcile): keeping the repo-root catalog reflecting all components/agents is not a per-edit push — a session scoped to one component may never see the parent catalog. Treat it as an on-demand reconcile pass (§3), run when asked to "sync the docs" or when you notice drift, not bolted onto every edit.
No personal information in committed artifacts (rule)
Committed artifacts — frontmatter hook commands, scripts, configs, docs, kaizen
logs, anything git tracks — must never contain the maintainer's personal
identifiers: home path (/home/<user>/…), OS username, real name, email, or
hostname. A home path additionally breaks on every other machine. In prose
(kaizen entries, origin notes), genericize: /home/<user>/…, "the maintainer".
When a tracked file must reference a deployed script, anchor it to an
expansion-safe location:
- User-scope agents (symlinked into
~/.claude/agents/):$HOME/.claude/agents/<name>/hooks/<script>.sh— resolves through the deployment symlink on any machine. Shell-form hook commands (noargs) run viash -c, so$HOMEexpands (verified 2026-07-10 againstcode.claude.com/docs/en/hooks). - Project-scoped hooks (settings.json in a repo):
${CLAUDE_PROJECT_DIR}— but it does not fit user-scoped agents, which must guard in projects where the project dir isn't the agents' repo.
The certification script (§4, check 7) greps every tracked file in the
repo for the runtime-derived identifiers ($HOME, id -un, git
user.name/user.email, hostname) and fails on any hit — the patterns are
never hardcoded in the script (that would itself be the leak), so the check
protects whoever runs it.
Origin: 2026-07-10 — six agents' frontmatter hook commands had been committed with the maintainer's absolute
/home/<user>/prg/…path; the user then asked for the guardrail to cover all personal information, not just the home dir.
Order of operations when you create or edit an artifact
- Write/edit the agent or skill source.
- Update its
kaizen/{plan,history}.md(§1; agents also write into the sharedkaizen_teamlearnings graph, §5 — noinbox.mdis created for a new agent). - If you added, renamed, or removed an agent: update every prompt that enumerates the team in the same change — an orchestrator's roster (e.g. teco's "The team you coordinate"). Other agents' prompts are consumers of the roster too; catalogs alone won't catch this drift class (origin: 2026-07-09, teco's roster silently missed two specialists created after it). Better still: don't create enumerated summary facts ("all N agents use model X") in always-loaded context docs at all — they duplicate frontmatter ground truth, cost tokens every session, and rot; delete them when found.
- Update
README.md(humans) and the relevant context file(s) (agents). - Mention at the end which docs you touched.
3. Audit & reconcile a drifted context doc
A standalone pass to bring an already-drifted AGENTS.md / CLAUDE.md /
steering doc back in line with repo reality — distinct from the "sync on my own
edits" duty above. Use when a doc has silently fallen behind (missing whole
components or agents that exist on disk).
- Enumerate ground truth.
git ls-filesfor the real file tree; read each component'sREADME/CLAUDE.md/SKILL.mdheaders and each agent's frontmatter to learn what actually exists. - Diff against the doc's claims. List what the context doc currently advertises; compare to ground truth.
- Reconcile. Add missing entries, fix changed ones, remove entries for things no longer present. Preserve the doc's existing structure and altitude.
- Apply the DRY import rule (§2) if you find the same catalog duplicated
across
CLAUDE.mdandAGENTS.md.
Origin: surfaced reconciling graphmind-ai-lab's root
AGENTS.md, which had silently lost the entirefalkor-chat/component, thegraph-dbaagent, and theseverinoOpenCode agent.
4. Team coherence certification (inter-agent audit)
The doc audit (§3) checks catalogs vs. disk. This pass checks the interfaces between agents — the drift class catalogs can't see. Run it when a specialist is added/renamed/removed, when an orchestrator or a handoff contract changes, or on demand ("certify the team").
Origin: the 2026-07-09 teco review —
qa-engineeranddevopshad existed for days with perfect catalog entries while teco's roster still enumerated a five-agent team, and several delegates carried "ask one sharp question" phrasing that assumes an interactive session subagents never get.
Deterministic half — run the script first:
claude/scripts/audit-team.sh (read-only, exit 1 on any FAIL) verifies the
greppable invariants: every agent folder has its <name>.md + kaizen pair, is
symlinked into ~/.claude/agents/, its frontmatter hook commands exist and
are executable (after mirroring the shell-form $HOME/~ expansion), every
agent is named in the orchestrator's prompt and in the two catalog owners
(claude/AGENTS.md, claude/README.md) — root AGENTS.md is checked
separately (once, not per agent) for still pointing at that catalog, not
for repeating every name inline, since the 2026-07-28 trim deliberately
de-duplicated the roster out of the root file — each declared boundary pair
(BOUNDARY_PAIRS in the script — currently eight pairs across
coder/tdd-engineer/frontend-engineer, analyst/qa-engineer/data-scientist,
graph-dba/devops/data-scientist, architect/data-scientist) names its partner
in its frontmatter description (the routing contract every router sees),
and no tracked file anywhere in the repo contains the maintainer's personal
identifiers — home path, username, git name/email, hostname, derived at
runtime (the personal-info rule, §2). Fix any FAIL before judging the rest.
Not a bare pass/fail plan done-condition. Because check 7 greps every tracked file in the repo, a plan step written as "assert
audit-team.shpasses" can be permanently unsatisfiable the moment any unrelated pre-existing leak exists elsewhere in the repo — unrelated to the change the step is actually gating. Write such a done-condition as a diff instead: capture the script's output before the change and assert no new FAIL line appears after it. (Origin: 2026-07-25, reworkingdocs/plans/cpg-query-access.md, whose v1 used the bare form.)
Counting FAIL lines from the raw output:
grep -c FAILover-counts by one — it also matches the trailingRESULT: FAIL — fix the items above, then re-run.summary line. Anchor withgrep -c '^FAIL'for the exact count of individual failing checks.
Judgment half — checklist (what the script can't see):
- Roster accuracy — the orchestrator's roster describes each specialist's current contract (deliverable paths, conventions, guardrails), not just its name.
- Handoff symmetry — every producer/consumer convention is stated on both sides (e.g. the architect's plan-doc path on architect and every implementer that consumes it; the qa-engineer's plan/report paths on qa-engineer and the orchestrator).
- Subagent-awareness — every delegate-able agent handles the can't-ask-mid-run constraint: questions, blockers, and approval requests return as the deliverable; no "ask" phrasing that assumes an interactive session — including every approval or destructive-op gate, which needs its own subagent branch stating what to return and that the rest of the work continues.
- Enforcement parity — every prompt guardrail that claims harness enforcement has a live hook, and every wired hook is described in the prompt it guards (no silent machinery, no hopeful prose posing as enforcement).
- Boundary reciprocity — when agent A says "defer X to B", B actually
claims X (and vice versa for "B routes X to me"). The name-level half is
scripted (check 6 greps each declared pair's
descriptionfor the partner); whether the claimed scopes actually complement each other stays judgment — and when a new specialist borders an existing one, add the pair toBOUNDARY_PAIRSin the script.
Fold in the single-artifact lint (§7): run the prompt-quality lint over every artifact changed since the last certification — the semantic, intra-artifact defects (contradiction, ambiguity, persona, cognitive load, coverage, composition conflict, prompt waste) that the five inter-agent checks above can't see. Mirrors the §5 graph-distillation fold-in; roll its findings into the certificate.
Certificate: log a dated entry in the maintainer's kaizen history (cobb's, in graphmind-ai-lab) recording scope, script result, findings (including any §7 lint findings), and fixes — so "when was the team last certified?" is answerable from the log.
5. Learnings graphs — capture & distillation
The self-improvement loop for a stateless agent team: capture is cheap and
unreviewed; promotion is curated. Every agent's raw capture writes into one
shared working-memory FalkorDB graph, kaizen_team, as a :KaizenEntry node
(entryId, date, fact, evidence, context, suggestedHome,
createdAt) connected by a
(:Agent {agentId})-[:PRODUCED {sessionId}]->(:KaizenEntry) edge to a real
:Agent node identifying the producer — the producer-write shape (locked
name/direction, M8, docs/plans/kaizen-agent-ontology-graph.md §2):
MERGE (a:Agent {agentId: '<agent-slug>'})
CREATE (a)-[:PRODUCED {
sessionId: '<value of $CLAUDE_CODE_SESSION_ID, or omit this key entirely if unavailable>'
}]->(k:KaizenEntry {
entryId: '<uuid4>', date: '<YYYY-MM-DD>', fact: '<the fact, one line>',
evidence: '<what was run/read/observed>', context: '<the task where it surfaced, one line>',
suggestedHome: 'prompt | knowledge base | project docs | unsure',
createdAt: '<ISO-8601 write time>'
})
called as mcp__cypher__query(graph='kaizen_team', cypher=<that text>, agent='<agent-slug>').
M8 (2026-08-22, docs/plans/kaizen-agent-ontology.md) replaced the plain
author string property with this real :Agent node + PRODUCED edge, for
every entry created from that point on — entries that already existed when
M8 shipped keep their author property and no edges at all, unretrofitted
(FR-2's no-retrofit rule; both a legacy and a current-shape read are needed
below for exactly this reason). This pattern was piloted on graph-dba, then
migrated team-wide 2026-08-20 (graphmind-ai-lab; see the Origin note below for
the two-step migration lineage — one graph per agent, then consolidated onto
this single shared graph the same day, then given real :Agent identity by
M8). The 12 agents that existed at the 2026-08-20 migration each used to carry
<agent>/kaizen/inbox.md (sibling of plan/history, but no longer required by
audit-team.sh check 1 — plan+history alone suffice): frozen from the
migration onward, then removed outright on 2026-08-21 once every entry it
ever held had been distilled into kaizen_team and cleared (git history
retains each file). A new agent created from here on gets no inbox.md at
all (FR-12/AC-9) — its Learning-capture section points straight at the
kaizen_team producer-write recipe above. During runs, every agent writes
dated, evidence-backed observations of durable, non-obvious environment
facts in its discipline — tool quirks, undocumented behaviors, conventions
that live only in the code — as new graph nodes.
What capture systematically misses, and how a distiller should read around
it. The trigger for writing an entry is surprise — the environment
behaved other than the agent expected. Being wrong is the commonest kind of
surprise and dominates any inbox, but it is not the boundary: an unexpected
discovery that involved no error at all is captured just as readily
(measured 2026-09-10 over one 17-entry chunk, of which 10 were written by
other coordinations and so uncontaminated by the request to write them: about
9 of the 10 were surprise-triggered, and two recorded no mistake of any kind).
The consequence is the part to hold on to. What is never captured is the
unsurprising success — the routine check that held, the gate that worked
as designed, the practice that quietly prevented a defect before it had a
name. Those are exactly the load-bearing practices, and they are invisible to
anyone reading the graph to learn how the team actually works. So: never
read an inbox as a description of a pass — it is a description of that
pass's surprises, and the pass's working machinery is systematically absent
from it; and when a promotion turns on a practice having worked, expect its
evidence in the coordination document or in history.md, not in an entry.
(Note the shape of that second point: it is a claim about an absence, so
it is checked by asking where would such an entry be if it existed, and did I
look there — not by the reach check, which a negative passes vacuously.) Agents never promote their
own entries, never edit or delete a :KaizenEntry once created, and never tag
a MENTIONS edge onto one — the MCP tool's producer-write authorization only
lets an agent create its own entry (and, incidentally, the :Agent node
identifying it); tagging a different agent onto an entry, editing, or
clearing one all require the curator role below. The maintainer (cobb)
distills — on request, and folded into every certification pass (§4):
-
Read the team-wide graph. Two queries, needed side by side for as long as any pre-M8 entry remains uncleared — once every legacy entry has been cleared through step 4 below, the legacy query permanently returns nothing and can eventually be dropped, but don't drop it while any legacy entry still exists (
docs/plans/kaizen-agent-ontology-graph.md§7):- Legacy read (pre-M8 entries —
authorproperty, no edges):mcp__cypher__query(graph='kaizen_team', cypher="MATCH (e:KaizenEntry) RETURN e.entryId, e.date, e.fact, e.evidence, e.context, e.suggestedHome, e.author ORDER BY e.date")— a plain read, noagentneeded (reads are unrestricted). To scope to one agent's legacy entries, add{author: '<agent>'}to theMATCHpattern. - Current-shape read (entries created after M8 — real
:Agent/PRODUCED/MENTIONSedges): "every note produced by or mentioning agent X," using the verified-idiom fallback (docs/plans/kaizen-agent-ontology-graph.md§5 — itsUNIONform is flagged there as unverified on this build, so use this one instead):
A plain read, noMATCH (a:Agent {agentId: '<agent-slug>'}) OPTIONAL MATCH (a)-[:PRODUCED]->(produced:KaizenEntry) WITH a, collect(DISTINCT produced) AS producedList OPTIONAL MATCH (mentioned:KaizenEntry)-[:MENTIONS]->(a) WITH producedList, collect(DISTINCT mentioned) AS mentionedList UNWIND (producedList + mentionedList) AS k RETURN DISTINCT k.entryId AS entryId, k.date AS date, k.fact AS fact, k.evidence AS evidence, k.context AS context, k.suggestedHome AS suggestedHome ORDER BY dateagentneeded. A historical entry has no edge for eitherOPTIONAL MATCHto traverse, so it is silently absent from this query — expected under FR-2's no-retrofit rule, not a gap; the legacy read above is what still reaches it.
Both reads truncate every cell — page the long ones before dispositioning anything. The
cypherMCP tool cuts each cell atCYPHER_MCP_MAX_CELLchars (default 300) and appends…(+N chars), so anyfactorevidencelonger than that is read short — and the tail is exactly where an entry's scope caveats, negative results and self-corrections sit. Page past it in the same tool with OpenCyphersubstring; noredis-clifallback is needed. Project several offsets in one row and check them againstsize()so you know you reached the end:MATCH (k:KaizenEntry {entryId: '<id>'}) RETURN size(k.fact) AS n, substring(k.fact,0,240) AS f1, substring(k.fact,240,240) AS f2, substring(k.fact,480,240) AS f3Verified 2026-09-09 against
kaizen_team: a 656-charevidencecame back as 300 chars plus…(+356 chars)on a plain read, and whole under the slicing above. A disposition argued from a truncated cell is argued from the half of the entry that makes the strongest claim, with the half that bounds it missing.kaizen_teamis a shared graph provisioned once up front — there is no per-agent "graph not found" case; an agent simply has zero matching entries (of either shape) until it writes one.A count delta between two census reads is a lead to attribute, not a clearing defect to assume.
PRODUCED.sessionIdnames which coordination wrote a node —MATCH (a:Agent)-[p:PRODUCED]->(k) RETURN a.agentId, p.sessionIdseparates a concurrent writer's entries from this coordination's own before you treat a moved figure as a miscount. Two caveats keep it a lead rather than a verdict:sessionIdis optional on the producer-write shape and readsnullon any entry whose writer omitted it, and inside a subagent$CLAUDE_CODE_SESSION_IDresolves to the parent session, not the producing agent — so the value identifies which coordination captured an entry, never which agent or which unit, and two units of the same coordination are indistinguishable by this method alone. Worked example, including a mis-attribution this caught and corrected:claude/docs/plans/kaizen-distillation2-coordination.md(Follow-ups, "$CLAUDE_CODE_SESSION_IDresolves to the parent session inside a subagent"). - Legacy read (pre-M8 entries —
-
Verify each entry — is it still true? Re-check cheaply against the live system or docs; environment facts rot on upgrades. Re-derive the fact yourself; don't just confirm the entry's cited evidence still exists at that path/line — a citation can be real and still misdescribe what's there (origin: 2026-08-18, a
graph-dbaentry's quoted evidence omitted aCREATEd edge that was present in the very function it quoted, and had been since five weeks before the entry was written — the entry's bottom-line conclusion still held, for a narrower reason than claimed, but a verbatim promotion would have shipped the wrong absolute claim into project docs). Unverifiable ≠ discard — date-stamp the doubt and keep or drop by value. Also check whether the entry was captured while its producing agent was mid-writing a still-open plan/method doc on the same topic — that document can already hold a fuller, more authoritative treatment, including a disposition (e.g. "defensible as-is", a scope bound) the raw entry itself never states; a match there is usually grounds for discard/generalize rather than a stop-and-ask fork (origin: 2026-09-10,data-scientistU56 — two entries captured while writingagent-knowledge-base-strategy-ml.mdturned out to be compressed duplicates of that doc's own recommendations; one instance so far). -
Route each surviving entry to exactly one destination:
- The agent's always-loaded prompt — only if it changes behavior or
routing in most sessions. Highest bar: every session pays tokens for it.
Promoted form: the rule plus at most one clause of why — nothing
else. The evidence, incident story, and provenance (dates, deciding
authority, supersession trail) land in the producing agent's
kaizen/history.mddisposition entry (step 4), never in the prompt. A rule's non-negotiability is expressed by stating it absolutely, not by citing authority or dates. Full classification table:claude/docs/plans/prompt-waste-reduction.md§3. - An on-demand knowledge base — the
graph-dba/falkordb-quirks.mdpattern: dated, live-verified entries in a<agent>/<topic>.mdreferenced from the prompt but loaded on demand. Create one when an agent's domain facts accumulate; don't inline them into the prompt. - Project docs (
AGENTS.md, the component'sdocs/) — facts about the project belong where every agent sees them, never hoarded in one agent's private files where they drift out of sync. - Discard — stale, task-specific, or already documented.
- Kept open (unresolved) — step 2's "unverifiable ≠ discard" case. Log
the dated doubt in
history.mdregardless; if the entry is actionable (not just a shrug), also open a backlog item in the agent'splan.mdunder the nextK-number. Dedup check before opening one: grep the agent'splan.mdfor the entry'sentryId— if a prior distillation pass already opened an item for it, reference/update that item instead of creating a duplicate (origin: 2026-08-18,graph-dbaentry6e5d6451…/K-007 review — the entry'sentryIdhas no in-place way to carry a forward pointer to theK-item it spawned, so a later pass reading it fresh would have no signal a backlog item already exists without this check). The raw entry itself does not survive being kept open past this pass — see step 4. - New (M8) — tag a
MENTIONSedge when the entry is really about a different agent. If, during review, an entry (legacy or current-shape) turns out to be substantively about an agent other than the one who produced it,cobbtags it — this iscobb's job during distillation (FR-4), never the producing agent's:
called asMATCH (k:KaizenEntry {entryId: '<entry-id>'}) MERGE (a:Agent {agentId: '<mentioned-agent-slug>'}) MERGE (k)-[:MENTIONS]->(a)mcp__cypher__query(graph='kaizen_team', cypher=<that text>, agent='cobb')— theMENTIONS-write curator shape (docs/plans/kaizen-agent-ontology-graph.md§3).MERGEthroughout: for theAgentnode, because the mentioned agent may never have produced an entry itself (no node yet); for the edge itself, as a free idempotency guard against double-tagging the same pair across two passes. A tagged entry then surfaces again in the mentioned agent's own future distillation pass (FR-5) — this applies equally to a legacy entry (once read via the legacy query and judged to be about another agent) and a current-shape one; tagging a legacy entry is not "retrofitting" it (FR-2's no-retrofit rule is about the producer link, not about whether acobb-added reference edge can ever point at a pre-M8 node). This tag, if added, must land before step 4 runs for this same entry in this same pass — see the ordering invariant in step 4's per-entry sequence below (item 3); do not treat this tagging and step 4's count-and-decide as reorderable or parallelizable.
- The agent's always-loaded prompt — only if it changes behavior or
routing in most sessions. Highest bar: every session pays tokens for it.
Promoted form: the rule plus at most one clause of why — nothing
else. The evidence, incident story, and provenance (dates, deciding
authority, supersession trail) land in the producing agent's
-
Log & clear. Every disposition — promoted, discarded, or kept open — gets a dated entry in the agent's
history.md(what, why, where it went, or why it's still open) — the history entry (and, for a kept-open item, theplan.mdbacklog entry) is the durable record, not the raw capture itself.Clearing a legacy entry (pre-M8,
authorproperty, no edges) is unchanged: always the one curator-clear shape, unconditionally. Clearing a current-shape entry (realPRODUCED/MENTIONSedges) is instead a read-then-decide sequence, because the node may still be needed by an edge nobody has resolved yet (FR-6,docs/plans/kaizen-agent-ontology-graph.md§4). Concretely, for each entry being disposed of (promoted, discarded, or kept open), for agent<agent>:- Read the raw entry (already done in step 1, or re-read by id) — the legacy or current-shape read as applicable.
- Verify it (step 2, above).
- Ordering invariant (load-bearing, not incidental — state this
explicitly, don't rely on step numbering alone): if step 3 (above)
tagged this entry with a new
MENTIONSedge during this same pass, that write must be confirmed durably committed to the graph before item 5's count-and-decide read (below) runs for this same entry. If the count ran before a same-passMENTIONStag landed,otherRemainingcould read one edge short, and a fullDETACH DELETE(item 5's last-edge branch) could fire before the just-addedMENTIONSedge was ever attached — silently discarding the exact cross-agent link FR-3/FR-4 exist to create, with no error raised, since aDETACH DELETEon an already-gone timeline has nothing to complain about. A future edit that reorders or parallelizes per-entry work for speed must not violate this. Editclaude/<agent>/kaizen/history.md, appending the disposition (promoted/discarded/kept-open, with reasoning) in the existing format, andplan.mdtoo if a backlog item is opened for a kept-open entry. Confirm the edit(s) succeeded before the next step — do not proceed on an error. This append-before-mutate ordering is non-negotiable regardless of disposition, and regardless of whether the next step is a partial-edge or full-node clear: the two writes are independent tool calls, not one transaction, so append-then-mutate is the only sequence that fails safe (a crash between the two leaves the entry harmlessly duplicated, or only partially resolved, rather than silently lost).- Only then, mutate the graph:
- Legacy entry — the one recognized curator-clear shape,
unconditionally, unchanged from before M8:
mcp__cypher__query(graph='kaizen_team', cypher="MATCH (e:KaizenEntry {entryId: '<id>'}) DETACH DELETE e", agent='cobb'). - Current-shape entry — first count what remains
(
docs/plans/kaizen-agent-ontology-graph.md§4.1):
A zero-row read on anMATCH (k:KaizenEntry {entryId: '<entry-id>'}) OPTIONAL MATCH (:Agent)-[p:PRODUCED]->(k) OPTIONAL MATCH (k)-[m:MENTIONS]->(:Agent) RETURN count(DISTINCT p) AS producedEdges, count(DISTINCT m) AS mentionEdgesentryIdyou believe exists is an id error before it's an absence. A UUID recalled from context (rather than copy-pasted) can be misremembered on the suffix while the leading characters read right — a sibling risk to two different entries colliding on a shared 8-char prefix (claude/docs/plans/ kaizen-distillation2-coordination.md, U17) — same consequence: a lookup that reads as already gone when it never existed as typed. Before concluding the node was already cleared (by an earlier pass, or a concurrent session), re-list the producer/mentions edges for the entry you actually have in front of you and get theentryIdverbatim from that result, not from memory. A sibling trap in the same read:exists()over a relationship pattern does not reliably scope to the bound node — it can readtruefor a node with zero matching edges even when the node appears directly in the pattern (claude/graph-dba/falkordb-quirks.md, "Cypher dialect & query behavior"). Always use theOPTIONAL MATCH+count()form above, neverexists(), to check what edges remain. ComputeotherRemaining = producedEdges + mentionEdges - 1(subtracting the one edge this pass is about to resolve), then either resolve just that one edge or clear the whole node:- Resolving
PRODUCED(the producing agent's own pass) — always resolve it, regardless ofotherRemaining(FR-6, AC-4):MATCH (:Agent)-[p:PRODUCED]->(k:KaizenEntry {entryId: '<id>'}) DELETE p. - Resolving one
MENTIONSedge (that mentioned agent's own pass) — resolve only that one edge, regardless ofotherRemaining(AC-3):MATCH (k:KaizenEntry {entryId: '<id>'})-[m:MENTIONS]-> (:Agent {agentId: '<mentioned-agent-slug>'}) DELETE m. - If
otherRemaining == 0(this was the last edge — nothing else points at the node), delete the whole node instead of just the one edge — the same unchanged curator-clear shape as the legacy case:MATCH (k:KaizenEntry {entryId: '<id>'}) DETACH DELETE k(removes onlyk's own incident edges andkitself; theAgentnode(s) on the other end are never deleted). All of the above are curator-gated Cypher shapes;cobbis a recognized curator agent (CYPHER_MCP_CURATOR_AGENTS), so each is authorized when called withagent='cobb'.
- Resolving
- Legacy entry — the one recognized curator-clear shape,
unconditionally, unchanged from before M8:
This runs for every disposition, kept-open included — an unresolved question lives on in
history.md's dated note (andplan.mdif actionable), not by leaving a live node (or live edge) sitting in the graph next to entries nobody has reviewed yet. The graph is working memory for capture not yet reviewed, not a permanent store for reviewed-but-still- unresolved questions. (Decided 2026-08-18,analyst-gated review ofdocs/reviews/graph-dba-kaizen-distillation.md, piloted ongraph-dbabefore the 2026-08-20 team-wide migration; extended to the partial-edge case by M8,docs/plans/kaizen-agent-ontology.md§3.3/Finding 2 — the alternative of leaving a partially-resolved node's remaining edges live as a standing "still unresolved" marker was not reopened, same reasoning as the original decision: nothing reads the graph for that signal thathistory.md/plan.mddon't already serve just as well.) Promotion into a prompt or catalog is a normal agent edit: full §1/§2 bookkeeping applies.
Origin: 2026-07-12 — the user asked how the agents could self-improve from what they learn exploring their areas; the answer generalized graph-dba's quirks-file pattern into a team-wide capture→distill loop, at first file-based per agent. 2026-08-20: migrated the whole team onto the graph-based capture piloted on
graph-dba(docs/plans/generic-cypher-mcp.md,docs/plans/generic-cypher-mcp-graph.md) — every agent'skaizen/inbox.mdbecame a frozen historical snapshot, capture happens inkaizen_<agent>instead (claude/cobb/kaizen/history.md). Later the same day: the per-agent graphs were themselves consolidated onto one sharedkaizen_teamgraph,author-partitioned (docs/plans/generic-cypher-mcp2.md) — capture now happens there instead, and no agent created from this point on gets aninbox.mdat all (FR-12/AC-9). 2026-08-21: all 12 remainingkaizen/inbox.mdfiles were deleted outright — every entry any of them had ever held was, by this date, long since distilled intokaizen_teamand cleared, so the frozen files were pure redundant copies of data already captured downstream; git history retains each one verbatim. 2026-08-22 (M8): the shared graph's write shape itself gained real identity —docs/plans/kaizen-agent-ontology.mdreplaced the plainauthorstring property with:Agentnodes and(:Agent)-[:PRODUCED]->(:KaizenEntry)/(:KaizenEntry)-[:MENTIONS]->(:Agent)edges, for entries created from that point on; entries that predate M8 are unaffected (FR-2's no-retrofit rule) and are still read and cleared exactly as before.
6. Testing standards (reference)
For how to test the agents/skills you maintain — the two-altitude standard
(pytest for deterministic code; the eval/bless harness for agent behavior) and
the reusable agent-eval-harness pattern — see claude/cobb/TESTING.md in the
graphmind-ai-lab repo. Keep it in sync when the harness pattern evolves.
7. Prompt quality review (single-artifact lint)
The passes above are structural (catalogs vs. disk, §3) and inter-agent
(the interfaces between agents, §4). This one is semantic and
intra-artifact: a judgment lint of a single prompt — an agent/subagent
system prompt, a SKILL.md body, a steering doc, a memory file — for the
defects an LLM reviewer can see but a grep can't. Run it when authoring or
reviewing any one artifact, and — folded into §4 — over every artifact changed
since the last certification.
It is LLM judgment, not a script: read the artifact, then work the seven
dimensions below. For each, emit findings as finding — severity (blocker / major / minor) — suggested rewrite (a concrete rewrite where the
fix is a wording change; a pointer where it's structural). "Clean" on a
dimension is a valid result — say so rather than inventing a finding.
Severity for a prompt: blocker = would cause wrong behavior in most
sessions; major = a real gap that bites in some sessions; minor =
polish. When one issue spans dimensions, report it once under the most
informative dimension (note the others in a clause) rather than filing it
several times.
- Contradiction — logical, behavioral, or format conflicts within the one prompt. Probes: does any instruction countermand another (an "always X" and an "except-when-X" placed far apart)? Do two rules demand incompatible outputs (terse vs. exhaustive; JSON-only vs. prose)? Does a tool/permission grant collide with a "never do Y" rule?
- Semantic ambiguity — instructions open to more than one reading. Probes: pronouns/scope with no clear referent ("update it"); undefined thresholds ("large files", "when appropriate") with no operational test; sequencing left implicit where order matters. Rewrite each into one operational reading.
- Persona consistency — one coherent voice and altitude. Probes: conflicting traits (terse and thorough; deferential and decisive) with no resolving rule; tone drift across sections; role labels that overclaim (the 2026-07 "senior"-removal class). Rewrite toward a single stance.
- Cognitive load — is the prompt followable in one pass? Probes: count the hard rules and competing priorities (when many items are top-priority, none is); nested/conditional depth (if-A-unless-B-except-C); always-loaded bulk that belongs in a progressively-disclosed skill (the Lean-context principle, here for instruction-following load, not just tokens). Suggest splitting, ranking, or demoting to on-demand.
- Semantic coverage — gaps in the intents the artifact claims to handle. Probes: for each stated responsibility, is the success path and the failure/empty/blocked path specified? Are the triggers for each named handoff defined? For a subagent, is the can't-ask-mid-run path covered (question returns as the deliverable)? Flag the missing path; don't invent scope the artifact never claimed.
- Composition conflict — the artifact never runs alone. Resolve its full
load-set first — the
CLAUDE.md/AGENTS.mdchain that auto-loads, every@-import, wired skills, and steering with a reachinginclusionmode (what reaches a subagent differs per tool — verify via theagent-standardsskill) — then re-run the contradiction / persona / coverage probes over the combined context. Probes: does the artifact restate (and now contradict) a rule its memory file already sets? Does a loaded skill's persona fight the prompt's? Do two loaded sources give conflicting defaults? Report each conflict as a pair (artifact rule ↔ load-set rule) with which should win. - Prompt waste — story where only a rule belongs: a prompt carries rules
and mechanisms, never stories. Probes: inline provenance (dates,
decision-authority markers such as "stakeholder decision, ",
supersession/replacement history, incident retellings); dated pointers into
kaizen/history.md(the history file is the standing, greppable home — a pointer to it is still waste); the same rule restated more than once in the file. Exempt: a normative citation — a path the rule requires the agent to use (a spec, a template location). Rewrite: state the rule absolutely; a counterintuitive rule keeps ≤1 clause of why; the story routes to the artifact'skaizen/history.md(verify it's recorded there before deleting). Full doctrine table:claude/docs/plans/prompt-waste-reduction.md§3.
Output: a per-dimension list of findings (or "clean"), each with severity
and a rewrite/pointer. On a review-only pass, record the notable ones in the
artifact's plan.md (§1). This is a lint, not a gate — it surfaces; the author
(or the user) decides.