Skip to content

feat(aidd-context): rebuild project-memory as three actions, verified on both hosts#442

Merged
blafourcade merged 14 commits into
nextfrom
feat/project-memory-rebuild
Jul 15, 2026
Merged

feat(aidd-context): rebuild project-memory as three actions, verified on both hosts#442
blafourcade merged 14 commits into
nextfrom
feat/project-memory-rebuild

Conversation

@blafourcade

@blafourcade blafourcade commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Closes #417

Rebuilds 02-project-memory on the onboard anatomy: five actions become three (scan → generate → sync), each asking its own question when the answer is used.

What changed

  • Three actions. scan reads the project and stops if there is nothing to remember; generate scaffolds, writes memory to a forced flat path table, and reviews with independent agents; sync picks the tools, creates or wires each context file, fills the block with the script.
  • The client nesting bug, fixed at the root. A template→destination table names every path; generate reads it, never derives. A nested memory file is not auto-loaded, so this was silent context loss.
  • Each action asks its own question. The tool pick moved from scan to sync, so sync runs alone to wire a new tool without regenerating memory.
  • Independent review by aidd-dev:checker agents, degrading to an honest fresh-context self-pass where a host has no subagents.
  • Drift is surfaced, never silently fixed: an older template shape, an orphaned capability, a context file on an old template — each reported or offered, applied only on the user's word.
  • Templates draw a flow only where one exists (auth, deployment), never a derivable schema (the database ER is gone).
  • argument-hint names the user's cases (setup | refresh | rewire) via a new manual-hint exemption in the shared hook — the base for any case-based router.

A shared-hook change rides along

scripts/sync-skill-argument-hints.mjs gains a MANUAL_ARGUMENT_HINT list so a skill can hand-write a case-based hint. Repo-wide mechanism, additive, flagged for review.

Verified in execution

Ten headless fixtures, both hosts, every claim read off disk — 31/31. See aidd_docs/tasks/2026_07/2026_07_13_project-memory-rebuild/smoke-test.md. One asymmetry, accepted: independent review is real on Claude, an honest self-pass on Codex (codex exec spawns no subagents).

Not proven

Accepting a Prune removal or a reconcile: headless offers but cannot answer, so only the decline path is proven.

Follow-up ticket

Wire node --test into CI, then unit-test update_memory.js (updateMarkers, resolveTargets).

🤖 Generated with Claude Code

blafourcade and others added 14 commits July 13, 2026 09:12
The memory skill carried five actions, four of them a step wearing an
action's coat, and a SKILL.md that listed the references its own actions
already point at.

Rebuild the router on the onboard anatomy: a linear scan -> generate ->
sync mermaid, a three-verb table, and the line that makes the skill run on
a host that reads only SKILL.md. Scan detects the tools and takes the
user's pick, so no tool is ever wired without being chosen. One tools.md
carries detection and the context-file path, since both are keyed by tool.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Clients running Codex and Copilot got their core memory written into a
core/ or internal/ subfolder. The old action forbade it in prose, inside a
step, and the prose lost to the template tree's own shape. A nested memory
file is not auto-loaded, so the project silently lost the memory it thought
it had.

Give every template an exact destination in a table. The capability folder
gates which rows generate and never enters a path. Generate reads the
destination instead of deriving it.

Generate now also scaffolds and reviews, folding two actions that were each
a single step. The review fans out to readers that did not write the file,
and says so when the host cannot give it any.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sync could not create a context file, so a project whose tool had none was
told to go make one first. And the fill script wrote into every context file
it found, including an AGENTS.md the user never chose.

Sync now owns the context file end to end: it creates a missing one from the
template, upserts the block, then fills it. The script takes the picked tools
and fills only theirs. Called with no tool, it still fills every file present,
which is what the auto hook wants. It refuses a tool it does not know rather
than filling nothing and reporting success.

It never inserts a block. A hand-written AGENTS.md with no block stays as its
author left it, unless its tool is picked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Delete the five old actions and the AI map, now carried by three actions and
tools.md. Fix docs/CATALOG.md, stale for project-memory and for onboard, whose
rework renamed its actions and never told the catalog.

Verified by running it, not by reading it. Both hosts were synced to this
branch first: their caches held 2.2.0 and its old actions, so an unsynced run
would have passed for the wrong reason.

Claude and Codex each walked scan -> generate -> sync and wrote nine flat
memory files. Codex's hand-written AGENTS.md, which had no block at all, got
the section, the block, and the fill, and kept its own line. Neither host
touched a tool the user had not picked. The review found real defects a writer
cannot see in its own draft: a dependency declared and never imported, and an
architecture diagram drawing edges the code does not have.

The no-subagent review fallback stays unproven. Both hosts have subagents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… is used

Scan asked which AI tools you use before a single memory file existed, a
leftover of the design where the context file came first. The answer was only
ever consumed by sync, three steps later, and holding it there made the whole
pipeline all-or-nothing: wiring a new tool into a project that already had its
memory meant regenerating that memory.

Move the tool pick to sync, which now detects, asks, and wires on its own. A
detected tool is offered ticked, so adding codex cannot silently unwire claude
and leave its block to rot.

Scan gains the guard it never had: memory records what exists, so a project
with no code, no INSTALL.md and no PRD is told to go make something first,
rather than handed six hollow files that its own rules forbid.

