Shipkit architecture map
Skill stefan-stepzero/shipkit/install/skills/shipkit-architecture-map
Shipkit — AI-assisted product development framework for Claude Code. Skills, agents, and workflows for shipping MVPs fast.
npx -y skills add stefan-stepzero/shipkit --skill shipkit-architecture-mapAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Maintain a code-derived 'current belief of the system architecture' map — key applications, datastores, contracts, and integration points. Triggers: 'map architecture', 'architecture map', 'what does the system look like', 'refresh architecture map'.
SKILL.md
10.4 KB, as published. Nobody here has run it
shipkit-architecture-map — Living Architecture Map
Purpose: Maintain .shipkit/architecture-map.json — a continuously-refreshable, code-derived answer to "what does the system currently look like?" (applications, datastores, contracts, integrations). It is the what-is map.
This is distinct from .shipkit/architecture.json, which is the why — the append-only decisions log. This skill never reads or writes architecture.json; the two artefacts coexist (decisions vs current-state).
When to Invoke
User triggers:
- "Map the architecture"
- "What does the system currently look like?"
- "Refresh the architecture map"
- "Show me applications / datastores / contracts / integrations"
Auto-suggested when:
- No
.shipkit/architecture-map.jsonexists and the repo has real source code - The existing map is older than 14 days (staleness)
- A major structural change landed (new service, new datastore, new external integration)
What This Map Contains
| Section | What it captures | ID prefix |
|---|---|---|
applications | Deployable/runnable units: services, frontends, workers, CLIs, libraries | APP-NNN |
datastores | Persistence: postgres, redis, s3, sqlite, mongo, etc. | DS-NNN |
contracts | Interface/data shapes at boundaries: REST/GraphQL routes, events, RPC, shared types | CON-NNN |
integrations | External systems: third-party APIs, webhooks, queues, SaaS | INT-NNN |
IDs are stable cross-references: datastores[].ownedBy points at an APP-NNN, contracts[].boundary names APP-NNN -> APP-NNN, integrations[].usedBy points at an APP-NNN.
Full schema: references/output-schema.md · Realistic example: references/example.json
Process
Completion Tracking (MANDATORY)
Before starting, create one task per section so coverage is provable:
TaskCreate: "Staleness check + load prior map (preserve IDs)"TaskCreate: "Read upstream hints (codebase-index, engineering-definition)"TaskCreate: "Derive applications (APP-*)"TaskCreate: "Derive datastores (DS-*)"TaskCreate: "Derive contracts (CON-*)"TaskCreate: "Derive integrations (INT-*)"TaskCreate: "Write architecture-map.json (replace)"TaskCreate: "Verify cross-references resolve + no empty required sections"
Rules:
TaskUpdatetocompletedonly after the section holds verified, code-grounded data — not guesses.- The final task requires re-reading the written file and confirming every
ownedBy/usedBy/boundaryreference points at an ID that exists in the map. - An entity you cannot ground in a file/config gets
"confidence": "inferred"rather than being asserted as fact.
Step 0: Staleness Check & ID Preservation
# Does a map already exist, and how old is it?
ls -la .shipkit/architecture-map.json 2>/dev/null
- If it exists:
Readit first. This run is replace-on-rerun (the file is rewritten whole), but reuse existing IDs for entities that still exist so cross-references and external citations stay stable. Allocate new IDs (next free number per prefix) only for genuinely new entities. Do not renumber survivors. - If absent: start IDs at
APP-001,DS-001,CON-001,INT-001.
If the map exists and is less than 14 days old, tell the user the age and ask whether to refresh anyway (a structural change may justify it) before doing the full scan.
Step 1: Read Upstream Hints (context-derived layer)
Read these if present — they are hints, not the source of truth. The source of truth is the code.
.shipkit/codebase-index.json—framework,entryPoints,concepts(database/payments/api),directories. Maps concepts to files fast..shipkit/engineering-definition.json—components[], declared mechanisms, intended data contracts, chosen stack. Names the intended architecture; reconcile it against what the code actually shows.
Note any drift between intent (engineering-definition) and reality (code) in the relevant entity's notes.
Step 2: Derive from Code (primary source)
Scan the actual repo. Use the codebase-index skip/concepts to avoid wasted exploration. For a large repo, dispatch an Explore subagent per section to scan in parallel.
Applications (APP-*) — find runnable/deployable units:
- Package manifests:
package.json(per workspace/monorepo package),pyproject.toml,go.mod,Cargo.toml,pom.xml - Entry points:
main/index/appfiles,src/app(Next.js),cmd/(Go),__main__.py, server bootstraps, worker/queue consumers, CLI entrypoints (bin,scripts) - Containerisation:
Dockerfile,docker-compose.ymlservices,Procfile - Classify
kind:service|frontend|worker|cli|lib
Datastores (DS-*) — find persistence:
- Schema/migration files:
schema.prisma,migrations/,*.sql,alembic/,drizzle/ - Connection config:
DATABASE_URL, redis/mongo/s3 clients, ORM configs docker-compose.ymldata services (postgres, redis, mysql, mongo, minio)- Classify
kind(postgres/redis/s3/sqlite/...) and setownedByto the APP that connects to it
Contracts (CON-*) — find boundary shapes:
- HTTP routes/handlers:
src/app/api/**/route.ts, Express/Fastify routers, FastAPI/Flask routes, controllers - GraphQL:
schema.graphql, resolvers - Events/queues: publish/subscribe, topic/queue names
- Shared types at boundaries: Zod schemas, TS interfaces, JSON Schema, protobuf
- Set
boundary(APP-A -> APP-B, orexternal -> APP-Afor inbound public APIs),kind(rest/graphql/event/rpc/fn), andshape(a path to the schema/type, or a short description)
Integrations (INT-*) — find external systems:
- Third-party SDK imports (stripe, twilio, openai, sendgrid, aws-sdk, etc.)
- Outbound HTTP base URLs, webhook receivers, OAuth providers
- Message brokers / external queues
- Set
direction(inbound/outbound),kind(external-api/webhook/queue/saas),usedBy
Step 3: Verification Before Asserting
| Claim | Required check |
|---|---|
| "Application X exists" | A manifest/entrypoint/Dockerfile file is read and confirms a runnable unit |
| "Datastore Y is used" | A schema, migration, client init, or compose service is found |
| "Contract Z at boundary" | The route/handler/schema file is read and the shape located |
| "Integration W" | The SDK import or outbound endpoint is found in code |
Anything that cannot be grounded gets "confidence": "inferred" and a notes line explaining the inference. Never present an inferred entity as verified.
Step 4: Write the Map (replace-on-rerun)
Write the complete .shipkit/architecture-map.json with the Write tool (whole-file replace — do not append). Include:
{
"$schema": "shipkit-artifact",
"type": "architecture-map",
"version": "1.0",
"lastUpdated": "<ISO 8601 timestamp>",
"source": "shipkit-architecture-map",
"applications": [],
"datastores": [],
"contracts": [],
"integrations": []
}
If a section is genuinely empty for this repo (e.g. no external integrations), write [] — do not invent entries.
Step 5: Confirm to User
✅ Architecture map written to .shipkit/architecture-map.json
Applications: 3 (2 service, 1 frontend)
Datastores: 2 (postgres, redis)
Contracts: 7 (5 rest, 2 event)
Integrations: 2 (stripe, sendgrid)
This is the "what-is" map (current state). The "why" decisions log
lives separately in .shipkit/architecture.json — untouched.
Derivation Model
| Layer | Source | Role |
|---|---|---|
| Code scan (entrypoints, manifests, schema, routes, SDK imports) | the repo | Primary — ground truth |
codebase-index.json | .shipkit/ | Navigation hint (concept → files) |
engineering-definition.json | .shipkit/ | Intent hint; reconcile vs reality |
Prior architecture-map.json | .shipkit/ | ID stability across refreshes |
Principle: the map reflects what the code is, refreshed over time — not what was once designed. Where they diverge, record the divergence.
Context Files This Skill Reads
.shipkit/codebase-index.json— navigation hints (optional).shipkit/engineering-definition.json— intended architecture, components (optional).shipkit/architecture-map.json— prior run, for ID preservation (if exists)- Actual repo source — primary derivation
Does NOT read .shipkit/architecture.json (the decisions log is a separate concern).
Context Files This Skill Writes
.shipkit/architecture-map.json— complete replacement on each run (replace-on-rerun, like codebase-index). IDs preserved for surviving entities.
Completion Checklist
- Staleness checked; prior map loaded and IDs preserved (if any)
- Upstream hints read (codebase-index, engineering-definition) if present
- Applications derived and grounded in code
- Datastores derived and grounded in code
- Contracts derived and grounded in code
- Integrations derived and grounded in code
- Every cross-reference (
ownedBy/usedBy/boundary) resolves to an existing ID - Map written (whole-file replace) and re-read to verify
<!-- SECTION:after-completion -->
After Completion
Architecture map written to .shipkit/architecture-map.json.
Next (the map is a current-state input for downstream work):
/shipkit-spec— anchor a feature spec to the real applications/contracts it touches./shipkit-codebase-audit— cross-check the map against the code for orphaned apps, unwired contracts, or dead integrations./shipkit-engineering-definition— if the map reveals drift from intended architecture, revisit the engineering blueprint.
Refresh by re-running /shipkit-architecture-map after a structural change (new service, datastore, or external integration) or when the map is older than 14 days.
Note (v1 reachability): this skill is standalone / user-invocable. Wiring it as an automatic input into the orchestration loops is deferred to a later iteration.
<!-- /SECTION:after-completion -->