Heuristics for identifying when a codebase needs a NEW archetype on the server, or when an EXISTING archetype is being stretched/misapplied/duplicated. Used by /analyze-archetypes, and by /analyze when recording the archetype gaps it hit. Defines what makes a good proposal, what to avoid, and how to phrase rationales.
Installs into .claude/skills of the current project.
Are you the author of Archetype Analysis?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/provenmap-archetype-analysis)
---
name: archetype-analysis
description: Heuristics for identifying when a codebase needs a NEW archetype on the server, or when an EXISTING archetype is being stretched/misapplied/duplicated. Used by /analyze-archetypes, and by /analyze when recording the archetype gaps it hit. Defines what makes a good proposal, what to avoid, and how to phrase rationales.
user-invokable: false
metadata:
author: ProvenMap
version: 0.2.0
---
# Archetype Analysis — Heuristics
When `/analyze-archetypes` runs, the architecture-analyzer agent invokes this skill in `--archetypes-only` mode to decide what proposals (if any) the codebase warrants. Archetypes are server-managed and approved by humans — a noisy proposal queue burns admin attention, so be selective.
Settling the vocabulary is **optional** — `/analyze` types every component with the closest available archetype and runs to completion regardless. These heuristics decide what is worth proposing: the same bar applies whether `/analyze-archetypes` is scanning for proposals up front, or `/analyze` is recording the gaps it hit in `metadata.archetypeGaps` so the user can act on them afterwards.
## When to run `/analyze-archetypes`
- After `/analyze` reported archetype gaps — it names the categories your codebase has that the catalogue doesn't.
- When you want to curate the vocabulary up front on a fresh project, before any board exists.
- After a codebase change that introduces a genuinely new component category (e.g. adding CDK stacks to a previously codebase-only repo).
- After admin approves proposals you previously submitted — re-running confirms the catalogue is now complete and updates the lock file. Then `/analyze --clean` retypes the affected components.
The command does **not** write board JSONs; it is a pre-analysis vocabulary check only. Approved proposals appear in `/code-plugin/archetypes` only after admin review in the ProvenMap UI — until then the live catalogue is unchanged, and `/analyze` warns if you have pending proposals submitted.
## Running the scan (`--archetypes-only`)
`/analyze-archetypes` Step 2 invokes the `architecture-analyzer` agent in `--archetypes-only` mode. The agent runs `/analyze` Steps 0, 3, 4, 5 (project detection → tech stack detection → component discovery + archetype classification) but stops there. It does **not** produce board JSON, edges, hierarchies, or manifest updates.
**Model.** If `.provenmap/config.json` has `analysis.subagentModel`, pass it as the model for the dispatched agent; otherwise inherit the session model. Same rule as `/analyze` Step 8.7 — the setting pins every analysis subagent, and this scan is one.
**Payload.** The agent's output conforms to `ArchetypeProposalPayloadSchema`: `proposed[]` (new-archetype candidates) plus `improvements[]` (improvement candidates — rename | split | redescribe | merge). Both are judged by the heuristics below, for what to propose and equally for what to skip.
**Surface the evidence before asking.** The scan runs for minutes in the background; a spawn line followed by a summary gives the user nothing to judge. Before the submit prompt, print for each proposal:
- the archetype name and the kind of gap (new archetype vs improvement)
- the files and components that evidence it — the concrete instances found
- which existing catalogue entries were considered and rejected, and why
That is precisely the material needed to sanity-check a proposal before it consumes admin review time. If the agent's payload does not carry it, say so explicitly rather than presenting an unevidenced proposal as ready.
## What makes a good NEW archetype
A proposal should clear all four bars:
1. **Coverage.** It applies to **≥2 distinct nodes** in the analyzed codebase. A one-off doesn't justify a new archetype — use an existing close-fit and add tags.
2. **Semantic role.** A clear verb-like answer to "what does this *do* on the board." Good: `lambda_function`, `event_bus`, `feature_flag`. Bad: `utility`, `helper`, `common`. **Agent-native stacks count**: repos built of prompt-ware — the prepass marks these skeleton nodes with `artifact.kind` (skill/command/agent) — commonly warrant archetypes like `agent_command`, `agent_skill`, `agent_definition` when the catalogue has no prompt-ware vocabulary yet; the detection pattern is mechanical (frontmatter signature), so bar 3 is trivially met.
3. **Observable detection pattern.** Something a future analyzer can detect mechanically — file path convention, dependency marker, import signature, naming pattern. If a human couldn't write the detection rule in one sentence, the archetype is too vague.
4. **No existing close fit.** Before proposing, scan the fetched archetype list for synonyms. If `database` already exists, don't propose `db_store`. If `service` exists, don't propose `microservice` unless you're splitting (then use an improvement instead).
## What makes a good IMPROVEMENT
There are four shapes (the `suggestedChange` enum):
| Change | When to use | Required field |
| --- | --- | --- |
| `rename` | Existing name is misleading or generic for what it's actually being used for. E.g., `service` always points to HTTP endpoints in this codebase. | `newName` |
| `split` | Same archetype is being applied to ≥2 clearly different node sub-populations. Identify the dividing axis. | `splitInto` (≥2 targets) |
| `redescribe` | Description doesn't match how it's actually being used. The name is fine; the docs are misleading. | `newDescription` |
| `merge` | Two existing archetypes are near-duplicates with no meaningful behavioral difference on the board. | `mergeIntoName` |
## How to phrase rationales
Three sentences max. Each does one thing:
1. **Pattern** — what you observed. *"12 nodes typed as `service` split cleanly into HTTP-facing controllers and background queue workers."*
2. **Impact** — what's worse without the change. *"Today these get the same icon and styling on the board, hiding the operational difference between sync and async work."*
3. **Proposed change** — what specifically would be done. *"Split into `http_service` and `worker_service`."*
No essays. No marketing language. No "for clarity" — explain *what* clarity, *for whom*.
## What NOT to propose
These all fail review:
- **Vendor names** as archetypes: `stripe_service`, `aws_lambda`, `postgres_db`. The archetype should describe the *role*, not the *vendor*. (`lambda_function` is fine because it describes the compute model; `aws_lambda` is not.)
- **Single-node coverage.** If only one node fits the proposed archetype, defer — it's not worth a server-side review cycle.
- **Archetypes already on the server.** Always check the fetched archetype list first.
- **Layered/board concepts** dressed up as archetypes. Boards have their own hierarchy; don't propose archetypes like `l0_overview` or `subsystem`.
- **Status/lifecycle** masquerading as archetypes: `deprecated_service`, `legacy_db`. Use tags for status; archetypes describe what a thing *is*, not its lifecycle stage.
## The role map (roles → archetypes)
`.provenmap/role-archetype-map.json` is the compiled bridge between the index's script-owned
role claims and the server archetype catalogue. `/analyze` Step 0 compiles it once per
catalogue hash: for every unmapped headline role (`controller`, `service`, `repository`,
`model`, `middleware`, `client`, `worker`, `module`, `migration`, `component`, `utility`) it
chooses one archetype name from the fetched catalogue, writes a draft, and runs
`pmap-prepass.js --role-map <draft>` to validate and save it. Once compiled, `--detail` rows
carry `archetype` directly — no more per-file guessing.
**An unmapped role is a legitimate outcome, not an error.** If no catalogue archetype
honestly fits a role, leave it in `unmappedRoles` — the projection shows the bare role and
those files get typed by hand. Don't force a bad fit just to close out the list.
**To re-pin a choice** (so it survives the next catalogue-hash recompile): write a draft with
`"pinned": true` on the entries you want to keep, then run
`pmap-prepass.js --role-map <draft>` again. Pinned entries are carried forward unchanged on
every future recompile; only unpinned entries get recomputed when the hash drifts.
## Examples
### Good — new archetype proposal
```json
{
"name": "feature_flag",
"visualPrimitiveType": "node",
"description": "A runtime toggle that gates code paths. Read at request-time from a flag service or env config; controls feature rollout.",
"detectionRules": "Imports from `unleash-client`, `launchdarkly-node-server-sdk`, `@growthbook/growthbook`, or local `flags.ts` with `FlagKey` enum.",
"exampleNodeSlugs": ["billing-flags", "experiments-runtime"],
"sourceContext": { "boardSlug": "overview" }
}
```
Why it passes:
- Two distinct nodes use it.
- Clear role: gates code paths.
- Detection rule a human can verify in seconds.
- No existing archetype covers it.
### Good — split improvement
```json
{
"existingArchetypeName": "service",
"suggestedChange": "split",
"rationale": "12 nodes typed as `service` split cleanly into 7 HTTP-facing controllers (use Fastify/Express) and 5 background workers (consume from SQS or run on schedule). Today they get the same icon and don't visually distinguish sync vs async work.",
"splitInto": [
{
"name": "http_service",
"description": "Synchronous HTTP service exposing REST or GraphQL endpoints.",
"visualPrimitiveType": "node"
},
{
"name": "worker_service",
"description": "Background async service consuming queues or running on a schedule.",
"visualPrimitiveType": "node"
}
],
"affectedNodeSlugs": [
"auth-svc", "billing-svc", "user-svc", "orders-svc", "search-svc",
"notifications-svc", "webhooks-svc",
"email-worker", "invoice-worker", "image-resize-worker",
"cleanup-worker", "report-scheduler"
],
"sourceContext": { "boardSlug": "overview" }
}
```
Why it passes:
- Clear dividing axis (sync HTTP vs async background).
- Population is balanced (7 vs 5 — not one outlier).
- Both targets are real archetypes in their own right.
### Bad — too narrow
```json
{
"name": "stripe_webhook_handler",
"visualPrimitiveType": "node",
"description": "Handles incoming Stripe webhook events.",
"exampleNodeSlugs": ["stripe-webhook"],
...
}
```
Why it fails:
- Vendor-specific (`stripe_`).
- Covers only one node.
- Already covered by a generic `webhook_handler` or `http_service` archetype.
For more examples and edge cases, see [`references/proposal-quality-rules.md`](references/proposal-quality-rules.md). For the command's own Steps 1–5 — every CLI call, decision branch, printed line, and the lock file plus its optional strict gate — see [`references/scan-workflow.md`](references/scan-workflow.md).