Skip to content

Repository files navigation

M21

Markdown-driven spec files with dependency graphs, feature tracking, and group clustering — visualized as an interactive, explorable graph.

What is M21?

M21 lets you define project contracts as Markdown files with YAML frontmatter. A spec can define a concern's data model, semantic interfaces, architectural contract, dependencies, and optional Gherkin .feature files. Dependent specs declare which behavioral capabilities they use, creating traceable contracts between concerns. M21 renders everything as a live, interactive dependency graph in the browser.

Vision

M21 is an experiment in higher-level software tooling for building maintainable, extensible, reliable, professional, clean, and understandable software. It treats a project as a network of purposeful concerns with explicit models, interfaces, responsibilities, dependencies, and executable behavior.

The goal is living architecture: data models define shared meaning, interfaces define semantic surfaces, specs describe intent, Gherkin scenarios demonstrate behavior, dependency edges explain which capabilities are used, and test results close the loop.

Read the full vision in VISION.md.

Install

npm install -g @moejay/m21

Or run directly:

npx @moejay/m21 ./spec/

Skills

M21 ships with skills for spec authoring and brownfield adoption. Install them with:

npx skills install moejay/m21

This installs two skills:

  • m21 — helps you create and maintain spec files, dependencies, and feature files
  • m21-init — analyzes an existing codebase and generates specs + features from it (brownfield adoption)

Quick start

1. Create a spec directory

myproject/
├── spec/
│   ├── bootstrap.md
│   ├── persistence.md
│   └── repos.md
└── features/
    ├── bootstrap/
    │   ├── project-scaffolding.feature
    │   └── health-endpoint.feature
    ├── persistence/
    │   ├── data-storage.feature
    │   └── query-interface.feature
    └── repos/
        └── repo-onboarding.feature

2. Write a spec file

Each spec is a markdown file with YAML frontmatter:

---
name: bootstrap
description: One-time project scaffolding
group: foundation
tags: [setup, init]
depends_on: []
features: features/bootstrap/
---

# Bootstrap

## Data model

```m21-model
entities:
  ProjectConfiguration:
    fields:
      root: { type: string, required: true }
      ready: { type: boolean, required: true }

Interfaces

operations:
  project-scaffolding:
    input: ProjectConfiguration
    output: ProjectConfiguration
    failures: [InvalidProjectRoot]

Contract

Describe responsibilities, non-goals, invariants, dependencies, decisions, and guarantees.


The sections are optional, but when present they follow **Data model → Interfaces → Contract**. Fenced `m21-model` and `m21-interface` YAML blocks are parsed and enforced; surrounding prose remains human-owned. Skip empty sections. Existing free-form Markdown bodies remain valid.

### 3. Declare dependencies with feature tracking

Specs declare which features they use from their dependencies:

```markdown
---
name: persistence
description: SQLite database layer
group: infrastructure
tags: [database, storage]
depends_on:
  - name: bootstrap
    uses: [project-scaffolding, health-endpoint]
features: features/persistence/
---

The uses array references Feature: names from the parent spec's .feature files. This creates a traceable contract — you know exactly which capabilities each module relies on.

Frontmatter fields

Field Required Description
name Yes Unique identifier for the spec
description No Short summary shown in the info panel
group No Logical grouping — specs in the same group are visually clustered
tags No Array of tags for categorization
depends_on No Dependencies — simple strings or objects with name and uses
features No Path to a directory of .feature files

depends_on format

Simple (backwards compatible):

depends_on:
  - bootstrap
  - config

Rich (with feature references):

depends_on:
  - name: bootstrap
    uses: [project-scaffolding]
  - name: persistence
    uses: [data-storage, query-interface]

Mixed:

depends_on:
  - name: persistence
    uses: [data-storage]
  - server-api

4. Write Gherkin features

Features provide executable examples of observable interface behavior or evidence-backed guarantees; they do not replace model or interface definitions. Feature names must be kebab-case:

Feature: project-scaffolding
  The project compiles and all tooling works from a fresh checkout.

  Scenario: Clean build with zero warnings
    Given a fresh clone of the repository
    When I run the build command
    Then the build succeeds

5. Run M21

# Start the dev server (default: http://localhost:3333)
npx @moejay/m21 ./spec/

# Auto-create the spec directory
npx @moejay/m21 ./spec/ -y

# Custom port
npx @moejay/m21 ./spec/ --port 4000

# Export a static HTML file instead
npx @moejay/m21 ./spec/ --output graph.html

# Overlay test results (auto-detected from results/, reports/, test-results/ when omitted)
npx @moejay/m21 ./spec/ --results results/cucumber.json

Visualizing test results

M21 never runs your tests — it ingests a test report and overlays the outcomes. Two formats are accepted, auto-detected by shape:

  • Cucumber JSON — emitted by every Gherkin runner (cucumber-js, cucumber-jvm, behave, cucumber-ruby, godog, Reqnroll, cucumber-rs), so it stays language-agnostic.
  • Jest / vitest JSON — the --reporter=json output common across the JS ecosystem. For vitest-cucumber/jest-cucumber runs the Feature:/Scenario: titles join directly; for plain describe/it suites the top-level describe is the feature and the it is the scenario.
# vitest / jest example
npx vitest run --reporter=json --outputFile=results/vitest-results.json
npx @moejay/m21 ./spec/          # auto-detected

