# Likec4 Discover

> Scan TypeScript/Python repo to IR and generate validated LikeC4 model (specification+model+views). Use when user asks for architecture diagram, C4 model, likec4, code-to-diagram, or codebase overview.

- Skill: `liberifatali/likec4-discover` (Agent Skill, multi-file: 14 files)
- Install (CLI): `npx skillmds@latest add liberifatali/likec4-discover`
- Raw SKILL.md: https://api.skillmd.com/api/skills/liberifatali/likec4-discover/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: LiberiFatali (https://skillmd.com/u/liberifatali)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/liberifatali/likec4-discover

---


# likec4-discover

Generate a LikeC4 architecture model from code. Scripts do deterministic work; you do only naming/grouping. Never hand-write DSL syntax.

Quick one-liner (best-effort: raw titles, all proposals promoted, nothing pruned):

```bash
<skill>/scripts/discover.sh quick --root <repo> --out ./generated --system <name>
# flooded diagram (too many elements)? use file-level + routes instead:
<skill>/scripts/discover.sh quick --root <repo> --out ./generated --system <name> --granularity file
```

Defaults when the user gives no args: `--root .`, `--out ./generated`, `--system <basename-of-root-sanitized>` (fallback `cloud`). Run quick immediately without asking; only ask when overwriting an existing `--out` dir or exceeding budgets.

For curated output, run the steps below with manual labeling in between.

Requires `likec4-dsl` skill for DSL reference (via `npx skills add https://likec4.dev/`). This skill is write-path only (`scan -> IR -> .c4`); use `@likec4/mcp` for read-path queries.

## Workflow

### 1. Scan (deterministic, no LLM judgment)

Run from the repo root:

```bash
<skill>/scripts/discover.sh scan --root ./src --out /tmp/ir.json
# flags: --root <dir> (default .), --out <file|-> (default stdout),
#   --max-files 2000, --include-tests (default false),
#   --include "<glob>" (repeatable, replaces defaults),
#   --exclude "<glob>" (repeatable, merges with defaults),
#   --no-symbols | --symbol-kinds <csv> (file-level granularity, see below)
# (calls scripts/scan.mjs; same flags)
```

- `scan.mjs` walks TS/JS with node stdlib (import regex + exported class/function names for titles) and spawns `scan.py --root <dir>` once for Python (`ast` stdlib only; skipped automatically when the repo has no `.py` files). Granularity flags (`--no-symbols`, `--symbol-kinds`) are forwarded to `scan.py`.
- Granularity (default): file = parent element; module classes, top-level functions, and route handlers (FastAPI decorators / Express-style registrations) = nested components with `parent` + `line` evidence. Symbol-free files fall back to file = component.
- Too many elements? When a scan yields dozens of files, per-function symbols flood the diagram with helpers (`pad2`, `sleep`, `esc`, ...). Prefer file-level + routes: `quick --granularity file`, or step by step: `scan --symbol-kinds route` → `auto-label --keep-symbols route` → `emit --drop-symbols`. Routes always survive pruning (they carry the HTTP surface); plain functions/variables/classes are dropped. Rule of thumb: switch to `file` granularity when any single file contributes >5 symbols or the labeled IR exceeds ~40 elements.
- Infra/actor candidates arrive as `proposals[]` (with `source` evidence) — promote or drop each, never auto-add.
- Default ignores: `node_modules, dist, build, .venv, __pycache__, .git` + symlinks + `.gitignore` rules. `--include` replaces default extensions; `--exclude` merges.
- Output envelope: `{ "elements": [...] }` per `references/ir-schema.md`. Cap ~200 elements; script exits non-zero with a clear error when over budget (narrow `--include` or raise budget explicitly).

### 2. Group and label (only LLM step)

