Skip to main content

archlet

Interactive, provenance-backed architecture maps in .archlet/. Two modes: MAP — analyze the whole codebase into .archlet/data.js and seed a starter overlay from a recent change; DIFF — given a PR, commit, range, branch, or working-tree changes, overlay what they touch. Use when the user asks to map / diagram / visualize a codebase's architecture, refresh the map, or show what a PR / commit / change touches.

소스 정보

저장소
superdesigndev/archlet
최근 소스 활동
2026년 6월 5일 10:45
감지된 SKILL.md 언어
영어
스타
53
포크
8

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
archlet
description
Interactive, provenance-backed architecture maps in .archlet/. Two modes: MAP — analyze the whole codebase into .archlet/data.js and seed a starter overlay from a recent change; DIFF — given a PR, commit, range, branch, or working-tree changes, overlay what they touch. Use when the user asks to map / diagram / visualize a codebase's architecture, refresh the map, or show what a PR / commit / change touches.
# archlet You produce files under `.archlet/` that the viewer renders. Pick the mode from the request: - **MAP** — "map / visualize the architecture", "refresh the map", no specific change given. - **DIFF** — a change is referenced (PR, commit, range `A..B`, branch, or "my changes / staged"). Needs an existing `.archlet/data.js` — run MAP first if absent. Nodes form a **tree of any depth** via `parent`: top-level nodes (source roots / apps) contain **modules**, which can nest further when a module is big enough to warrant it. Keep it shallow — add a level only when it earns its keep; the viewer expands/collapses at every level. Always finish by launching the viewer (see end). --- ## Mode 1 — MAP → `.archlet/data.js` The single source of truth the viewer reads: ```js /* GENERATED by the archlet skill. */ window.ARCH = { config: { project, layers: { <key>: { label, border, ink, fill? }, ... } }, // project = repo name (viewer title); layers = the taxonomy YOU choose nodes: [{ id, name, g, parent?, brief, role, rt, path, methods? }], // g = a layer key edges: [{ s, t, k, l?, src, method }], // src = "file:line" methodEdges: [{ sNode, sMethod, tNode, tMethod, src }], // method→method calls (step 5) }; ``` - **node** — `id` internal unique slug (never shown; namespace it, e.g. `coding-tools` vs `foundation-tools`) · `name` short heading on the card · `g` a layer key · `parent` the containing node's id, nested as deep as the structure needs (omit for top-level nodes) · `brief` ≤ ~6-word tagline · `role` one sentence · `rt` key file(s) · `path` dir relative to repo root · `methods` (optional, leaf nodes) `[{ name, src:"file:line", calls? }]` — the top ~3–6 functions by call count. - **edge.k** — a short lowercase kind YOU choose (static `import`, runtime wire, app→engine…); keep the vocabulary small so the viewer can style by kind. `method`: `mechanical` (tool) | `manual` (grepped). Containment is implicit via `parent` — never emit containment edges. - **edge.l** (optional) — what flows over a wire edge (`messages.create`, `POST /webhook`); set it only where it adds signal, never a count (`3×`). - **methodEdge** — a call from one node's method to another's. `sMethod`/`tMethod` must exist in those nodes' `methods` and `src` is the call site, else the edge is dropped. Procedure: 1. **Scan structure** — find source roots (`apps/*`, `packages/*`, `src`); they become the top-level nodes. Read docs. 2. **Choose the layer taxonomy** (the key judgment) — a few layers, calm palette, e.g. frontends / control-plane / runtime / shared-pkg / external. Put them in `config.layers`. 3. **Extract the mechanical floor — required, via `npx`:** - **Routes + import/call graph (codegraph):** `npx -y @colbymchenry/codegraph@latest init -i`, then `npx -y @colbymchenry/codegraph@latest query "" --kind route --limit 99999 --json` for the route inventory. The import + call graph lives in `.codegraph/codegraph.db` (query it directly). - **Import graph (madge), JS/TS roots only:** `npx -y madge@latest --json --ts-config <root>/tsconfig.json <root>/src`, then collapse file→file edges to module→module. Non-JS/TS roots: use that language's tool (`go mod graph`, `pydeps`) or codegraph's import graph instead. Build on these — only drop to Grep/Read for what a static tool can't see (most **wire/cross-process edges**). 4. **Build — use a workflow, one agent per major module.** Split the repo into its handful of large/important modules (in a monorepo, each app/package; in a single package, the main subsystems) and give each its own agent. Each agent picks core modules (routes/controller/plugin/tool/store/service, or doc-named), emits intra-module import edges (`mechanical`), and stitches **wire edges** out of its module by matching client call sites (fetch/SDK/db/proxy/queue) to a target or external node, each with a real `file:line` (`manual`). Wire edges are NOT in the import graph and are the most valuable. 5. **Methods + methodEdges — from codegraph's call graph** (`.codegraph/codegraph.db`; don't skip — this is what makes nodes legible). Derive mechanically, don't invent names: - **`node.methods`** — top functions defined under each leaf node's `path`, ranked by call in-degree: `SELECT n.name, n.file_path||':'||n.start_line AS src, (SELECT COUNT(*) FROM edges e WHERE e.kind='calls' AND e.target=n.id) AS calls FROM nodes n WHERE n.kind IN ('method','function') AND n.file_path LIKE '<node.path>/%' ORDER BY calls DESC LIMIT 6;` - **`methodEdges`** — `calls` edges crossing node boundaries, mapped to `{ sNode, sMethod, tNode, tMethod, src }`; keep only if both method names survived into their nodes' `methods`. Bucket each side's `file_path` to its node by longest `path` prefix. 6. **Write, then validate** — write `.archlet/data.js`, run **`npx archlet validate`** (checks shape + referential integrity), fix what it reports, re-run until clean. Spot-check wire edges against their `file:line` — drop, don't fabricate. 7. **Seed a starter diff — by default.** A fresh map is static; overlaying a real recent change shows the DIFF feature working and where activity is concentrated. Pick one coherent change (prefer a recently-merged PR via `gh pr list --state merged --limit 15 --json number,title,additions,changedFiles,url`; else the largest meaningful commit from `git log`), discounting lockfile / generated / `dist` noise. Build it as in **Mode 2**, register it in the manifest but leave `default` null so the clean map opens first. Skip silently if history is too thin (shallow clone, lone initial commit, only trivial changes); never fabricate one. Mention it on handoff. **Launch the viewer** — `npx archlet view` is a blocking server that auto-opens the browser; start it in the background and tell the user it's at `http://localhost:4173` (stop the process to shut it down). --- ## Mode 2 — DIFF → `.archlet/diffs/<name>.js` Overlay the files a change touches onto the existing map. Read `.archlet/data.js` first for node `path`s. **1. Get the changed files** (each: path, additions, deletions): | source | command | |---|---| | PR | `gh pr view <n> --repo <owner/name> --json files,title,additions,deletions,changedFiles,url,number` | | commit | `git show --numstat --format= <sha>` | | range / branch | `git diff --numstat <A>..<B>` (use `<base>...<head>` for branch-vs-merge-base) | | working tree / staged | `git diff --numstat` · `git diff --numstat --staged` | `--numstat` lines are `<add>\t<del>\t<path>` (`-` = binary). **2. Map files → nodes.** For each path, find the node whose `path` is the **longest prefix**; else fall back to its top-level root/app node; else report it unmapped. Aggregate per node `{ files, add, del, paths }`. Compute `contains` = ancestor node ids of every changed node (walk `parent`). **3. Write the overlay** `.archlet/diffs/<name>.js`: ```js window.ARCH = window.ARCH || {}; window.ARCH.pr = { label: "<human label>", // "PR #565" · "commit a1b2c3d" · "working tree" title: "<optional>", url: "<optional>", number: <n>, // number only for PRs (enables ?pr=<n>) add, del, files, nodes: { "<nodeId>": { files, add, del, paths:[...] }, ... }, contains: [ "<ancestorNodeId>", ... ], links: { // OPTIONAL — connectivity the change alters add: [ { s, t }, ... ], // a dependency/wire INTRODUCED cut: [ { s, t }, ... ], // one REMOVED }, }; ``` `links.add` renders as a green + arrow, `links.cut` as a dashed ✕ — between the nodes' visible ancestors. Only fill `links` when the change actually adds/removes a node→node connection (a new/removed import, fetch, db/proxy call); omit for internal-only changes. `<name>`: `pr-<n>`, else `commit-<sha7>` / `wip` / `staged`. **4. Register it** in `.archlet/diffs/manifest.js` (create if missing; keep existing entries): ```js window.DIFFS = { default: "<name>", available: [ { name, label, number?, add, del, files }, ... ], // newest first }; ``` Run **`npx archlet validate`**, fix any issues, then **launch the viewer** in the background (as above) at `http://localhost:4173`. The viewer has a **Diffs menu**; switch via the menu, `?pr=<n>`, or `?diff=<name>`. --- ## Rules - **Provenance or it didn't happen** — every wire edge needs a real `file:line`; never invent edges. - **You decide the taxonomy** (small); `data.js` is the single source of truth and a draft the user can hand-edit. - **Always end by opening the map** in the background, whichever mode you ran — don't leave a command to paste. - Monorepo gotchas: CommonJS/NestJS DI deps aren't plain imports; apps importing another app's built `dist`; dynamic plugin/route registration (invisible to static tools — read the registrar).
GitHub에서 보기