ANALYSIS.md
# Analysis Phases
## Phase 1: Scan the codebase
Launch **multiple `research` agents in parallel** to explore different facets of the codebase. Each agent focuses on a specific aspect so the combined output covers the full picture without any single agent running out of context.
**Agent 1a: Project identity and tech stack**
```
Explore the codebase at <path>. Answer with specifics — file paths, line numbers, version strings:
1. What is this project? What problem does it solve? Who is the intended user?
2. What is the tech stack?
- Languages (check file extensions, build configs, lockfiles)
- Frameworks (check imports, package.json, requirements.txt, go.mod, Cargo.toml, etc.)
- Databases (check connection strings, ORM configs, migration files)
- External services (check API client imports, SDK usage, webhook handlers)
3. What is the entry point? (main function, app bootstrap, CLI entrypoint, index file)
4. How is it built? (build scripts, Makefile, Dockerfile, CI config)
5. How is it deployed? (Dockerfile, serverless config, platform manifests, deploy scripts)
6. What does the dependency tree look like? (count of direct deps, any notable or unusual ones)
Read the actual lockfiles and config files — don't rely on the README alone.
If the README makes claims about the stack, verify each one against the source.
Return specific file paths for everything you reference.
```
**Agent 1b: Architecture and module structure**
```
Explore the codebase at <path>. Map the internal architecture:
1. What is the directory structure? (top 2–3 levels, with purpose of each directory)
2. What are the major modules/packages/components? For each one:
- Name and location
- Single-sentence purpose
- Key dependencies (what it imports from other internal modules)
3. How does data flow through the system?
- Where does input enter? (HTTP handler, CLI parser, message consumer, file watcher)
- Where is it processed? (business logic layer, service layer, domain models)
- Where does output go? (database, response, file, queue, external API)
4. What patterns does the code use?
- Architectural pattern (monolith, microservices, modular monolith, layered, event-driven)
- Design patterns visible in the code (repository pattern, middleware chain, plugin system, pub/sub)
- DON'T impose patterns that aren't there. If the code is a flat script, say so.
5. What are the cross-cutting concerns?
- Logging (what library, where configured)
- Error handling (centralized handler? per-route? unhandled?)
- Configuration (env vars, config files, defaults)
- Authentication/authorization if present
Return a module dependency list: which internal modules depend on which.
```
**Agent 1c: API and external interface inventory**
```
Explore the codebase at <path>. Produce a COMPLETE inventory of external interfaces:
1. HTTP/REST endpoints:
- Method, path, handler function, file:line
- Any route parameters, query parameters, or request body shape
- Authentication requirement (if visible from middleware or decorators)
- Group by router/module/resource
2. CLI commands (if applicable):
- Command name, description, arguments, flags
- Handler function and file:line
3. GraphQL operations (if applicable):
- Queries, mutations, subscriptions with their types
4. gRPC services (if applicable):
- Service name, RPC methods, request/response types
5. WebSocket handlers (if applicable):
- Event names, payload shapes
6. Exported library API (if this is a library/package):
- Exported functions, classes, types
- Public vs internal API boundary
7. Background jobs / scheduled tasks / message consumers:
- What triggers them, what they do, where defined
8. Webhooks / callbacks (incoming):
- Endpoint, expected payload, what triggers it externally
Be EXHAUSTIVE for categories that apply. Skip categories that don't exist in this codebase.
Return exact file paths and line numbers for every interface found.
```
### Synthesizing Phase 1 outputs
Collect all three agents' outputs. Before proceeding, verify consistency:
- If Agent 1a says "uses PostgreSQL" but Agent 1b found no database module, investigate.
- If Agent 1c found endpoints that Agent 1b didn't mention in the module map, update the module map.
- If any agent reports "unclear" or "not found", note it as a gap — don't fill it with assumptions.
Compile the raw findings into a working document you'll use in Phase 2. This intermediate document is NOT written to disk — it's your working memory for synthesis.
## Phase 2: Synthesize into SUMMARY.md
Using the combined Phase 1 outputs, write `<output-dir>/SUMMARY.md` with this structure:
```markdown
# Codebase Summary: <project-name>
## Overview
<2–4 sentences: what this project is, who it's for, and what problem it solves.
If there's a discrepancy between the README and the actual code, note it.>
## Tech Stack
| Layer | Technology | Evidence |
|-------|-----------|----------|
| Language | e.g. TypeScript 5.x | tsconfig.json, package.json |
| Framework | e.g. Express 4.18 | package.json, src/app.ts |
| Database | e.g. PostgreSQL via Prisma | prisma/schema.prisma |
| ... | ... | ... |
<Only include layers that exist. "Evidence" = the file that proves it.>
## Architecture
<Prose description of the architecture: 1–3 paragraphs depending on complexity.
Describe the actual pattern (not the aspirational one).
Cover: entry point → request/data flow → business logic → persistence → response.
Mention any notable architectural decisions or tradeoffs.>
### Architecture Diagram
```mermaid
<Mermaid diagram here — see diagram rules below>
```
## Module Map
<For each major module/package/directory:>
### <module-name> (`path/to/module/`)
<1–2 sentences: what it does and why it exists.>
- **Key files**: list 2–3 most important files with one-line descriptions
- **Internal dependencies**: which other modules it imports
- **External dependencies**: notable third-party packages it uses
## API Reference
<Organized by category. Only include categories that exist.>
### HTTP Endpoints
| Method | Path | Handler | Auth | Description |
|--------|------|---------|------|-------------|
| GET | /api/users | getUsers (src/routes/users.ts:24) | Required | List all users |
| ... | ... | ... | ... | ... |
### CLI Commands
| Command | Description | Handler |
|---------|-------------|---------|
| ... | ... | ... |
<Add sections for GraphQL, gRPC, WebSocket, library exports, background jobs
as applicable. Omit sections that don't apply.>
## Configuration & Environment
<What env vars does this project need? What config files does it read?
What external services does it depend on at runtime?>
## Build & Deploy
<How to build, test, and deploy. Based on actual scripts/configs found,
not README instructions that may be outdated.>
## Observations
<Brief notes on:
- Code quality patterns (consistent style? tests? type safety?)
- Gaps or concerns noticed during analysis (dead code, missing error handling, etc.)
- Areas that would benefit from deeper investigation>
```
### Mermaid diagram rules
The architecture diagram must follow these constraints:
1. **Match the prose.** Every box in the diagram must correspond to something described in the text. No mystery boxes.
2. **Use the right diagram type.**
- `graph TD` (top-down) for request/data flow
- `graph LR` (left-right) for pipeline/processing chains
- `C4Context` or `C4Container` for system-level views of larger projects
- Choose based on what the architecture actually looks like
3. **Label edges.** Every arrow should say what flows along it (HTTP, SQL, events, function calls).
4. **Group related components.** Use `subgraph` for logical groupings (e.g., "API Layer", "Data Layer").
5. **Keep it readable.** 5–15 nodes is the sweet spot. If you need more, you're at the wrong abstraction level — zoom out.
6. **No aspirational components.** Only diagram what exists in the code right now.
## Phase 3: Structure and validate
Produce `<output-dir>/summary.json` conforming to the schema in `summary-schema.json` (in this skill's directory — read it before writing output).
### Steps
1. **Read `summary-schema.json`** from this skill's directory. Follow it exactly — `additionalProperties: false` is enforced.
2. **Populate every required field.** Key rules:
- `tech_stack` entries must have `evidence_file` — a real file path you verified exists
- `modules` must include `dependencies` (internal module references) — empty array if none
- `api_endpoints` must have `file` and `line` — if you can't cite the exact location, go back and verify before including it
- `architecture_pattern` must be one of the allowed enum values. If the code doesn't fit any cleanly, use `"other"` and explain in `architecture_description`
3. **Run the validator:**
```
node <skill-dir>/validate-summary.cjs <output-dir>/summary.json
```
Fix any failures before finishing. The validator checks structural conformance only — it doesn't verify that your claims are accurate (that's your responsibility from Phase 1).
4. **Cross-check against SUMMARY.md.** The JSON and the markdown must agree. If the markdown lists 12 endpoints and the JSON has 8, one of them is wrong. Reconcile before delivering.
SKILL.md
---
name: codebase-summary
description: Generate a structured summary of any codebase — architecture overview, tech stack, module map, and full API inventory with a Mermaid diagram. Use when asked to summarize a codebase, explain a project structure, map an API surface, generate architecture documentation, onboard onto a new repo, or produce a technical overview. Triggers on phrases like "summarize this codebase", "what does this project do", "map the architecture", "list all endpoints", "give me an overview", "document this repo", or any request to understand an unfamiliar codebase. Also use when someone uploads or points at a project directory and asks "what is this?" or "how is this structured?"
---
# Codebase Summary
You are a technical analyst. Your job is to produce a clear, accurate, structured summary of a codebase — the kind of document that lets a new engineer understand the project in 10 minutes.
## Platform terminology
This skill is agent-neutral. In the methodology:
- **Task tool** means the coding agent's delegation or sub-agent mechanism.
- **`research` agent** means a delegated agent optimized for focused codebase exploration.
- **`subagent_type`** means the equivalent delegated-agent role supported by the current platform.
Use the platform's equivalent capabilities while preserving the specified roles, parallelism, and prompts.
## Setup
Before starting, establish two paths:
- **Target**: the codebase to analyze (from the user's request or the current working directory)
- **Output directory**: where all artifacts go. Ask the user if not specified, or default to `~/codebase-summary/<repo-name>/run-<N>` where `<N>` is the next unused integer. Create it if it doesn't exist.
All files written during the analysis go in the output directory:
- `SUMMARY.md` — human-readable summary with architecture diagram (Phase 2)
- `summary.json` — machine-readable structured output (Phase 3)
Subagents do NOT write files — they return results to you via the Task tool. You write all files.
## Core Principles
### Accuracy over completeness
Report what you can verify by reading the code. If a module's purpose is unclear, say so — don't guess. An honest "purpose unclear from code inspection" is better than a plausible-sounding fabrication.
### Follow the code, not the README
READMEs go stale. If the README says "supports PostgreSQL and MySQL" but the code only imports `pg`, report what the code shows and note the discrepancy. The README is a hypothesis; the source code is the truth.
### Calibrate depth to the codebase
A 200-line CLI tool needs a paragraph, not a 10-page report. A monorepo with 15 services needs more. Match the output to the input. Padding a summary to look thorough is the same failure mode as padding a security report.
### APIs mean all external interfaces
"API" isn't just REST endpoints. It includes CLI commands, exported library functions, gRPC services, WebSocket handlers, message queue consumers, scheduled jobs — anything an external caller or system interacts with. Inventory them all.
## Workflow overview
Follow all three phases in order. Read the referenced files from this skill's directory before executing each phase.
1. **Scan** — Run Phase 1 from [ANALYSIS.md](ANALYSIS.md) to explore the codebase with parallel research agents. Produces raw intelligence about the project.
2. **Synthesize** — Run Phase 2 from [ANALYSIS.md](ANALYSIS.md) to combine agent outputs into `SUMMARY.md` with a Mermaid architecture diagram.
3. **Structure & Validate** — Run Phase 3 from [ANALYSIS.md](ANALYSIS.md) to produce `summary.json` conforming to `summary-schema.json`, validated by `validate-summary.cjs`.
## Anti-Patterns to Avoid
1. **Listing files without explaining purpose.** A directory tree is not a summary. Every module mentioned needs a one-sentence explanation of what it does and why it exists.
2. **Copying the README as the summary.** The README is an input, not the output. Your job is to verify claims against the actual code.
3. **Inventing architecture patterns.** If the code doesn't have a clear MVC separation, don't impose one. Describe what's there, not what should be there.
4. **Missing the actual entry points.** Every codebase has a "start here" — `main()`, `app.listen()`, `if __name__`, the CLI entrypoint. Find it. If you can't find it, that's a finding worth reporting.
5. **Ignoring configuration and environment.** What env vars does it need? What config files does it read? What external services does it connect to? These are part of the architecture.
6. **Over-documenting trivial code.** A `utils/formatDate.js` doesn't need its own section. Group utilities and mention them in aggregate.
7. **Generating a Mermaid diagram that doesn't match the prose.** The diagram and the written summary must describe the same architecture. If they disagree, one of them is wrong.
summary-schema.json
{
"$comment": "Single source of truth for summary.json structure (see SKILL.md Phase 3). validate-summary.cjs reads this file directly.",
"output_schema": {
"type": "object",
"properties": {
"project_name": {
"type": "string",
"description": "Name of the project (from package.json, Cargo.toml, directory name, etc.)"
},
"description": {
"type": "string",
"description": "2-4 sentence plain-language description of what the project does and who it's for."
},
"entry_point": {
"type": "string",
"description": "Relative file path to the main entry point (e.g. src/index.ts, main.py, cmd/server/main.go)."
},
"architecture_pattern": {
"type": "string",
"enum": [
"monolith",
"modular_monolith",
"microservices",
"serverless",
"cli_tool",
"library",
"pipeline",
"event_driven",
"plugin_based",
"static_site",
"other"
],
"description": "The dominant architectural pattern observed in the code."
},
"architecture_description": {
"type": "string",
"description": "1-3 paragraph prose description of the architecture, covering data flow and key design decisions."
},
"architecture_diagram_mermaid": {
"type": "string",
"description": "Complete Mermaid diagram source code for the architecture (graph TD, graph LR, C4Context, etc.)."
},
"tech_stack": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"layer": {
"type": "string",
"enum": [
"language",
"framework",
"database",
"orm",
"cache",
"queue",
"search",
"auth",
"cloud_platform",
"containerization",
"ci_cd",
"testing",
"monitoring",
"other"
]
},
"technology": {
"type": "string",
"description": "Technology name and version if known (e.g. 'Express 4.18', 'Python 3.11')."
},
"evidence_file": {
"type": "string",
"description": "Relative file path that proves this technology is used (e.g. 'package.json', 'requirements.txt')."
}
},
"required": ["layer", "technology", "evidence_file"],
"additionalProperties": false
}
},
"modules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Module/package/directory name."
},
"path": {
"type": "string",
"description": "Relative path to the module root."
},
"purpose": {
"type": "string",
"description": "Single sentence explaining what this module does."
},
"key_files": {
"type": "array",
"items": {
"type": "string"
},
"description": "2-5 most important files in the module (relative paths)."
},
"dependencies": {
"type": "array",
"items": {
"type": "string"
},
"description": "Names of other internal modules this module depends on. Empty array if none."
}
},
"required": ["name", "path", "purpose", "key_files", "dependencies"],
"additionalProperties": false
}
},
"api_endpoints": {
"type": "array",
"items": {
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": [
"http",
"graphql",
"grpc",
"websocket",
"cli",
"library_export",
"background_job",
"webhook",
"message_consumer",
"other"
]
},
"method": {
"type": "string",
"description": "HTTP method, CLI command name, gRPC method, etc. Use 'N/A' for categories where method doesn't apply."
},
"path": {
"type": "string",
"description": "URL path, command string, function signature, event name, etc."
},
"handler": {
"type": "string",
"description": "Handler function or method name."
},
"file": {
"type": "string",
"description": "Relative file path where the handler is defined."
},
"line": {
"type": "integer",
"description": "Line number where the handler is defined."
},
"auth_required": {
"type": "string",
"enum": ["yes", "no", "unknown"],
"description": "Whether authentication is required. 'unknown' if not determinable from code inspection."
},
"description": {
"type": "string",
"description": "One-line description of what this endpoint does."
}
},
"required": ["category", "method", "path", "handler", "file", "line", "auth_required", "description"],
"additionalProperties": false
}
},
"configuration": {
"type": "object",
"properties": {
"env_vars": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"required": {
"type": "string",
"enum": ["yes", "no", "unknown"]
},
"description": {
"type": "string"
}
},
"required": ["name", "required", "description"],
"additionalProperties": false
}
},
"config_files": {
"type": "array",
"items": {
"type": "string"
},
"description": "Relative paths to configuration files the project reads."
},
"external_services": {
"type": "array",
"items": {
"type": "string"
},
"description": "External services the project connects to at runtime (databases, APIs, queues, etc.)."
}
},
"required": ["env_vars", "config_files", "external_services"],
"additionalProperties": false
},
"observations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["quality", "gap", "notable", "concern"]
},
"description": {
"type": "string"
}
},
"required": ["category", "description"],
"additionalProperties": false
},
"description": "Noteworthy observations about code quality, gaps, or patterns."
}
},
"required": [
"project_name",
"description",
"entry_point",
"architecture_pattern",
"architecture_description",
"architecture_diagram_mermaid",
"tech_stack",
"modules",
"api_endpoints",
"configuration",
"observations"
],
"additionalProperties": false
}
}
validate-summary.cjs
#!/usr/bin/env node
/**
* Validates summary.json against summary-schema.json.
* Usage: node validate-summary.cjs <path-to-summary.json>
*
* The validation rules live in summary-schema.json — the single source of truth.
* This script reads that schema at runtime and interprets the subset of JSON
* Schema it uses: type, properties, required, additionalProperties:false,
* enum, items, and minItems.
*
* Zero dependencies. Exits 0 on success, 1 on validation failure.
*/
const fs = require("fs");
const path = require("path");
const file = process.argv[2];
if (!file) {
console.error("Usage: node validate-summary.cjs <path-to-summary.json>");
process.exit(1);
}
const schemaPath = path.join(__dirname, "summary-schema.json");
let rootSchema;
try {
const doc = JSON.parse(fs.readFileSync(schemaPath, "utf8"));
rootSchema = doc.output_schema;
if (!rootSchema) throw new Error('summary-schema.json is missing top-level "output_schema"');
} catch (e) {
console.error(`Failed to load schema from ${schemaPath}:`, e.message);
process.exit(1);
}
let summary;
try {
summary = JSON.parse(fs.readFileSync(file, "utf8"));
} catch (e) {
console.error("Failed to parse JSON:", e.message);
process.exit(1);
}
// --- Generic JSON Schema interpreter ---
function typeOf(v) {
if (Array.isArray(v)) return "array";
if (v === null) return "null";
return typeof v;
}
function validate(value, schema, p, errors) {
if (schema.enum && !schema.enum.includes(value)) {
const allowed = schema.enum.map((v) => JSON.stringify(v)).join(", ");
errors.push(`${p}: invalid value ${JSON.stringify(value)} (expected one of ${allowed})`);
}
switch (schema.type) {
case "object": {
if (typeOf(value) !== "object") {
errors.push(`${p}: expected object, got ${typeOf(value)}`);
return;
}
for (const req of schema.required || []) {
if (!(req in value)) errors.push(`${p}: missing required field "${req}"`);
}
for (const key of Object.keys(value)) {
if (schema.properties && key in schema.properties) {
validate(value[key], schema.properties[key], `${p}.${key}`, errors);
} else if (schema.additionalProperties === false) {
errors.push(`${p}: unexpected field "${key}"`);
}
}
break;
}
case "array": {
if (typeOf(value) !== "array") {
errors.push(`${p}: expected array, got ${typeOf(value)}`);
return;
}
if (typeof schema.minItems === "number" && value.length < schema.minItems) {
errors.push(`${p}: must have at least ${schema.minItems} item(s), got ${value.length}`);
}
if (schema.items) {
value.forEach((el, i) => validate(el, schema.items, `${p}[${i}]`, errors));
}
break;
}
case "integer": {
if (typeOf(value) !== "number" || !Number.isInteger(value)) {
errors.push(`${p}: expected integer, got ${typeOf(value)}`);
}
break;
}
case "string": {
if (typeOf(value) !== "string") {
errors.push(`${p}: expected string, got ${typeOf(value)}`);
}
break;
}
default:
break;
}
}
// --- Semantic validations beyond schema structure ---
function semanticChecks(summary, errors) {
// Check: architecture_diagram_mermaid should contain a mermaid diagram keyword
if (summary.architecture_diagram_mermaid) {
const diagram = summary.architecture_diagram_mermaid.trim();
const validStarts = [
"graph ", "graph\n",
"flowchart ", "flowchart\n",
"sequenceDiagram", "classDiagram", "stateDiagram",
"erDiagram", "gantt", "pie", "gitGraph",
"C4Context", "C4Container", "C4Component", "C4Deployment",
"mindmap", "timeline", "block-beta",
];
const hasValidStart = validStarts.some((s) => diagram.startsWith(s));
if (!hasValidStart) {
errors.push(
`root.architecture_diagram_mermaid: does not appear to start with a valid Mermaid diagram type`
);
}
}
// Check: api_endpoints with category "http" should have a real HTTP method
if (Array.isArray(summary.api_endpoints)) {
const httpMethods = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
summary.api_endpoints.forEach((ep, i) => {
if (ep.category === "http" && ep.method) {
if (!httpMethods.includes(ep.method.toUpperCase())) {
errors.push(
`root.api_endpoints[${i}].method: HTTP endpoint should use a standard HTTP method, got "${ep.method}"`
);
}
}
});
}
// Check: modules should have unique names
if (Array.isArray(summary.modules)) {
const names = summary.modules.map((m) => m.name);
const dupes = names.filter((n, i) => names.indexOf(n) !== i);
if (dupes.length > 0) {
errors.push(`root.modules: duplicate module names found: ${[...new Set(dupes)].join(", ")}`);
}
}
// Check: tech_stack should have at least one "language" layer
if (Array.isArray(summary.tech_stack)) {
const hasLanguage = summary.tech_stack.some((t) => t.layer === "language");
if (!hasLanguage) {
errors.push(`root.tech_stack: should include at least one entry with layer "language"`);
}
}
}
// --- Run ---
const errors = [];
console.log("Validating summary.json against schema...\n");
// Schema validation
validate(summary, rootSchema, "root", errors);
// Semantic validation
if (errors.length === 0) {
semanticChecks(summary, errors);
}
// Report
if (errors.length === 0) {
const stats = {
tech_stack: (summary.tech_stack || []).length,
modules: (summary.modules || []).length,
api_endpoints: (summary.api_endpoints || []).length,
env_vars: (summary.configuration && summary.configuration.env_vars || []).length,
observations: (summary.observations || []).length,
};
console.log("PASS: summary.json is valid\n");
console.log("Summary statistics:");
console.log(` Tech stack entries: ${stats.tech_stack}`);
console.log(` Modules: ${stats.modules}`);
console.log(` API endpoints: ${stats.api_endpoints}`);
console.log(` Environment vars: ${stats.env_vars}`);
console.log(` Observations: ${stats.observations}`);
} else {
for (const msg of errors) console.error(" ERROR:", msg);
console.error(`\nFAIL: ${errors.length} error(s)`);
process.exit(1);
}