| name | pre-scaffold-openspec-coherence-check |
| description | Run before scaffolding any OpenSpec proposal in pi-agent-dashboard to catch duplicates of archived work and contradictions with already-shipped architecture. Always run when about to create openspec/changes/<name>/ (proposal.md/design.md/tasks.md), especially for proposals touching tool-renderers, plugin slots, MCP rendering, or any subsystem with a recent archive entry. Skipping this check produces stale proposals that duplicate archived work and contradict shipped architecture. Triggers: 'scaffold OpenSpec', 'write a proposal', 'create change', 'openspec change new'. |
| version | 1 |
| created | 2026-06-13 |
| updated | 2026-06-13 |
When to Use
Use before scaffolding any new OpenSpec change in pi-agent-dashboard, regardless of whether the topic feels novel. Two of the most damaging mistakes the assistant has made are (a) re-proposing work that already shipped and was archived, and (b) basing claims about current code on stale file-index harvests or grep results that miss the actual wiring idiom. This skill front-loads the cheap checks that would have caught both.
Trigger this skill when about to run any of: openspec change new, Write to openspec/changes/<name>/proposal.md, the openspec-new-change skill, the openspec-ff-change skill, or any drafted "## Why / ## What Changes" markdown that will become a proposal.
Do NOT skip even when the explore-mode conversation feels grounded. The Explore subagent harvests the file-index which can be days stale; the main agent's own grep can answer the wrong question (e.g. grepping for a consumer component when the wiring is inline).
Procedure
- Archive sweep: ls openspec/changes/archive/ | grep -iE ‘<topic-keywords>’. For tool-renderer / plugin-slot / MCP / ctx_* / context-mode topics specifically check for 2026-06-05-wire-tool-renderer-slot and 2026-06-05-add-ctx-tool-renderer. If any archive entry matches the topic, READ its proposal.md before writing a new one.
- Active sweep: openspec list | grep -iE ‘<topic-keywords>’. Read any active change that overlaps so the new proposal does not collide on filename, capability, or scope.
- Current-code verification (for behaviour claims): if the proposal says ‘X is not wired’, ‘Y never fires’, ‘Z falls through to Generic’, grep for the FUNCTIONAL pattern not just the named component. For tool-renderer claims specifically: grep -rn 'getClaims.*tool-renderer\|forToolName' packages/client/src/components/ToolCallStep.tsx and read the current dispatch block (lines 90–120). The slot wiring inlines useSlotRegistryOrNull + forToolName + claimShouldRender; the ToolRendererSlot consumer component is unused, but that does NOT mean the slot is unwired.
- Slot-prop contract check: cat packages/shared/src/dashboard-plugin/slot-props.ts and read SlotPropsMap[‘<slot>’]. Confirm the required fields (every slot requires pluginContext: AnyPluginContext) and the optional fields. Do not invent a contract.
- Registry check (built-in renderers): cat packages/client/src/components/tool-renderers/registry.ts. The ctx_* family is mapped to a single CtxToolRenderer with a ctx_-prefix safety net for new tool names. Honour this architecture choice unless explicitly proposing to revisit it.
- Architecture-choice review: when the topic intersects an existing implementation, search recent commits with git log --oneline --since=<30 days> -- <relevant paths> to understand which design the team picked and the rationale. The choice between core built-in vs plugin for ctx_* was DELIBERATE (high-frequency tool, hot path); do not propose to reverse it without an explicit justification section.
- Optional but recommended: run the spec-coherence-check skill (project skill) which sweeps all active proposals for staleness, conflicts, and obsolescence against the current codebase and archived changes. Treat its output as authoritative.
Pitfalls
- Trusting an Explore subagent that read only the file-index. The file-index can lag commits by days; for any claim about CURRENT code behaviour, verify against the source tree directly.
- Misreading grep results: 'rg ToolRendererSlot returns no hits' is technically correct but does NOT imply 'plugin tool-renderer claims do not fire'. The wiring may be inline. Always grep for the FUNCTIONAL identifier (getClaims, forToolName) not just the named component.
- Skipping the archive sweep because the topic feels new. Topics that already shipped get archived under YYYY-MM-DD-prefixed folder names; ls openspec/changes/archive/ once, costs nothing.
- Inventing a slot prop contract from memory. Every plugin slot in slot-props.ts requires pluginContext: AnyPluginContext on top of the slot-specific fields. Missing this in a spec is a silent gap.
- Re-proposing a plugin-based architecture without acknowledging the team chose core built-in (commit 858464d0 for ctx_*). The proposal must explicitly argue why the existing choice should be reversed; otherwise it contradicts shipped reality.
- Pushing a proposal commit straight to develop without running these checks. develop accumulates contributions quickly; a stale proposal there gets cleaned up by others (which is what happened to openspec/changes/wire-tool-renderer-slot/ in commit e4e63989 — someone deleted my folder upstream, and I had to revert the rest).
Verification
- The archive sweep ran and either returned no matches OR I read every matching proposal.md and either align with it (delta-style change) or explicitly argue why a fresh proposal is needed.
- For every behaviour claim in the proposal's ## Why section, I have a direct grep / cat result from current code that supports it, not a recollection.
- The proposal's ## What Changes section does not contradict any code in packages/client/src/components/tool-renderers/registry.ts, packages/client/src/components/ToolCallStep.tsx, or packages/shared/src/dashboard-plugin/slot-props.ts.
- If proposing a new capability name, it does not collide with any folder under openspec/changes/ or openspec/changes/archive/. Specifically: openspec/changes/<name>/ does not exist AND openspec/changes/archive/*-<name>/ does not exist.
- openspec validate <change-name> passes (catches structural issues but not contradictions — the above checks catch those).