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.json exists 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:
TaskUpdate to completed only after the section holds verified, code-grounded data — not guesses.
- The final task requires re-reading the written file and confirming every
ownedBy / usedBy / boundary reference 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:
Read it 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/app files, src/app (Next.js), cmd/ (Go), __main__.py, server bootstraps, worker/queue consumers, CLI entrypoints (bin, scripts)
- Containerisation:
Dockerfile, docker-compose.yml services, 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.yml data services (postgres, redis, mysql, mongo, minio)
- Classify
kind (postgres/redis/s3/sqlite/...) and set ownedBy to 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, or external -> APP-A for inbound public APIs), kind (rest/graphql/event/rpc/fn), and shape (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
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.
1---2name: shipkit-architecture-map3description: 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'.4---56# shipkit-architecture-map — Living Architecture Map78**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.910**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).1112---1314## When to Invoke1516**User triggers**:17- "Map the architecture"18- "What does the system currently look like?"19- "Refresh the architecture map"20- "Show me applications / datastores / contracts / integrations"2122**Auto-suggested when**:23- No `.shipkit/architecture-map.json` exists and the repo has real source code24- The existing map is older than **14 days** (staleness)25- A major structural change landed (new service, new datastore, new external integration)2627---2829## What This Map Contains3031| Section | What it captures | ID prefix |32|---------|------------------|-----------|33| `applications` | Deployable/runnable units: services, frontends, workers, CLIs, libraries | `APP-NNN` |34| `datastores` | Persistence: postgres, redis, s3, sqlite, mongo, etc. | `DS-NNN` |35| `contracts` | Interface/data shapes at boundaries: REST/GraphQL routes, events, RPC, shared types | `CON-NNN` |36| `integrations` | External systems: third-party APIs, webhooks, queues, SaaS | `INT-NNN` |3738IDs 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`.3940**Full schema:** `references/output-schema.md` · **Realistic example:** `references/example.json`4142---4344## Process4546### Completion Tracking (MANDATORY)4748Before starting, create one task per section so coverage is provable:49501. `TaskCreate`: "Staleness check + load prior map (preserve IDs)"512. `TaskCreate`: "Read upstream hints (codebase-index, engineering-definition)"523. `TaskCreate`: "Derive applications (APP-*)"534. `TaskCreate`: "Derive datastores (DS-*)"545. `TaskCreate`: "Derive contracts (CON-*)"556. `TaskCreate`: "Derive integrations (INT-*)"567. `TaskCreate`: "Write architecture-map.json (replace)"578. `TaskCreate`: "Verify cross-references resolve + no empty required sections"5859**Rules**:60- `TaskUpdate` to `completed` only after the section holds verified, code-grounded data — not guesses.61- The final task requires re-reading the written file and confirming every `ownedBy` / `usedBy` / `boundary` reference points at an ID that exists in the map.62- An entity you cannot ground in a file/config gets `"confidence": "inferred"` rather than being asserted as fact.6364### Step 0: Staleness Check & ID Preservation6566```bash67# Does a map already exist, and how old is it?68ls -la .shipkit/architecture-map.json 2>/dev/null69```7071- **If it exists**: `Read` it 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.72- **If absent**: start IDs at `APP-001`, `DS-001`, `CON-001`, `INT-001`.7374If 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.7576### Step 1: Read Upstream Hints (context-derived layer)7778Read these if present — they are *hints*, not the source of truth. The source of truth is the code.7980- `.shipkit/codebase-index.json` — `framework`, `entryPoints`, `concepts` (database/payments/api), `directories`. Maps concepts to files fast.81- `.shipkit/engineering-definition.json` — `components[]`, declared mechanisms, intended data contracts, chosen stack. Names the *intended* architecture; reconcile it against what the code actually shows.8283Note any drift between intent (engineering-definition) and reality (code) in the relevant entity's `notes`.8485### Step 2: Derive from Code (primary source)8687Scan 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.8889**Applications (APP-*)** — find runnable/deployable units:90- Package manifests: `package.json` (per workspace/monorepo package), `pyproject.toml`, `go.mod`, `Cargo.toml`, `pom.xml`91- Entry points: `main`/`index`/`app` files, `src/app` (Next.js), `cmd/` (Go), `__main__.py`, server bootstraps, worker/queue consumers, CLI entrypoints (`bin`, `scripts`)92- Containerisation: `Dockerfile`, `docker-compose.yml` services, `Procfile`93- Classify `kind`: `service` | `frontend` | `worker` | `cli` | `lib`9495**Datastores (DS-*)** — find persistence:96- Schema/migration files: `schema.prisma`, `migrations/`, `*.sql`, `alembic/`, `drizzle/`97- Connection config: `DATABASE_URL`, redis/mongo/s3 clients, ORM configs98- `docker-compose.yml` data services (postgres, redis, mysql, mongo, minio)99- Classify `kind` (postgres/redis/s3/sqlite/...) and set `ownedBy` to the APP that connects to it100101**Contracts (CON-*)** — find boundary shapes:102- HTTP routes/handlers: `src/app/api/**/route.ts`, Express/Fastify routers, FastAPI/Flask routes, controllers103- GraphQL: `schema.graphql`, resolvers104- Events/queues: publish/subscribe, topic/queue names105- Shared types at boundaries: Zod schemas, TS interfaces, JSON Schema, protobuf106- Set `boundary` (`APP-A -> APP-B`, or `external -> APP-A` for inbound public APIs), `kind` (rest/graphql/event/rpc/fn), and `shape` (a path to the schema/type, or a short description)107108**Integrations (INT-*)** — find external systems:109- Third-party SDK imports (stripe, twilio, openai, sendgrid, aws-sdk, etc.)110- Outbound HTTP base URLs, webhook receivers, OAuth providers111- Message brokers / external queues112- Set `direction` (inbound/outbound), `kind` (external-api/webhook/queue/saas), `usedBy`113114### Step 3: Verification Before Asserting115116| Claim | Required check |117|-------|----------------|118| "Application X exists" | A manifest/entrypoint/Dockerfile file is read and confirms a runnable unit |119| "Datastore Y is used" | A schema, migration, client init, or compose service is found |120| "Contract Z at boundary" | The route/handler/schema file is read and the shape located |121| "Integration W" | The SDK import or outbound endpoint is found in code |122123Anything that cannot be grounded gets `"confidence": "inferred"` and a `notes` line explaining the inference. Never present an inferred entity as verified.124125### Step 4: Write the Map (replace-on-rerun)126127Write the **complete** `.shipkit/architecture-map.json` with the Write tool (whole-file replace — do not append). Include:128129```json130{131 "$schema": "shipkit-artifact",132 "type": "architecture-map",133 "version": "1.0",134 "lastUpdated": "<ISO 8601 timestamp>",135 "source": "shipkit-architecture-map",136 "applications": [],137 "datastores": [],138 "contracts": [],139 "integrations": []140}141```142143If a section is genuinely empty for this repo (e.g. no external integrations), write `[]` — do not invent entries.144145### Step 5: Confirm to User146147```148✅ Architecture map written to .shipkit/architecture-map.json149150Applications: 3 (2 service, 1 frontend)151Datastores: 2 (postgres, redis)152Contracts: 7 (5 rest, 2 event)153Integrations: 2 (stripe, sendgrid)154155This is the "what-is" map (current state). The "why" decisions log156lives separately in .shipkit/architecture.json — untouched.157```158159---160161## Derivation Model162163| Layer | Source | Role |164|-------|--------|------|165| Code scan (entrypoints, manifests, schema, routes, SDK imports) | the repo | **Primary** — ground truth |166| `codebase-index.json` | `.shipkit/` | Navigation hint (concept → files) |167| `engineering-definition.json` | `.shipkit/` | Intent hint; reconcile vs reality |168| Prior `architecture-map.json` | `.shipkit/` | ID stability across refreshes |169170**Principle**: the map reflects what the code *is*, refreshed over time — not what was once designed. Where they diverge, record the divergence.171172---173174## Context Files This Skill Reads175176- `.shipkit/codebase-index.json` — navigation hints (optional)177- `.shipkit/engineering-definition.json` — intended architecture, components (optional)178- `.shipkit/architecture-map.json` — prior run, for ID preservation (if exists)179- Actual repo source — primary derivation180181**Does NOT read** `.shipkit/architecture.json` (the decisions log is a separate concern).182183## Context Files This Skill Writes184185- `.shipkit/architecture-map.json` — **complete replacement on each run** (replace-on-rerun, like codebase-index). IDs preserved for surviving entities.186187---188189## Completion Checklist190191- [ ] Staleness checked; prior map loaded and IDs preserved (if any)192- [ ] Upstream hints read (codebase-index, engineering-definition) if present193- [ ] Applications derived and grounded in code194- [ ] Datastores derived and grounded in code195- [ ] Contracts derived and grounded in code196- [ ] Integrations derived and grounded in code197- [ ] Every cross-reference (`ownedBy`/`usedBy`/`boundary`) resolves to an existing ID198- [ ] Map written (whole-file replace) and re-read to verify199200---201202<!-- SECTION:after-completion -->203## After Completion204205Architecture map written to `.shipkit/architecture-map.json`.206207**Next** (the map is a current-state input for downstream work):208- `/shipkit-spec` — anchor a feature spec to the real applications/contracts it touches.209- `/shipkit-codebase-audit` — cross-check the map against the code for orphaned apps, unwired contracts, or dead integrations.210- `/shipkit-engineering-definition` — if the map reveals drift from intended architecture, revisit the engineering blueprint.211212**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.213214**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.215<!-- /SECTION:after-completion -->