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

@rickheere/archtest

v1.3.0

Published

Architectural drift detection through declarative rules

Readme

archtest

npm version npm downloads license CI

Architectural drift detection through declarative rules. Any language with import statements.

Define boundaries in YAML. Enforce them with grep. Let your AI write the rules.

archtest turns implicit architectural knowledge (the stuff that lives in people's heads and PR review comments) into executable constraints. Rules are declarative YAML. Enforcement is deterministic pattern matching. AI agents write the rules because regex is what they're good at, but nothing about runtime enforcement involves AI. It's grep. Fast, predictable, CI-friendly.

The Problem

Everyone knows architectural rules. "The orchestrator shouldn't import strategy internals." "The database layer shouldn't know about the API." But nobody writes the checks because regex and glob patterns are tedious expert-level string manipulation.

So boundaries erode. With AI coding agents it's worse: they don't smell architectural intent, and after 20 incremental changes you have spaghetti.

The Insight

LLMs write grep patterns like humans write sentences. The LLM authors the rules, the human reviews them, the test runner executes them. The human never touches regex.

Quick Start

Tell your AI coding agent:

Run npx @rickheere/archtest interview to scan our codebase,
then ask me about the boundaries we should enforce.

The agent will:

  1. Run archtest interview. The tool reports it needs --ext and --import-pattern flags
  2. Figure out your language and provide the right flags (e.g. --ext .go --import-pattern '^\s*"([^"]+)"')
  3. Run the interview again, this time scanning imports and mapping your directory structure
  4. Ask you questions about which boundaries matter
  5. Write .archtest.yml rules based on your answers (using archtest schema and archtest examples)
  6. Run archtest to verify the rules pass (or catch existing violations)

Manual Setup

npx @rickheere/archtest init        # Creates a starter .archtest.yml
npx @rickheere/archtest schema      # Shows the YAML format reference
npx @rickheere/archtest examples    # Shows common rule patterns

Edit .archtest.yml, then run:

npx @rickheere/archtest             # Check rules, show failures
npx @rickheere/archtest --verbose   # Show all rules with per-file breakdown

Example Rules

scan:
  extensions: [.ts, .tsx]
  import-patterns:
    - 'require\s*\(\s*[''"]([^''"]+)[''"]\s*\)'
    - '(?:import|export)\s+.*?\s+from\s+[''"]([^''"]+)[''"]'
  skip-dirs: [vendor]

rules:
  - name: no-deep-imports-into-auth
    description: "Import auth/ only through its index, not internal files"
    scope:
      files: ["**/*.ts"]
      exclude: ["auth/**"]
    deny:
      patterns:
        - "from ['\"].*auth/(?!index)"

  - name: no-db-in-domain
    level: warn  # warn = shown but won't fail CI; error (default) = blocks CI
    description: "Domain layer must not import database modules"
    scope:
      files: ["domain/**/*.ts"]
    deny:
      patterns:
        - "from ['\"].*database"
        - "prisma|knex|sequelize"

The scan section tells archtest which files to scan and how to extract imports. Both extensions and import-patterns are required. Save them in config so archtest interview works with no flags next time.

Any Language

archtest works on any language with greppable import syntax. You provide --ext and --import-pattern (a regex where capture group 1 is the import target), and archtest does the rest.

# Go
archtest interview --ext .go --import-pattern '^\s*"([^"]+)"'

# Python
archtest interview --ext .py \
  --import-pattern 'from\s+(\S+)\s+import' \
  --import-pattern 'import\s+(\S+)'

# Kotlin / Java
archtest interview --ext .kt --import-pattern 'import\s+([\w.]+)'

# Clojure
archtest interview --ext .clj \
  --import-pattern '\[([a-z][a-z0-9_-]*(?:\.[a-z][a-z0-9_-]*)+)' \
  --import-pattern '\(([a-z][a-z0-9_-]*(?:\.[a-z][a-z0-9_-]*)+)\s+[A-Z]'

# Rust
archtest interview --ext .rs --import-pattern 'use\s+([\w:]+)'

Built-in hints exist for JS/TS, Go, Python, Rust, JVM, and Clojure. The tool suggests the right --import-pattern when it detects these languages. For everything else, your AI agent can figure out the pattern from a sample import line.

Monorepos

Each sub-project can have its own .archtest.yml with different scan settings. Config lookup cascades upward from --base-dir to the repo root. Nearest config wins.

my-monorepo/
  backend/.archtest.yml     # extensions: [.clj], import-patterns for Clojure
  mobile/.archtest.yml      # extensions: [.ts, .tsx], import-patterns for JS/TS
  .archtest.yml             # shared rules (optional)
archtest interview --base-dir backend/    # Uses backend/.archtest.yml
archtest interview --base-dir mobile/     # Uses mobile/.archtest.yml

CI Integration

archtest exits with code 1 on failure. Add it to your test pipeline:

{
  "scripts": {
    "test": "vitest && archtest"
  }
}

Why This Exists Now

Enforcing architectural boundaries isn't a new idea. ArchUnit does it for Java. But it never scaled beyond single-language, class-level analysis because the hard part was always writing the rules: regex patterns, glob expressions, exclusion logic. Tedious, error-prone, expert work.

AI makes rule authoring cheap. Describe a boundary in natural language, have an agent produce the YAML with correct patterns. The bottleneck that kept this approach impractical for 20 years is gone.

archtest can be a simple grep-based runner because the complexity was never in enforcement. It was in rule authoring.

Philosophy

Stable systems are not created by controlling how code gets written. They are created by enforcing invariants on the result.

A PR reviewer might catch an architectural violation today and miss it tomorrow. An AI agent will never notice that its 15th incremental change crossed a boundary the first 14 respected. A grep rule catches it every time.

archtest makes architectural drift as visible as a failing test. The rule file is the contract between human intent and machine enforcement. Human-readable YAML that anyone can review, with regex patterns inside that AI writes because that's what AI is good at.

No AI at runtime. No LLM calls during archtest. Pure pattern matching. Fast, predictable, cacheable.

Not a Workflow Tool

archtest does not orchestrate AI agents, manage tasks, or sequence work. It does not care who wrote the code, how it was written, or what process produced it.

It checks the result against declared invariants. That's it.

If your agent wrote clean code that respects boundaries, archtest passes. If it drifted, archtest fails. The agent sees the failure, reads the rule, and fixes the violation. Same as a failing unit test.

archtest is a test tool, not a process tool.

CLI Reference

| Command | Description | |---|---| | archtest | Run rules against the codebase | | archtest --verbose | Show all rules and per-file breakdown | | archtest --config <path> | Use a specific rule file | | archtest interview | Scan codebase and generate an architectural interview | | archtest schema | Show the YAML rule file schema | | archtest examples | Show example rules for common patterns | | archtest init | Generate a starter .archtest.yml |

Install

npm install @rickheere/archtest

Or run directly without installing:

npx @rickheere/archtest

License

MIT