npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ruledoc

v0.2.1

Published

Business rules documentation generator — extract @rule() annotations from code and generate Markdown, JSON and HTML docs.

Readme

ruledoc

┌─┐┬ ┬┬  ┌─┐┌┬┐┌─┐┌─┐
├┬┘│ ││  ├┤  │││ ││
┴└─└─┘┴─┘└─┘─┴┘└─┘└─┘

npm version npm downloads CI license node zero dependencies

Extract @rule() annotations from your codebase and generate living business rules documentation.

Business rules are scattered everywhere — constants, guards, validators, middleware. ruledoc finds them all and produces a structured, searchable doc.

Try it

npx ruledoc

Zero install, zero config. Scans ./src and generates your doc instantly.

Install

Once you're sold, add it as a dev dependency:

npm install -D ruledoc

Requires Node.js 20.19.0 or later.

Quick start

1. Annotate your code

// @rule(billing.plans, critical): Free plan is limited to 50 links
export const FREE_PLAN_LINK_LIMIT = 50;

// @rule(auth.session): Session expires after 24h of inactivity
const SESSION_TTL_MS = 24 * 60 * 60 * 1000;

// @rule(redirect.chain, FLEW-234, warning): Max 5 hops to prevent loops
export const MAX_REDIRECT_CHAIN = 5;

2. Run npx ruledoc

3. Get your docBUSINESS_RULES.md + BUSINESS_RULES.json at the root.

Annotation format

// @rule(scope): Description
// @rule(scope.sub): With subscope
// @rule(scope.sub, critical): With severity
// @rule(scope.sub, critical, JIRA-123): With ticket
// @rule(scope.sub, JIRA-123, critical): Order doesn't matter
// @rule(scope.sub, JIRA-123): Ticket only — severity defaults to info

| Param | Required | Description | |-------|----------|-------------| | scope | ✅ | Dotted path like billing.plans, auth.session | | severity | ❌ | One of info (default), warning, critical — or custom | | ticket | ❌ | Any string like JIRA-123, FLEW-234, #42 |

Smart detection: severity and ticket can be in any order. ruledoc matches against the known severity list and figures out which is which.

Warnings

ruledoc catches annotation issues without blocking:

◆ ruledoc 28 rules · 5 scopes · 7 critical · 5 warning

  ⚠ auth/session.ts:4 — unknown severity "crtical", did you mean "critical"? (defaulting to info)
  ⚠ billing/limits.ts:12 — empty description

Warnings appear in the terminal, and are included in the generated Markdown and JSON output.

Output formats

| Format | Flag | Description | |--------|------|-------------| | Markdown | md | Grouped by scope, TOC, summary table, severity badges, warnings | | JSON | json | Structured tree for tooling, includes warnings | | HTML | html | Standalone dark-themed page with search, scope/severity filters | | Context | context | Flat, token-efficient text for LLM prompts (CLAUDE.md, .cursorrules) |

ruledoc --format md,json,html,context

Context format

The context format produces a flat text file optimized for injecting into LLM prompts. Rules are sorted by severity (critical first) and output one per line with file references.

ruledoc --format context

Output (BUSINESS_RULES.context):

# Business Rules (auto-generated by ruledoc — do not edit)
# 28 rules · 5 scopes · Generated 2026-03-16
[critical] billing.plans: Free plan is limited to 50 links (billing/limits.ts:1)
[warning] redirect.chain: Max 5 hops to prevent loops (redirect/handler.ts:12)
[info] auth.session: Session expires after 24h of inactivity (auth/session.ts:3)

Wire it into your LLM context file:

cat BUSINESS_RULES.context >> CLAUDE.md

Configure filtering and limits via ruledoc.config.json:

{
  "formats": ["md", "json", "context"],
  "context": {
    "maxRules": 50,
    "severities": ["critical", "warning"]
  }
}

Interactive diff

Each run compares with the previous JSON output and shows what changed:

◆ ruledoc 28 rules · 5 scopes · 7 critical · 5 warning
  + Refunds must be processed within 48h [critical] billing.refund → billing/limits.ts:22
  - Old trial rule [info] billing.trial → billing/limits.ts:8
  → ./BUSINESS_RULES.md
  → ./BUSINESS_RULES.json

