| name | stack-gaps |
| description | Find the components a project is missing rather than the ones it has — caching at every layer, backups, queues, rate limiting, observability, error tracking, secrets handling, migrations — judged against what the project's archetype actually needs. Use when the user says "what's missing from my stack", "am I missing caching", "should I add a cache", "what components should this have", "is anything obviously absent". Reads docs/stack/stack.json from stack-inventory. |
stack-gaps
What should be here and is not.
The inventory lists what exists. This skill works the other side of the slot list: for every slot
the archetype expects, is it filled, deliberately empty, or just missing? Missing infrastructure
is invisible in code review — nothing points at the cache that was never added.
Inputs
path (optional): repo root. Defaults to cwd.
focus (optional): a single concern, e.g. caching, resilience, observability.
Procedure
1. Load the record and the expectations
Read docs/stack/stack.json (run stack-inventory first if absent) and
${CLAUDE_PLUGIN_ROOT}/references/archetype-checklists.md.
Take the archetype from the record. If it looks wrong for what you can see in the repo, say so
before proceeding — every judgement below depends on it.
2. Filter out settled decisions
Drop every slot marked intentionally-absent. Those were decided; re-raising them wastes the
user's attention and makes the plugin annoying to run twice.
Two exceptions, both stated explicitly rather than silently reopened:
- The archetype changed since the decision, so its premise may no longer hold.
- The stated reason is visibly expired ("no production data yet" on a repo that now has a
production deploy target).
3. Work the caching question first
Regardless of focus, walk all five caching layers from the archetype checklist: edge/CDN, HTTP
response, application, data access, client. For each, state present / partial / absent.
A gap here is only a finding if there is something worth caching. Look for the workload evidence:
- Repeated identical queries or an N+1 pattern in the data access layer
- A paid third-party API called on a request path
- LLM inference on idempotent input with no memoization — recurring cost with no upside
- A read-heavy endpoint hitting the database with no
Cache-Control on the way out
- A frontend refetching the same data on every mount
Where there is no evidence of load, say that: recommend recording the slot as
intentionally-absent: no measured load rather than inventing a cache the project does not need.
Adding a cache to a system with no load is itself an anti-pattern — a new failure mode and a new
consistency problem bought with nothing.
Where there is evidence, be specific about which layer. "Add Redis" is not a recommendation;
"cache the geocoding API responses, which are called per-request and change annually, in a
process-local TTL map before reaching for a shared cache" is.
4. Work the remaining expected slots
For each slot marked R or E for this archetype and not filled, ask:
- What breaks, and when? A missing backup is a total-loss risk on day one. A missing queue is
fine until the first slow request path.
- Is the concern being handled somewhere else, differently? Rate limiting may be at Cloudflare
rather than in the app; logs may go to the platform's own collector. Handled elsewhere is
handled — check before flagging.
- Would filling it introduce more operational surface than it removes risk? For a single-operator
homelab service, "add Prometheus, Grafana and Alertmanager" can be worse than the gap.
Give backups and secrets handling particular weight. Both are cheap to fix and unbounded in cost
when absent, and neither shows up in any code-level review.
5. Right-size every recommendation
Match the fix to the project, not to a reference architecture:
| Instead of | For a small project consider |
|---|
| Redis for caching | in-process TTL map, or HTTP Cache-Control + CDN |
| Kafka for events | Postgres table with SELECT … FOR UPDATE SKIP LOCKED |
| Kubernetes | one Docker Compose file |
| Datadog | structured stdout logs + the platform's log viewer |
| Vault | 1Password CLI or platform-injected env vars |
| Celery + broker | a cron job |
The lightest thing that closes the gap is the recommendation. Note the heavier option as the
upgrade path if the project outgrows it, and name the signal that would mean it has.
6. Record
Append findings to stack.json with category: "gap", the slot, severity, evidence, a specific
recommendation, effort, and blast_radius (most gap fixes are additive — worth stating,
since additive changes are the safe ones to do first).
Update slots_absent[] so the state matches. Where the user confirms a gap is deliberate, write
the reason and decided_on immediately — that is what stops the next run repeating it.
Write docs/stack/reports/<date>-gaps.md.
7. Report
Order by severity, not by slot order. For each: what is missing, what it costs to leave, the
lightest fix, effort. Close with the slots you checked and found fine, in one line — the absence
of a finding is information too.
Guardrails
- No cargo-culting. Every recommendation names the specific evidence in this project that
motivates it.
- Do not raise a slot the archetype table marks not-applicable.
- Do not re-raise settled decisions.
- Recommend; do not implement. Handing a proposal to an execution agent is
stack-proposal's job.