Context & Investigations
Capability Self-Awareness
A single hand-curated capability registry that generates both Mallory's cached persona self-description and, later, the UI's copy — so he never denies something he can actually do.
Situation
Wave 1-A. Mallory's sense of what he can and can't do is hardcoded in two disconnected places, and both have drifted from reality: src/persona.ts still denies capabilities the system has since grown (deep digs, agenda/tasks/activity/status, earlier conversation history), and web/src/routes/+page.svelte's Briefing help sheet hand-writes a separate, independently-drifting description for the user.
There is no machine-readable manifest of capabilities — the only structured list is KNOWN_SIGNALS in orchestrator.ts. The goal is one source of truth that both the persona (now) and the UI (Wave 1-B/C, later) read from, so Mallory never denies a capability he has, and is honest in the moment about signal-backed capabilities that depend on a fresh push.
Key decisions
Curated registry, not auto-derived
src/capabilities.ts is hand-authored — raw routes like /loops/item/toggle are too granular to describe in the persona's voice.
Hybrid: static claim + dynamic note
A pure renderCapabilities() builds the constant "can/not yet" passages that stay inside the cached persona block; a per-turn, non-cached note layers on live signal freshness ("agenda is fresh as of 08:10").
Cache correctness preserved
renderCapabilities() reads only the static registry — no per-request data — so it can't bust the existing prompt-cache prefix.
Near-free dynamic layer
The availability note is derived from signals loadSignals already fetched that turn — no new fetch, no cache impact.
Drift guard deferred
A test asserting every signal/route maps to a registry entry is explicitly deferred to a future round at Alex's request, noted as a known follow-up.
Architecture
One new registry module feeds a scoped edit to the persona and a small injection point in the per-turn context assembly.
CAPABILITIES registry (id, built, claim, backing, liveness) + renderCapabilities() + the dynamic availability-note builder.Risks & guardrails
Cache correctness
Mitigated by keeping renderCapabilities() a pure function of the static registry only.
Voice quality
claim strings are full in-voice phrases joined into prose by the renderer, not a bulleted list — reviewed in the plan.
Dynamic note verbosity
Kept to one short line per turn so it doesn't bloat every response.
Signal-key duplication
KNOWN_SIGNALS in orchestrator.ts lists signal keys independently of the registry; they match today but could silently diverge — folded into the deferred drift-guard follow-up.
Delivery
Registry + renderer
CAPABILITIES inventory and renderCapabilities().
Persona integration
Fold the generated passages into the cached persona block.
Dynamic note builder
capabilityAvailabilityNote() from fresh/stale/missing signal state.
Signal-read reporting
loadSignals reports which requested signals were unavailable.
Chat wiring
Inject the availability note in chat.ts, non-cached.
Out of scope
docs/superpowers/specs/2026-06-12-capability-self-awareness-design.mdplan ·
docs/superpowers/plans/2026-06-12-capability-self-awareness.md