Results join onto specs by feature name and scenario name: each node is ringed green (all passing), red (any failing), or amber (pending/skipped) and shows a passed/total count (e.g. 15/19) inside the circle, and the side panel shows per-scenario ✓/✗ pills plus a passed / total summary. A legend appears whenever any spec has test data. In dev-server mode the overlay live-updates as the report file changes.

Features

  • Interactive graph — D3 dependency visualization with zoom, pan, and drag
  • Group clustering — Specs in the same group are visually clustered with colored hulls
  • Feature tracking — See which features flow along each dependency edge
  • Test results overlay — Point M21 at a Cucumber JSON or Jest/vitest JSON report and the graph colours each node by pass/fail, shows a passed/total count inside every circle, and lists per-scenario status pills in the side panel. Click a scenario to inspect step statuses and, for source-backed Jest/vitest reports, the Given/When/Then definition snippets. Auto-detected from results/, reports/, test-results/, or pass --results <file>. Live-updates as tests re-run
  • Tree-and-groups layout — Default architecture view combines dependency depth with group clustering. Nodes start unlocked for manual positioning, group labels drag whole groups, and checkboxes can lock nodes or reverse the tree direction
  • Side panel — Click any node to see description, group, tags, dependencies with used features, rendered markdown body, and Gherkin scenarios
  • Enforceable models — Parse and validate language-neutral m21-model and m21-interface blocks, including cross-spec references
  • Schema export — Export normalized contracts or JSON Schema for runtime validation, generators, and CI
  • Ordered contract stack — Evolve data model → semantic interfaces → architectural spec → executable features before implementation
  • Composable specs — Specs own clear model and interface contracts; dependencies identify the behavioral capabilities they consume
  • Live reload — Dev server watches your spec and feature files, pushes changes via SSE instantly
  • Inline editing — Edit spec bodies and feature files directly in the browser (dev server mode)
  • Static export — Generate a self-contained HTML file with --output
  • Version check — Notifies you when a new version is available

CLI reference

npx @moejay/m21 <directory>                       Start dev server with live reload (default)
npx @moejay/m21 <directory> --output <file>       Save graph to a static HTML file
npx @moejay/m21 <directory> --port <number>       Custom port for dev server (default: 3333)
npx @moejay/m21 <directory> --results <file>      Overlay Cucumber, Jest, or vitest JSON test results
npx @moejay/m21 <directory> -y                    Auto-create spec directory if missing
npx @moejay/m21 --help                            Show help

Read-only subcommands (for humans and coding agents)

Each subcommand also accepts --json for machine-readable output.

npx @moejay/m21 list <directory>                  Print all specs (group, dep count, feature count)
npx @moejay/m21 show <directory> <name>           Print one spec's full info — deps, dependents, features, body
npx @moejay/m21 features <directory> [<name>]     List features (across all specs, or scoped to one)
npx @moejay/m21 deps <directory> <name>           Print forward + reverse dependency tree
npx @moejay/m21 validate <directory>              Lint graph, model, interface, and feature contracts
npx @moejay/m21 model <directory> [<name>]         Export normalized models and interfaces
npx @moejay/m21 schema <directory> [<name>]        Export entity contracts as JSON Schema

Brownfield adoption

Already have a codebase? Install the skills (npx skills install moejay/m21) and use m21-init to analyze your existing code. It discovers model ownership first, semantic interfaces second, architectural concerns and dependencies third, and executable features last.

Development

M21 is itself spec-driven: every module has a spec in spec/ and Gherkin scenarios in features/, and every feature file is bound to executable tests (via @amiceli/vitest-cucumber), so the scenarios are the contract.

npm test          # run the suite once; also writes results/vitest-results.json
npm run test:watch
npm run docs:graph        # refresh docs/graph-export.html, including test overlay when results exist
npm run docs:graph:check  # CI check: generated static export must match docs/graph-export.html
npm run setup:githooks    # install the local pre-commit hook for static export refreshes

npm test emits a results/vitest-results.json report, so you can dogfood the overlay on M21 itself:

npm test
npx . ./spec/     # the graph lights up green with each module's passed/total count
npm run docs:graph # writes the same overlay into docs/graph-export.html for GitHub Pages

Requires Node ≥ 20.

Programmatic API

M21 can be used as a library. Entry points are exposed through the package exports map:

import { parseSpecDirectory } from "@moejay/m21";           // parse specs + features
import { generateHTML } from "@moejay/m21/generator";       // render the graph HTML
import { createM21Server } from "@moejay/m21/server";   // run the dev server
import { parseResultsFile, mergeResults } from "@moejay/m21/results"; // overlay test results
import { analyzeGraph } from "@moejay/m21/cycles";          // dependency + cycle analysis
import { validateContractRegistry, generateJsonSchema } from "@moejay/m21/contracts";

// Parse a spec directory and render a self-contained graph.
const specs = await parseSpecDirectory("./spec", { projectRoot: "." });
const issues = validateContractRegistry(specs);
const { schema } = generateJsonSchema(specs);
const html = generateHTML(specs);

// Overlay Cucumber/vitest results onto the specs, then render.
const lookup = await parseResultsFile("./results/cucumber.json");
if (lookup) mergeResults(specs, lookup);
const withStatus = generateHTML(specs);

// Start the dev server (loopback-only by default).
const server = await createM21Server({ specDir: "./spec", port: 3333 });
console.log(server.address);
await server.close();

The default import (@moejay/m21) is the parser. generateHTML produces a fully self-contained document — the rendering libraries are inlined, so it works offline.

License

MIT

About

Spec-driven dependency graphs — markdown specs with YAML frontmatter, Gherkin features, interactive D3 visualization

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages