원클릭으로
repomap
Generate architectural maps of repositories as RepoGraph JSON using local deterministic analysis, and serve interactive visualizations
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Generate architectural maps of repositories as RepoGraph JSON using local deterministic analysis, and serve interactive visualizations
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | repomap |
| description | Generate architectural maps of repositories as RepoGraph JSON using local deterministic analysis, and serve interactive visualizations |
| license | MIT |
| compatibility | opencode |
| metadata | {"type":"analysis","output":"json"} |
Before using this skill, ensure the required packages are installed:
# Dependencies for the analyzer (glob for file matching):
cd ~/.opencode/skills/repomap && npm install
# Visual server (auto-installed via npx on first serve):
npm install -g @frannn2114/repomap-visual
The serve action will auto-install the visual package via npx if missing.
Analyzes a repository and returns a RawAnalysis JSON object with deterministic
structural data (modules, files, imports, definitions, edges). The agent must then
use an LLM call to enrich it with semantic interpretation (roles, patterns, labels).
Input:
localPath (string, optional) — Path to a local repositoryrepoUrl (string, optional) — GitHub repository URL (e.g. https://github.com/owner/repo)githubToken (string, optional) — GitHub token for private reposoutputFile (string, optional) — Write the raw analysis JSON to a file pathresumeFrom (object, optional) — Previous analysis progress to resume fromAt least one of localPath or repoUrl must be provided.
How to execute:
getGitData).analyzeRepository from ./analyzer.js:
import { analyzeRepository } from './analyzer.js'
const raw = await analyzeRepository({ localPath, repoUrl, githubToken, resumeFrom, outputFile })
raw object contains modules, fileData, nodes, edges, and meta.detectedRole to each module (presentation, api_gateway, business_logic,
data_access, authentication, configuration, utility, testing, middleware, messaging,
caching, background_jobs, security, observability, database_migration, unknown)vertical_layers | horizontal_three_column | concentric_rings |
left_right_flow | grid_clusters | force_directedRepoGraph:
const nodesWithRoles = raw.nodes.map(node => ({
...node,
detectedRole: llmRoles[node.id] || 'unknown',
patterns: llmPatterns[node.id] || [],
}))
const graph = {
meta: {
...raw.meta,
detectedPattern: llmPattern,
layoutTemplate: llmLayout,
patternConfidence: llmConfidence,
},
nodes: nodesWithRoles,
edges: raw.edges,
overlay: { version: 0, nodeOverrides: {}, edgeOverrides: {}, manualNodes: [], manualEdges: [] },
}
git field if the user opted in (step 1):
if (gitData) {
graph.git = gitData
}
RepoGraph to the user.Analyzes a repository, persists the RepoGraph to ~/.repomap/maps/, and starts
the visual server. Maps are stored persistently and can be re-opened later via
open or the CLI.
Input:
localPath (string, optional) — Path to a local repositoryrepoUrl (string, optional) — GitHub repository URLgithubToken (string, optional) — GitHub token for private reposport (number, optional, default 3000) — Port for the serverHow to execute: 0. Before starting the analysis, the agent MUST ask the user: "Do you want to include git data (branches and commits) in the repository map?"
getGitData).serve(input). It analyzes, persists to ~/.repomap/maps/, and starts
the visual server automatically.http://localhost:<port>.node cli.js open <repoName>
Returns a list of all saved maps with metadata (name, date, node count, etc.).
How to execute:
import { list } from './index.js'
const maps = list()
// maps = [{ name, repoName, createdAt, detectedPattern, nodeCount, fileName }]
Opens a previously saved map by name (repo name, partial match, or file name) and starts the visual server. If no name is given, opens the most recent map.
Input:
name (string, optional) — Repo name, file name, or partial matchport (number, optional, default 3000) — Port for the serverHow to execute:
import { open } from './index.js'
const result = await open({ name: 'my-project' })
// result = { url, pid, mapPath } or { error, matches? }
The deterministric analysis produces a RawAnalysis JSON object:
{
"meta": {
"repoUrl": "local://my-project",
"repoName": "my-project",
"analysisVersion": "a1b2c3d4",
"analyzedAt": "2026-01-15T10:30:00.000Z",
"estimatedSize": "medium",
"languages": ["Python", "TypeScript"],
"totalFiles": 42,
"totalModules": 8
},
"modules": [
{
"id": "module__backend_api",
"label": "Api",
"layerId": "layer__backend",
"layerLabel": "Backend",
"fileCount": 5,
"filePaths": ["backend/api/routes.py", "backend/api/deps.py"]
}
],
"fileData": {
"backend/api/routes.py": {
"language": "Python",
"lineCount": 120,
"imports": ["fastapi", "app.services.users"],
"definitions": [
{ "name": "router", "type": "const" },
{ "name": "get_users", "type": "function",
"params": [{ "name": "user_id", "type": "int" }, { "name": "limit", "type": "int", "optional": true }],
"returns": "list[User]"
}
]
}
},
"nodes": [
{ "id": "layer__presentation", "label": "Presentation", "type": "layer", "depth": 0, "parentId": null, "files": [], "metadata": {} },
{ "id": "module__auth", "label": "Auth", "type": "module", "parentId": "layer__presentation", "depth": 1, "files": ["src/auth.ts"], "metadata": {} },
{ "id": "file__src_auth_ts", "label": "auth.ts", "type": "file", "parentId": "module__auth", "depth": 2, "files": ["src/auth.ts"], "metadata": {} }
],
"edges": [
{ "id": "edge_1", "source": "file__src_auth_ts", "target": "file__src_api_ts", "edgeType": "engineering", "strength": 3, "label": "imports", "confidence": "high" }
]
}
The analyzer extracts function/method signatures from source code deterministically (regex, no LLM):
| Convention | Languages |
|---|---|
name: type | TypeScript, JavaScript, Python, Rust, Swift, PHP, Ruby |
name type | Go |
type name | Java, C#, C++, Dart, Kotlin, Scala |
Fields per definition: params: [{ name, type?, optional? }], returns: string | undefined
No external dependencies beyond glob.
The agent must ask the user before analyzing whether they want git data (see analyze/serve actions above).
If the user says yes, follow this workflow:
maxCommits > 60, the agent must ask the user for a GitHub token (API rate limit: 60 req/h without token, 5000/h with token).getGitData({ localPath, repoUrl, githubToken, maxCommits }) which returns { branches: [{ name, current }], commits: [{ hash, message, author, date, files: [{ path, status }] }] } or null if not a git repo.git field in the final RepoGraph JSON.Agent workflow for this step:
if (gitData) {
graph.git = gitData
}
The RawAnalysis is meant to be fed to an LLM (without sending source code) to
produce the semantic interpretation. The agent now receives full function signatures
(params + return types), giving richer context for role assignment and pattern detection
without any extra token cost. Build a prompt with the module/file/import data and request:
presentation, api_gateway, business_logic, data_access, authentication,
configuration, utility, testing, middleware, messaging, caching,
background_jobs, security, observability, database_migration, unknownrepository_pattern, factory_pattern, etc.)clean_architecture, hexagonal, mvc,
layered_monolith, microservices, feature_modules, pipeline_etl, unknownvertical_layers, horizontal_three_column,
concentric_rings, left_right_flow, grid_clusters, force_directedMerge the LLM response into the final RepoGraph with this structure:
{
"meta": {
"repoUrl": "local://my-project",
"repoName": "my-project",
"analysisVersion": "a1b2c3d4",
"analyzedAt": "2026-01-15T10:30:00.000Z",
"detectedPattern": "layered_monolith",
"layoutTemplate": "vertical_layers",
"patternConfidence": 0.85
},
"nodes": [
{ "id": "layer__presentation", "label": "Presentation", "type": "layer", "depth": 0, "parentId": null, "files": [], "detectedRole": "", "patterns": [], "metadata": {} },
{ "id": "module__auth", "label": "Auth", "type": "module", "parentId": "layer__presentation", "depth": 1, "files": ["src/auth.ts"], "detectedRole": "authentication", "patterns": [], "metadata": {} }
],
"edges": [
{ "id": "edge_1", "source": "file__src_auth_ts", "target": "file__src_api_ts", "edgeType": "engineering", "strength": 3, "label": "imports", "confidence": "high" }
],
"overlay": { "version": 0, "nodeOverrides": {}, "edgeOverrides": {}, "manualNodes": [], "manualEdges": [] }
}
| Type | Depth | Description |
|---|---|---|
layer | 0 | Top-level architectural layer |
module | 1 | Module within a layer |
file | 2 | Individual source file |
| Type | Description |
|---|---|
engineering | Runtime calls, imports, data flow |
architecture | Contains, part-of, hierarchy |
high, medium, uncertain
If the map was generated with git data (graph.git.branches), the visualizer shows
a "Repository branches" section in the sidebar. Clicking a branch:
git diff --name-status from the server (/api/diff)Server must be started with --repo=<path> for diff support:
npx @frannn2114/repomap-visual serve graph.json --port=3000 --repo=/path/to/repo
For a full architectural map of a branch, ask the agent:
"Analyze branch feature/auth of the repo and add it to the map"
The agent will:
analyzeRepository() on that branch~/.repomap/ JSON with the new branch dataA standalone CLI script lets users browse and open saved maps without the agent:
# List all saved maps
node .opencode/skills/repomap/cli.js list
# Open a map by name (repo name, partial match, or file name)
node .opencode/skills/repomap/cli.js open my-project
Maps are stored persistently at ~/.repomap/maps/ with an index at ~/.repomap/index.json.