1. Default hierarchy = directory tree + fan-in/fan-out from IR `imports`/`calls`. Keep it unless clearly wrong.
2. Assign each element `fqn` as `<system>.<area>.<Name>` and a human `title`. Preserve `file`, `lang`, `imports`, `calls`, `extends`, `technology`.
3. Guardrails (see `references/dsl-min.md`):
   - Identifier: `[A-Za-z_][A-Za-z0-9_-]*`, no dots, must not start with a digit. Dots separate FQN levels only.
   - FQN unique project-wide. Cross-file refs always use full FQN.
   - Kinds only: `person, system, container, component, database`. Relationships only: `http, kafka, s3, promql, inproc` (+ `calls, imports, inherits` aliases). Fixed sets — never invent kinds.
   - No direct parent-child `->` relationships.
   - Every element keeps `tags: ["autogenerated"]` in IR (metadata only, not rendered). Provenance in output is a file header comment (`// Generated by likec4-discover ...`), never per-element tags (they render as badge spam).
4. Write the labeled IR to `/tmp/ir.labeled.json`. Ask before exceeding element/file budgets.

### 3. Emit (deterministic, string template by default)

```bash
<skill>/scripts/discover.sh emit --in /tmp/ir.labeled.json --out ./generated --system <name>
# file-level + routes safety net (drops helper symbols even if the labeled IR
# still contains them):
# <skill>/scripts/discover.sh emit --in /tmp/ir.labeled.json --out ./generated --system <name> --drop-symbols
# emits spec.c4/model.c4/views.c4, runs --check when likec4 is installed,
# then validates with the likec4 CLI when available
```

- `emit.mjs` has zero dependencies. It sanitizes identifiers, dedupes FQNs, and fails closed on duplicates or bad identifiers. `--check` additionally runs `LikeC4.fromSource().getErrors()` when the `likec4` package is installed (skipped with a note otherwise); template output stays canonical.
- Editing replaces, never merges. Confirm before overwriting an existing `./generated`.

### 4. Validate (required in CI, progressive locally)

```bash
npx -y likec4@1.59.3 validate --no-layout --json ./generated
# gate: .valid == true, .stats.filteredErrors == 0
```

- See `references/validation.md` for the `computedModel().elementsWhere()` vitest recipe.
- If `likec4` is absent locally, `emit.mjs` self-check (dup FQN / bad identifier) is the minimum gate.
- Lossy round-trip (`toDSL`/`writeDSL`) is one-way generation, never a formatter.

### 5. Preview / serve

```bash
npx -y likec4@1.59.3 start ./generated
# or: likec4 preview-view via MCP for file-less iteration
```

## Constraints

- Never hand-write `.c4` syntax; always go through `emit.mjs`.
- Never invent element/relationship kinds or tags beyond the spec defaults without declaring them in `spec.c4`.
- Never exceed file/element budgets silently — ask first.
- `deployment {}` and dynamic views are out of scope for v1.
- For drift detection, see Erode (deferred, not part of this skill).

## File map

- `scripts/scan.mjs`, `scripts/scan.py` — deterministic scanners.
- `scripts/discover.sh` — one entry point: `scan` (→ `scan.mjs`), `emit` (→ `emit.mjs --check` + CLI validate when available), and `quick` (scan → `auto-label.mjs` → emit → validate in one go).
- `scripts/auto-label.mjs` — best-effort labeling for `quick` (prettified titles, import wiring incl. barrels/aliases, all proposals promoted). Reuses `sanitize` from `emit.mjs`; mirrors its default FQN assignment.
- `scripts/emit.mjs` — deterministic emitter (template canonical + optional `--check`). Importable (`sanitize`, `emitModel`, `checkModel`) with unit tests (`node --test test/*.test.mjs` from repo root).
- `scripts/scan.py` — deterministic scanner with unit tests (`python3 -m unittest discover -s test` from repo root).
- `references/ir-schema.md` — IR field table + examples.
- `references/dsl-min.md` — spec/model/views + FQN rules, condensed.
- `references/validation.md` — validate commands + vitest recipe.
- `references/troubleshooting.md` — common identifier/FQN/predicate errors.
- `assets/templates/` — starting `spec.c4`, `model.c4`, `views.c4`.

