Skip to main content
ClaudeWave
Skill510 repo starsupdated today

capabilities-map

The capabilities-map skill audits installed skill coverage against the locked 6-value capability taxonomy defined in docs/CAPABILITIES.md. It reads skill manifests, runtime configuration, and per-skill capability declarations to build a matrix showing which enabled skills declare each capability tier and flags any tier with zero enabled coverage as an actionable gap. Operators use this to identify capability blindspots in their stack before they cause production issues.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/aaronjmars/aeon /tmp/capabilities-map && cp -r /tmp/capabilities-map/skills/capabilities-map ~/.claude/skills/capabilities-map
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

> **${var}** — Optional. `dry-run` skips notify (article + state still write). Empty = normal run.

Today is ${today}. PR #268 landed the locked 6-value capabilities taxonomy in `docs/CAPABILITIES.md` and the matching `capabilities: []` field in `skill-packs.json` (per-pack and per-skill). PR #304 added a CI parity check so the taxonomy can't drift across the three places it lives. The vocabulary is now stable — but no skill yet **uses** it to answer the operator's question: *what does my enabled stack actually cover, and where are the gaps?* This skill is that view.

It reads the installed-skill manifest (`skills.json`), the runtime config (`aeon.yml`), the community registry (`skill-packs.json`), each installed pack's local `skills-pack.json` manifest, and per-skill `capabilities:` frontmatter — joins them into a coverage matrix bucketed by the 6 locked tiers — and surfaces any tier with **zero enabled coverage** as a gap the operator can close before it bites them in production.

Read `memory/MEMORY.md` for context.
Read the last 8 days of `memory/logs/` for prior-run context.
Read `soul/SOUL.md` + `soul/STYLE.md` if populated to match voice in the notification and article.

## Why this exists

A working aeon instance typically runs 20–60 enabled skills mixed across native code, community packs, and one-off installs. Each carries a blast-radius footprint — does it touch the chain? does it speak for the operator on X/Discord/Slack? does it spend through a budgeted API key? — and after PR #268 each pack can self-declare that footprint in `skill-packs.json` (or its own `skills-pack.json`). But declared data without a viewer is dead data. An operator who installs five new community packs across a sprint has no surface that aggregates the resulting capability shift: maybe their stack is now writing on-chain across three skills when it used to do zero, and they'd never know unless they ground through each pack manifest by hand.

The matrix this skill writes is the missing surface. It answers three questions on one screen:

1. **Coverage** — for each of the 6 locked capability tiers, which enabled skills declare it?
2. **Gaps** — which tiers have **zero** enabled skills (capability missing entirely)?
3. **Undeclared** — which installed skills declare *nothing*, leaving their footprint invisible to the matrix?

The third row is the lever for community pack authors and for native-skill maintenance: every undeclared skill is a documentation gap a contributor (or the operator) can close with a one-line frontmatter edit.

This skill is **read-only**. It never edits `skill-packs.json`, never writes `capabilities:` into a skill's frontmatter on the operator's behalf, never disables a skill because it lacks a declaration. The taxonomy is documentation; this is the report that surfaces compliance.

## Inputs

| Source | Purpose | Auth |
|--------|---------|------|
| `docs/CAPABILITIES.md` | The locked 6-value taxonomy — extracted from the `## The taxonomy` table (same extractor `scripts/check-capabilities-parity.sh` uses) | Local file |
| `skills.json` | Installed-skill manifest — slug, name, category, schedule | Local file |
| `aeon.yml` | Runtime config — `enabled: true|false` per skill in the `skills:` block | Local file |
| `skill-packs.json` | Community registry — pack-level `capabilities[]` arrays + the `skills[]` slug list per pack (used to resolve which installed skills came from which pack) | Local file |
| `skills/<slug>/skills-pack.json` (if present) | Locally-installed pack's own manifest — per-skill `capabilities[]` arrays (more specific than the pack-level union) | Local file |
| `skills/<slug>/SKILL.md` frontmatter `capabilities:` | Per-skill native-source declaration — the canonical hook for native skills to declare a footprint | Local file |
| `memory/topics/capabilities-map-state.json` | Prior-run snapshot for the delta gate (per-tier enabled counts + the undeclared set last run) | Local file |

No network calls. No new secrets. All inputs are local files written by `generate-skills-json` / committed by the operator / installed by `./install-skill-pack`.

Writes:
- `articles/capabilities-map-${today}.md` — human-readable coverage matrix + gap call-outs (every non-error run, including `QUIET`)
- `memory/topics/capabilities-map-state.json` — prior-run snapshot
- `memory/logs/${today}.md` — one log block per run
- Notification via `./notify` — only when the gap set changed, when a previously-zero tier picked up coverage, or on the first (baseline) run (see step 7)

## Steps

### 0. Bootstrap

```bash
mkdir -p memory/topics articles
[ -f memory/topics/capabilities-map-state.json ] || cat > memory/topics/capabilities-map-state.json <<'EOF'
{"last_run":null,"last_status":null,"tier_counts":{},"gap_set":[],"undeclared_count":null,"declared_skills":[]}
EOF
```

If `jq empty` fails on the state file (corrupt JSON from an aborted write), back it up to `.bak`, reset to the empty template above, and set `STATE_WAS_CORRUPT=true`. On a corrupt-recovery run the skill writes the article + state but **suppresses notify** (terminal status `STATE_CORRUPT`) — there is no trustworthy prior snapshot to diff against, so the delta gate would either misfire or fire a spurious "all gaps are new" baseline. The next clean run notifies normally.

`tier_counts` is a map keyed by capability value: `{enabled: N, disabled: N, total_declared: N}`. `gap_set` is the array of capability values that had zero enabled coverage last run. `declared_skills` is the array of skill slugs that had any capability declared last run (used to detect when a previously-undeclared skill picks up a declaration).

### 1. Parse var

- Split `${var}` on whitespace. The only recognised token is `dry-run`.
- If any other token is present → log `CAPABILITIES_MAP_BAD_VAR: ${var}` and exit (no writes, no notify).
- `MODE=dry-run` if the `dry-run` token is present, else `execute`.

### 2. Load the locked taxonomy

Extract the 6 capability value