Proven by running it. Sync alone wired codex into a memory it did not write,
refreshed claude's block, and left all nine memory files byte for byte. An
empty repo stopped at Ground and wrote nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The templates changed shape three times in the past month. A file generated
from an older one silently kept that shape: generate refreshed its content from
the code and never looked at its sections, so a section the template gained was
never mentioned. The bank reported itself up to date while missing a section it
was supposed to have.

Generate now compares the template's sections to the file's. It reports what is
missing and injects nothing, the same rule already applied to a nested file.

A version field would have been the cheaper-looking fix and the wrong one. It
has to be bumped by hand, so a forgotten bump makes the drift invisible, and it
has to live in the generated file, which the AI loads every session, so every
project would pay tokens forever for a check that fires three times a month.
Sections are derived from what is actually there, cost no field, and cost no
tokens.

The noise it does not make matters as much as the drift it finds: a section
left out because the project has nothing to put there stays unmentioned.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SKILL.md carried two rule blocks and called both transversal. Only one was.
The six rules about what a memory file holds have exactly one consumer,
generate, so every action paid for them, including sync, which writes no memory
at all and can now run alone.

They were also said twice: three of the review protocol's four axes restated
them from the reviewer's side. Now they have one home. Generate writes against
it, the reviewers judge against it, sync never loads it.

Also stop the fill script from staging when the skill calls it. Staging is right
for the auto hook, which owns no other change. Called after generate has written
eight files the script knows nothing about, it staged its own two and left an
index that read like the whole change was ready to commit.

SKILL.md drops from 349 to 229 tokens. Both hosts still apply the rules from
behind the reference: no placeholder, no version in a tech name, memory pointing
at the code instead of copying it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t can see

Two ways the skill reached outside itself.

It named skills from other plugins. Scan sent an empty project to
aidd-pm:03-prd, and the review protocol called for aidd-dev:checker by name.
A plugin that may not be installed is not a dependency a worker skill gets to
have, and the review, the part that had to work, was the one hard-wired to a
neighbour. Both now say what they need in plain words. Claude still found its
checker on its own and ran nine independent reviewers, which caught the same
dependency-declared-but-never-imported bug as before. The behaviour survived
the decoupling.

Scan also grounded itself on AIDD's own artefacts, an INSTALL.md or a spec
under aidd_docs/, as if a project could only exist inside the ecosystem. It now
looks for source code, or anything written that says what the project is.

The Test sections restated the rules they sat under: "scan never asks about AI
tools" is the rule, not a way to find out whether it held. They now name what
can be observed once the action has run: a find that comes back empty, a file
at an exact path, an exit code, an unstaged working tree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A file-by-file pass over the skill with the maintainer.

Each reference now carries only what no table or action already says:
tools.md keeps two rules the columns cannot express, capability-signals
drops the files column (it lived in memory-destinations) and the monorepo
row (codebase-map's job), memory-destinations is a plain mapping, memory-rules
lists a memory file's properties, review-protocol is a numbered protocol
addressed to the reviewer and now catches dead commands, invented rationale,
and omissions.

memory-block.md is deleted: the block's shape lives in assets/AGENTS.md and
its fill in the script, so sync's upsert points at the template and needs no
separate reference. A new structure.md fixes the scaffold tree; a new
report.md shapes generate's report like onboard.

The actions gain what the review surfaced: scan splits the empty-project stop
from detection, generate splits Write from Prune and Review from Fix and
reports through the asset, sync gains a Require guard and offers to reconcile
a context file drifted from the template. SKILL.md's description leads with
the project, not the plumbing, and the mermaid shows both entries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rose

updateMarkers anchored on the first open tag. A user who quotes
`<aidd_project_memory>` in hand-written prose above the real block turned
that mention into the cut point, splicing out every line between it and the
block on the next fill.

Anchor on the close tag, then take the nearest open before it. The real
block is always the open closest to its own close, so a marker quoted above
is never chosen. Proven on the exact case plus the normal, no-block, and
hook paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The database template shipped an erDiagram, which is a restated schema the
migrations already hold. Replace it with an optional domain diagram: the
aggregate roots the schema does not show, gated to non-obvious cases.

auth and deployment are the most flow-shaped concerns and had no diagram.
Give each an optional, gated flow: the login-to-session path, the pipeline
stages, drawn only when non-trivial and never a derivable schema or tree.

The memory README shows how the bank loads as a mermaid instead of prose,
and its maintenance rules now match memory-rules.md rather than drifting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The hook derived every skill's argument-hint from its action file names.
That fits a loop, but not a router whose actions are not all entry points:
project-memory's generate never runs alone, and a user thinks in cases (set
up, refresh, re-wire), not action names.

Add a manual list the hook leaves untouched, so a skill can hand-write a
case-based hint. project-memory is the first, its hint now `setup | refresh
| rewire`. This is the base for any case-based router to come.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…roof

The plan gains the decisions taken during the file-by-file review, the
smoke test records ten fixtures verified on disk across both hosts, and the
session report is the map of what changed and why. Notes the one asymmetry:
independent review is real on Claude, an honest self-pass on Codex, accepted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ebuild

# Conflicts:
#	plugins/aidd-context/skills/02-project-memory/actions/02-scaffold-docs.md
@blafourcade blafourcade merged commit e494207 into next Jul 15, 2026
2 checks passed
@blafourcade blafourcade deleted the feat/project-memory-rebuild branch July 15, 2026 16:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant