| name | amg-consolidate |
| description | Maintain AMG memory: fold the co-activation log (Hebbian weight updates only when enabled), file the session's conclusions/decisions as notes by value, and run threshold-gated branch compaction so the graph stays sharp and bounded. USE THIS at the END of a working session (before /clear), on a schedule, or when asked to "consolidate / clean up / compact memory", or when retrieval feels noisy. Memory is NOT compressed by default — compaction only triggers on branches over budget. Crash-safe and idempotent. Triggers: "consolidate memory", "update the memory weights", "file what we decided into memory", "the memory graph is getting noisy/large", "wrap up this session and save the memory". |
AMG Consolidate
This closes the memory loop. Three concerns, in order of cost and safety:
- Weights — fold the co-activation log. By default this only accumulates the
coact counters (conductance stays static and predictable); the Hebbian update
itself — strengthen the used, fade the unused, prune — runs only when
weights.apply_hebbian: true. Deterministic, no model.
- Salience — promote the session's worthwhile conclusions to long-term memory.
Capture during a session is cheap and broad; selection happens here, with the
full context, so we don't have to be right in the moment.
- Compaction — only when a branch is over budget, compress it the minimal staged
amount, preserving the valuable and archiving the rest (reversibly).
The crash-safety, archival, and idempotency guarantees are in
../amg-bootstrap/references/consistency-model.md. The mechanical work is in
scripts/consolidate.py; model judgment is delegated to the amg-consolidator
subagent, which emits an action list that the script applies transactionally.
When to run
End of a session (before /clear), on a schedule, or on request. Running it on an
unchanged, in-budget graph is cheap and safe (with no new co-activation log nothing
changes; nothing is compacted).
Workflow
-
Fold weights (deterministic, run directly):
python .claude/skills/amg-consolidate/scripts/consolidate.py weights .
This reads .claude/amg/work/coactivation.log (written by retrieval), folds it
into the edges' coact counters, renormalizes part_of, and rotates the log into
the archive. The Hebbian update itself (reinforcement + decay + pruning) runs only
when weights.apply_hebbian: true in config.yml — off by default, so edge
conductance stays static until an uplift is measured.
-
Capture this session's conclusions through the safe note API — never by
hand-editing files under nodes/:
python .claude/skills/amg-bootstrap/scripts/notes.py add \
--type decision --summary "..." [--body "..."] [--tags "routing,controllers"]
Record any decisions, conclusions, open questions, or forward-looking plans reached
in the conversation (types: note / decision / adr / open_question / plan;
default status captured). The write is transactional and crash-safe. These are the
episodic inputs the salience step judges. When in doubt, capture — selection happens
next, not now.
-
Plan (deterministic):
python .claude/skills/amg-consolidate/scripts/consolidate.py plan .
Writes .claude/amg/work/consolidation-plan.json: branches over budget (with
staged steps), near-duplicate candidates, episodic notes ranked by a deterministic
salience score (recency, frequency, bridging, provenance, type), and — for
arbitration — contradictions (conflict pairs with comparison inputs) and
source_contradicted (nodes whose live-source check failed).
If the plan carries a warning (a large semantic backlog — the graph lags its
sources), stop and offer the user a sync first: judging a stale picture skews
both the consolidator and the eval gate; proceed anyway only on the user's
explicit say-so.
-
Judge — spawn the amg-consolidator subagent with the plan path and the
working_language value in the assignment (you read the config once; the judge
must not spend a turn reading it). The plan already carries every candidate's
summary, so the judge works from it (bodies are opened point-wise, only for the
finalists of a destructive action) and decides, per the salience rubric and branch
budgets, which notes to , which near-duplicates to ,
which stale episodes to , where to , and what
low-value detail to ; and it — by provenance,
freshness and source rank, not query frequency — emitting (non-destructive status verdicts, logged
to ). It emits . It does edit
the graph directly.
Salience rubric (what gets promoted / protected)
Value-of-information, not topic: novelty/surprise (does it change the model — a
duplicate is low, a contradiction high), decisions/commitments/plans (high,
referenced repeatedly), bridging (connects many nodes / clusters),
reusability (a principle that holds in future sessions vs a one-off),
provenance (grounded in code/docs vs an unsupported guess → file as an open
question, not a fact), recency/frequency. Promotion raises status; it does not
delete. Decisions/ADRs and high-centrality hubs are protected — never collapsed
or shortened.
Compaction is gated — by budget and by the eval
- A branch is compacted only if
size > branch_budget (per-hub override, else the
config default). Otherwise it is left untouched.
- Steps run bottom-up and stop the moment the branch is back under budget:
summarize_episodes → merge_near_duplicates → introduce_subhub → lossy_shorten.
- Lossy shortening is the last resort and archives the full text first.
- Compaction is auto-gated by recall — and only compaction.
consolidate.py apply
measures the COMPACTION SUBSET of the actions on a clone of the graph and commits
it to the real graph only if the pack holds its gold (pack_recall +
pack_hop_recall, the multi-hop subset frozen from the baseline); on a drop it
rejects the compaction subset — or warns and applies — per eval_gate.on_fail,
writing work/eval-gate-report.json (which cases regressed, which gold ids were
lost, which actions caused it). The non-compaction remainder — arbitration
verdicts, promotions — is non-destructive and applies regardless of the verdict,
so a rejected compaction never holds the safe half hostage (the result names both:
gate: rejected + the applied counts). It needs labeled cases (eval_gate.cases);
with none/empty/unresolved cases it skips safely — never a false reject. You can
still run the eval by hand (../amg-retrieve/scripts/eval_retrieval.py) to tune
budgets; the archive and git history make any revert trivial. Safety here is a
measured number, not a hope.
Reference
scripts/consolidate.py — weights, plan, apply (+ selftest_consolidate.py).
- Subagent:
../../agents/amg-consolidator.md.
../amg-bootstrap/references/consistency-model.md — crash-safety & archival model.