CI check

ruledoc --check

Exits with code 1 if the generated doc differs from the existing file. Combine with --quiet for clean CI output:

ruledoc --check --quiet
# .github/workflows/rules.yml
- run: npx ruledoc --check --quiet

Rule protection

Prevent accidental removal of critical rules:

ruledoc --check --protect critical

When a protected rule is removed, --check exits with code 2:

✗ [critical] billing.plans: Free plan limited to 50 items
    was in billing/limits.ts

✗ ruledoc: 1 critical rule(s) removed — build blocked
  To allow removal, use --allow-removal or add a @rule-removed() comment.

You can protect multiple severity levels:

ruledoc --check --protect critical,warning

Or in config:

{
  "protect": ["critical"]
}

Acknowledging removals

When you intentionally remove a protected rule, add a @rule-removed() annotation to acknowledge it:

// @rule-removed(billing.plans, JIRA-456): Migrated to config service

This tells ruledoc the removal was deliberate and unblocks the build.

Bypassing protection

To skip all protection checks (e.g. during a large refactor):

ruledoc --check --protect critical --allow-removal

History

ruledoc tracks removed rules as tombstones in BUSINESS_RULES_HISTORY.json. This gives you a changelog of what rules existed and when they were removed.

Removed rules also appear in the Markdown output under a "Removed rules" section, with their removal date and acknowledgment details (if any).

To disable history tracking:

ruledoc --no-history

Or in config:

{
  "history": false
}

Pro features

Rule protection, history, and context export work for free on projects with fewer than 50 rules — no license needed. Beyond 50 rules, a Pro license unlocks everything.

| Feature | < 50 rules | 50+ rules | |---------|:-:|:-:| | Scanning, Markdown, JSON, HTML | ✅ Free | ✅ Free | | Interactive diff | ✅ Free | ✅ Free | | CI check (--check) | ✅ Free | ✅ Free | | Rule protection (--protect) | ✅ Free | 🔑 Pro | | History / tombstones | ✅ Free | 🔑 Pro | | Context format (--format context) | ✅ Free | 🔑 Pro | | GitHub Action PR comments | ✅ Free | 🔑 Pro |

Set your license key via environment variable (recommended for CI) or config:

export RULEDOC_LICENSE=RULEDOC-XXXX-XXXX-XXXX
{
  "license": "RULEDOC-XXXX-XXXX-XXXX"
}

Get a Pro license →

GitHub Action

Use the built-in composite action to automate rule checking and PR comments:

# .github/workflows/rules.yml
name: Rules
on:
  pull_request:
    branches: [main]

jobs:
  ruledoc:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - uses: fmekkaoui/ruledoc/action@main
        with:
          protect: critical
          allow-removal: 'false'

The action will:

  • Run ruledoc --check to verify docs are up to date
  • Post a PR comment summarizing added/removed rules
  • Fail the check if protected rules are removed without acknowledgment

Ignore & Exclude

ruledoc uses a three-layer ignore system to keep noise out of your docs:

Layer 1 — .gitignore (on by default): Automatically respects your project's .gitignore patterns so build output, node_modules, and vendor code are never scanned.

