🕸️ Codependix CLI
Exports a project's dependency graphs — Nx, NestJS, and file-level imports — as JSON and Markdown diagrams, and gates the rules those graphs are judged against.
Codependix reads what each project depends on and renders it four ways: the
Nx project graph, a NestJS project's module graph, a TypeScript project's own
file-level import graph, and a Python project's own file-level import graph.
Each graph is delivered to whichever destinations
codependix.config.ts names for that project — a JSON file, a Markdown anchor
block spliced into an existing file such as a README.md, or both. The same
built graphs are then judged against whatever rules the configuration
declares — see @codependix/boundaries.
pnpm add --filter <project> --save-dev @codependix/cli
codependix map --write --config configuration/codependix.config.ts
Usage
One command, map, and no per-graph-type subcommand. Which graphs run for a
project, where its export lands, and which rules judge it is entirely a
function of the configuration file, which every run names with --config
because nothing searches for it and there is no default; see
configuration/codependix.config.ts
for this repository's own.
| Flag | Meaning |
|---|---|
--check [check] | Fail on a comma-separated set drawn from boundaries and reports |
--config <config> | Required. Path to the codependix configuration file. Omitting it fails the run, naming the flag; nothing is searched for |
--dependencies | Build --check boundaries over the dependencies of the projects --projects or --tags named, reporting their findings as notes (default). No effect without --projects or --tags |
--no-dependencies | Build --check boundaries over only the projects --projects or --tags named, not their dependencies. No effect without --projects or --tags |
-d, --directory [directory] | Workspace root whose Nx project graph this run reads. Defaults to the working directory |
--exclude [exclude] | Comma-separated globs overriding the configured exclude. Refused when exclude was never configured |
--file-imports | Build, check, and write the fileImports graph type for this run |
--no-file-imports | Skip the fileImports graph type for this run |
-f, --format [format] | What to print to standard output, one of json and markdown (default: markdown). A graph type prints only when the run also configured a workspace destination for it, even if its own toggle flag enabled it. A --check boundaries run adds its findings, under a boundaries key in json and a Boundaries section in markdown |
--include [include] | Comma-separated globs overriding the configured include. Refused when include was never configured |
--json-output [jsonOutput] | Write every active graph type's data, combined into one JSON file at this path, keyed by graph type name. A type appears only when the run also configured a workspace destination for it. A --check boundaries run adds its findings under a boundaries key |
--markdown-output [markdownOutput] | Write every active graph type's rendered diagram, combined into one Markdown file at this path. A type appears only when the run also configured a workspace destination for it. A --check boundaries run adds its findings as a Boundaries section |
--nestjs-modules | Build, check, and write the nestjsModules graph type for this run |
--no-nestjs-modules | Skip the nestjsModules graph type for this run |
--nx-projects | Build, check, and write the nxProjects graph type for this run |
--no-nx-projects | Skip the nxProjects graph type for this run |
--projects [projects] | Comma-separated project names or roots to export for, as globs, beyond those include already selects. Also narrows the Workspace Graph to the named set, and --check boundaries to failing only on findings charged to it |
--tags [tags] | Comma-separated Nx tags to export for, beyond what include already selects. Narrows the Workspace Graph and --check boundaries to the tagged projects, as --projects does |
--write | Writes every configured export |
The two --check names
--check names which finding fails the run, because the two findings belong
on opposite sides of a pull request.
--check value | What fails the run |
|---|---|
boundaries | An edge, or a cycle, breaking a declared rule |
reports | A configured destination no longer holding what a fresh run would write |
A boundary violation is caused by the branch and fixed by the branch, so it
gates every pull request, one project at a time — see
The per-project gate. A stale export moves with the
workspace it describes and would fail every branch that changed a project
graph rather than anything the branch itself did, so it is published on the
default branch and gated nowhere. That is the same split
callidescope makes between --check depth
and --check reports, and reports is deliberately spelled the same in both:
it is the same finding, and two names for it would make the two reports
unreadable together.
--check boundariesreads no destination and writes nothing, so it leaves every committed export exactly as it found it.--write --check boundariesis legal — a boundary has no destination to be stale.--write --check reportsis refused: an export cannot be stale in the run that just wrote it.- A bare
--check, or one whose value is only separators, is refused. Read as "gate nothing" it would be a gate that cannot fail, which is worse than no gate at all because it looks like protection.
Which project a boundary finding fails
Every finding is charged to the project or projects it belongs to: a cycle to every project owning a node on it, a forbidden edge to the project owning its source, a file- or NestJS-level finding to the project whose graph it was found in, and a container that cannot boot to that container's project — its message naming the project that owns the class it failed on, when the stack shows another one.
--projects and --tags name the projects a run judges. Graphs are built
over those projects and everything they transitively depend on, and a finding
fails the run only when it is charged to a named project. One charged only to
a dependency is logged as a note, "in dependency", without failing:
the named project is built on it, but it is not that project's to fix.
--no-dependencies builds over the named projects alone. With neither flag
every project is judged. A --projects/--tags selection that matches no
project at all — a misspelled name, a tag nobody carries, or the workspace
root — is refused as a rejected command line rather than run as a gate that
judges nothing.
When no mode is named
Naming neither --check nor --write is asked about, as a three-item menu —
boundaries, reports, write.
There is no flag that turns the prompt off, because there is nothing to turn
off where it cannot be answered: a run whose stdin is not a terminal fails
immediately, naming the flag it wanted, rather than drawing a menu. That
refusal is load-bearing rather than defensive — prompts does not fail on a
non-terminal stdin. It renders the menu, never resolves, and lets the process
exit 0, which would turn a scripted run that forgot its mode flag into a
silent success that wrote nothing. Dismissing the menu at a terminal is
reported the same way, as a rejected command line rather than a crash.
No mode is ever inferred, which is the rule codometer's and
callidescope's flags follow too.
In an Nx workspace the gate is a per-project codependix-bound target, and
publishing is the one workspace-wide write run. This repository's guard-code
reaches the first on every pull request, and its release workflow runs the
second on the default branch:
nx run <project>:codependix-bound
nx run configuration:codependix:write
One project failing — a missing anchor, or a NestJS project that fails to
boot its container — is reported and does not stop the rest: --write either
fully succeeds or names exactly which projects failed while still completing
every other one.
The per-project gate
--check boundaries --projects <name> is a gate for one project, and needs no
task runner. @codependix/nx infers it for an
Nx workspace as a cached codependix-bound target on every project but the
workspace root, so nx affected -t codependix-bound selects the projects a
change touched and a failure names the project it is charged to rather than
one workspace-wide task. The target declares no configurations, so
guard-code --configuration=check falls through to its defaults, as
callidescope-restrict does.
Publishing stays workspace-wide: one --write run produces every project's
anchor blocks, which must reflect one commit, so configuration:codependix is
write-only and is not part of guard-code.
Where the output goes
Printing and delivering are separate. --format decides what reaches standard
output; the destinations under workspace in the configuration and
--json-output/--markdown-output decide what reaches a file.
Markdown is the console default because it is the one rendering that reads in a
terminal and pastes into an issue. --format json is for a machine reading
standard output, so every diagnostic goes to standard error — keeping standard
output clean and parseable as data.
The boundary report
--check boundaries logs its findings to standard error and, given
--format, --json-output, or --markdown-output, also prints them as a
report: under a boundaries key in JSON, and as a ### Boundaries section in
Markdown. A --check boundaries-only run, which exports nothing, prints just
that report; a run that also exports carries both in one document. Without one
of those flags a boundaries-only run prints nothing, and a run that also
exports prints its graphs exactly as it did before.
The JSON holds judgedProjects (the projects whose findings fail the run),
violations (level, rule, message, source, target, cycle, the
charged projects, and a verdict of fail or note) and failures
(level, error, the charged projects, an ownerProject when the failing
code belongs to another project, and a verdict). A note is a finding that
lives in a dependency of a judged project and does not fail the run. The
Markdown lists the same findings under each project they are charged to, a
note marked as not failing.
Who a finding is charged to is worked through, with the report each case prints, in four examples: a cycle, a forbidden edge, a dependent of either, and a container that cannot boot.
Packages
| Package | Role |
|---|---|
@codependix/cli | Orchestrates the four graph builders and delivers their exports |
@codependix/boundaries | Builds each level's graph for a workspace, judges it against the declared rules, and reports what breaks them. --check boundaries delegates to it wholesale |
@codependix/configuration | Reads codependix.config.ts and resolves per-project export destinations and boundary rules |
@codependix/examples | Twenty-one subjects built to be graphed, each with the guide codependix renders from it |
@codependix/nx | Nx plugin: infers a per-project codependix-bound target that runs --check boundaries over the project and its Nx dependencies |
@codependix/nx-projects | Builds a project's Nx Neighborhood and the whole-workspace Workspace Graph |
@codependix/nestjs-modules | Explores a NestJS project's container and builds its module graph |
@codependix/file-imports | Builds a project's file-level import graph — a typescript module walking its own ts.Program, and a python module parsing import/from ... import statements |
Agent skills
Agent skills for coding agents working with codependix are published in
@codependix/agents:
| Skill | Description |
|---|---|
codependix-export | Export dependency graphs and run boundary checks |
codependix-configure | Configure graph types, export destinations, and boundary rules in codependix.config.ts |
codependix-navigate | Query dependency paths and navigate package relationships |
codependix-triage | Triage boundary violations and report drift |
Examples
Every behavior described above — and every one that is not, because it lived
only in a JSDoc comment until now — has a worked example rendered by the real
tool in
@codependix/examples:
- README — one directory per example, each readable on its own, plus configuring a first export destination and adopting codependix in a workspace with no anchor blocks anywhere yet
- AGENTS.md — a "codependix said X → open
this example" table, weighted toward the refusals and toward
--checkstaleness
Start
nx run codependix-cli:start
Test
nx run codependix-cli:vitest
👔 Conformetry
This project was generated from the nestjs-command-project conformetry template.