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
آخر نشاط في المصدر
٥ يونيو ٢٠٢٦ في ١٠:٤٥
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥٣
التفرعات
٨

خيارات التثبيت

يُحدَّد 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