Layer 2 — Test file exclusion (on by default): Skips *.test.*, *.spec.*, and __tests__/** files since test annotations are usually not real business rules.

Layer 3 — Extra patterns: Add custom glob patterns to exclude additional files.

Config

{
  "extraIgnore": ["**/generated/**", "**/vendor/**"],
  "ignoreTests": true,
  "gitignore": true
}

CLI flags

ruledoc --extra-ignore "**/generated/**,**/vendor/**"
ruledoc --no-ignore-tests    # include test files
ruledoc --no-gitignore       # don't respect .gitignore

The --extra-ignore flag appends to any patterns set in the config file (it never replaces them). The existing --ignore flag for directory names continues to work as before.

CLI

ruledoc [options]

Options:
  -s, --src <dir>             Source directory (default: ./src)
  -o, --output <file>         Output file (default: ./BUSINESS_RULES.md)
  -f, --format <formats>      md,json,html,context (default: md,json)
  -e, --extensions <exts>     .ts,.vue,.py (default: .ts,.tsx,.js,.jsx,.mjs,.cjs,.vue,.svelte)
      --ignore <dirs>         Directories to skip
      --extra-ignore <globs>  Additional glob patterns to exclude (comma-separated)
      --no-ignore-tests       Include test files (*.test.*, *.spec.*, __tests__)
      --no-gitignore          Don't respect .gitignore patterns
  -t, --tag <name>            Annotation tag (default: rule → @rule(...))
      --severities <list>     Severity levels, first is default (default: info,warning,critical)
  -p, --pattern <regex>       Custom regex (overrides --tag)
  -c, --check                 CI mode: exit 1 if docs are stale
      --protect <severities>  Block removal of rules at these severity levels (comma-separated)
      --allow-removal         Bypass all protection checks
  -q, --quiet                 Suppress all output except errors
      --no-history            Don't track removed rules in history file
      --verbose               List every rule found
      --init                  Setup guide and example config
  -h, --help                  Show this help
  -v, --version               Show version

Quiet mode

--quiet suppresses all terminal output except errors. Useful in CI or when piping.

ruledoc --quiet

Verbose mode

--verbose lists every rule found, grouped by scope:

◆ ruledoc 28 rules · 5 scopes · 7 critical

  Auth (7)
    ● [critical] Session expires after 24h → auth/session.ts:3
    ● Password must be 8+ chars → auth/password.ts:1
    ...
  Billing (5)
    ● [critical] Free plan limited to 50 links → billing/limits.ts:1
    ● [warning] Trial lasts 14 days FLEW-102 → billing/limits.ts:7
    ...

Config

Config is loaded in this order (later wins):

  1. ruledoc.config.json
  2. "ruledoc" field in package.json
  3. CLI flags

Only JSON config files are supported — no JS/TS configs (no eval, no code execution).

{
  "src": "./src",
  "output": "./BUSINESS_RULES.md",
  "formats": ["md", "json", "html"],
  "tag": "rule",
  "severities": ["info", "warning", "critical"],
  "extensions": [".ts", ".tsx", ".js", ".jsx", ".vue"],
  "extraIgnore": ["**/generated/**"]
}

Or in package.json:

{
  "ruledoc": {
    "src": "./app",
    "formats": ["md", "json", "html"]
  }
}

Config validation

ruledoc validates the entire config before running and gives clear error messages:

✗ Invalid config:
  • unknown format "xml" — valid formats: md, json, html, context
  • extension "ts" must start with a dot (e.g. ".ts")
  • pattern is not a valid regex: Unterminated character class

Custom tag

Use a different annotation name:

{ "tag": "bizrule" }

Now ruledoc matches @bizrule(...) instead of @rule(...).

Custom severities

{ "severities": ["low", "medium", "high", "blocker"] }

The first value is the default when severity is omitted.

Custom regex

For full control, provide a regex with two capture groups — (1) params inside parens and (2) description:

{
  "pattern": "(?:\\/\\/|#)\\s*@business\\(([^)]+)\\)\\s*:\\s*(.+)"
}

When pattern is set, it overrides tag.

Use with Turborepo

// package.json
{ "scripts": { "rules": "ruledoc" } }
// turbo.json
{
  "tasks": {
    "rules": {
      "inputs": ["src/**/*.ts", "src/**/*.tsx"],
      "outputs": ["BUSINESS_RULES.md", "BUSINESS_RULES.json"]
    }
  }
}

Dev server + rules watcher side by side:

turbo watch dev rules --filter=web

Programmatic API

Use ruledoc as a library in your own tools:

import { extractRules, resolveConfig, generateMarkdown } from "ruledoc";

const config = resolveConfig([], process.cwd());
const { rules, warnings } = extractRules(config);
const md = generateMarkdown(rules, warnings, config.src);

Security

ruledoc is designed to be safe:

  • No eval — config is loaded from JSON only, never executed as code
  • No runtime deps — zero third-party dependencies in production
  • Read-only scanning — source files are never modified
  • No network — everything runs locally (Pro license validation is the only exception, and it's cached)

Example

See examples/saas-billing/ for a working demo with ~10 annotated rules across billing, auth, and notification modules.

License

MIT