v1.0.0

Arklint

Enforce import boundaries, dependency rules, and layer constraints across your codebase. Define your architecture in YAML - Arklint checks it automatically, before violations ever reach main.

Prevention, not detection
Language-agnostic
100% local
Quick setup
MCP server for AI agents
$pip install arklint
Python 3.10+ · Core CLI with all features
$npx arklint check
Node 16+ · Auto-downloads prebuilt binary · No Python needed
$dotnet tool install -g arklint
.NET 8.0+ · NuGet global tool · Auto-downloads prebuilt binary
1
Define rules
Write constraints in .arklint.yml
2
Run the check
Scans every file against every rule
3
Enforce in CI
Block violations before they reach main
Terminal~/my-project
$ arklint check

Arklint v1.0.0 - Scanning 142 files against 5 rules...

  ✗ FAIL  no-direct-db-in-routes
         routes/users.py → imports 'sqlalchemy' - blocked
         routes/orders.py → imports 'psycopg2' - blocked

  ✗ FAIL  single-http-client
         conflicting packages - keep one of requests, httpx

  ⚠ WARN  no-print-statements
         services/email.py:45 → banned pattern: 'print('

  ✓ PASS  models-in-models-dir
  ✓ PASS  layered-architecture

────────────────────────────────────────────────────
Results: 2 errors, 1 warning, 2 passed

Overview #

Your codebase has architectural rules. Nobody enforces them. Arklint does.

The problem nobody talks about

You’ve seen this happen. A pull request lands where a route handler imports directly from the database. Or an AI agent generates three files - clean code, wrong layer. Or requirements.txt quietly grows to include both requests and httpx because nobody was watching.

Code review catches some of this. Linters check syntax and style. But there’s nothing - until now - that enforces structural intent: which module can import which, which packages can coexist, which patterns belong in which directories.

Without enforcement, the architecture degrades. Rules exist only as comments in a wiki nobody reads.

What Arklint does

You write your architectural rules in a plain YAML file. Arklint checks them against your entire codebase in seconds - and blocks violations in CI before they ever merge.

.arklint.ymlyaml
version: "1"

rules:
  - id: no-direct-db-in-routes
    type: boundary
    description: "Route handlers must not import database drivers directly"
    source: "routes/**"
    blocked_imports:
      - "sqlalchemy"
      - "psycopg2"
    severity: error

  - id: single-http-client
    type: dependency
    description: "Use exactly one HTTP client library"
    allow_only_one_of:
      - "requests"
      - "httpx"
    severity: error

Run the check:

Terminalbash
$ arklint check

  ✗ FAIL  no-direct-db-in-routes
         routes/users.py → imports 'sqlalchemy' - blocked
         routes/orders.py → imports 'psycopg2' - blocked

  ✗ FAIL  single-http-client
         conflicting packages detected - keep one of: requests, httpx

  ✓ PASS  models-in-models-dir
  ✓ PASS  layered-architecture

Results: 2 errors, 2 passed

Violations are errors. Errors fail the pipeline. The architecture stays clean.

What it checks

Arklint ships with five rule types covering the most common architectural violations:

Rule type What it enforces
boundary Which directories can import which packages
dependency Which libraries can coexist in your dependency file
file-pattern Where specific code patterns are allowed to live
pattern-ban Regex patterns that must never appear in the codebase
layer-boundary The allowed import direction between architectural layers

Where it runs

Locally - arklint check while you build; arklint watch for live feedback on every save.

Pre-commit - block violations before they’re committed.

CI - arklint check --strict fails the pipeline. --diff origin/main makes it fast on large repos by scanning only changed files.

Inside AI coding tools - the MCP server lets Claude Code, Cursor, and Copilot check code before writing it. The export command writes your rules into .cursorrules or CLAUDE.md so AI agents understand your architecture natively.

Core concepts

Concept Description
Rule A single architectural constraint - one type, one id, one severity
.arklint.yml The config file where all your rules live
Pack A shareable bundle of rules for a framework (e.g. arklint/fastapi)
Check arklint check - scans every file against every rule
MCP server Exposes your rules to AI agents via the Model Context Protocol

Get started

Python

Terminalbash
$ pip install arklint
$ arklint init
$ arklint check

Node.js

Terminalbash
$ npm install -g arklint
$ arklint init
$ arklint check

.NET

Terminalbash
$ dotnet tool install -g arklint
$ arklint init
$ arklint check

Installation #

Arklint is available on PyPI, npm, and NuGet.

Which method should I use?

Feature pip (PyPI) npm .NET (NuGet)
arklint check
arklint watch
arklint diff
arklint visualize
arklint learn
arklint mcp ✓ (with [mcp] extra)
Python required Yes (3.10+) No No

All three methods run the same binary. Use npm or .NET if you are not in a Python project. Use pip if you want the MCP server extra or need to contribute.

Python (PyPI)

Requires Python 3.10+.

Terminalbash
$ pip install arklint

For MCP server support (AI agent integration):

Terminalbash
$ pip install 'arklint[mcp]'

For AI-powered rule generation with arklint learn (already bundled in npm/.NET, only needed here):

Terminalbash
$ pip install 'arklint[ai-anthropic]'   # Claude (Anthropic)
$ pip install 'arklint[ai-openai]'      # GPT-4o-mini (OpenAI)
Note: The pip extras are named ai-anthropic and ai-openai - with the ai- prefix. pip install arklint[anthropic] will fail. The --provider flag uses just anthropic / openai (no prefix) - a different naming from the pip extras.

Node.js (npm)

A thin wrapper that auto-downloads the platform-specific prebuilt binary on first run. No Python required.

Terminalbash
# Run directly without installing
$ npx arklint check

# Or install globally
$ npm install -g arklint
$ arklint check

Supports Linux x64, macOS ARM64 (Apple Silicon), and Windows x64.

.NET (NuGet)

A .NET global tool wrapper. Auto-downloads the prebuilt binary and caches it at ~/.arklint/bin/. Requires .NET 8.0+.

Terminalbash
$ dotnet tool install -g arklint
$ arklint check
Zero cloud dependency - Arklint sends no data anywhere. Everything runs on your machine. The npm and .NET wrappers simply download a prebuilt binary and cache it locally.

Quick Start #

Get from install to your first architecture check in four steps.

1. Generate a starter config

Run arklint init in your project root. Arklint detects your ecosystem (Python, Node.js, or .NET) and generates a .arklint.yml with sensible starter rules for that stack.

Terminalbash
$ cd ~/my-project
$ arklint init

2. Edit your rules

Open .arklint.yml and tailor the rules to your architecture - import boundaries, banned patterns, layered dependencies - all in readable YAML.

.arklint.ymlyaml
version: "1"

rules:
  - id: no-direct-db-in-routes
    type: boundary
    description: "API routes must not import database modules"
    source: "routes/**"
    blocked_imports:
      - "sqlalchemy"
      - "psycopg2"
    severity: error

  - id: no-print-statements
    type: pattern-ban
    pattern: 'print\('
    exclude:
      - "tests/**"
    severity: warning

3. Run the check

Scan your codebase. Add flags as needed:

Terminalbash
$ arklint check
$ arklint check --strict       # exit 1 on warnings too
$ arklint check --json         # JSON output for CI
$ arklint check --diff main    # only scan changed files

4. Add to your workflow

  • Watch mode - instant feedback as you code: arklint watch
  • Pre-commit hook - block violations before they’re committed
  • CI gate - fail the pipeline on violations
  • GitHub Action - first-class Action with diff mode and version pinning

See CI / Pre-commit and GitHub Action for ready-to-copy configs.

Rule Types #

Arklint ships with five rule types. Each targets a specific class of architectural violation. All are language-agnostic and configured in `.arklint.yml`.

Common fields

Common fields

Every rule shares these fields:

Field Required Description
id Yes Unique identifier for the rule (e.g. no-direct-db-in-routes)
type Yes Rule type: boundary, dependency, file-pattern, pattern-ban, or layer-boundary
description Yes Human-readable explanation shown in violation output
severity Yes error (fails the check) or warning (informational unless --strict)
exclude No List of glob patterns to skip. Supported by boundary, file-pattern, and pattern-ban
boundary

Import Restrictions

Block files in a source directory from importing specific packages. Keep API routes away from raw database drivers.

.arklint.ymlyaml
- id: no-direct-db-in-routes
  type: boundary
  description: "Route handlers must not import database drivers directly"
  source: "routes/**"
  blocked_imports:
    - "sqlalchemy"
    - "psycopg2"
    - "pymongo"
  severity: error
dependency

Package Conflicts

Detect when multiple libraries serving the same purpose exist in your dependency file.

.arklint.ymlyaml
- id: single-http-client
  type: dependency
  description: "Use exactly one HTTP client library"
  allow_only_one_of:
    - "requests"
    - "httpx"
    - "aiohttp"
  severity: error
file-pattern

Code Placement

Ensure certain code patterns only exist in the right directories.

.arklint.ymlyaml
- id: models-in-models-dir
  type: file-pattern
  description: "Model classes must live in models/ or schemas/"
  pattern: 'class\s+\w*Model'
  allowed_in:
    - "models/**"
    - "schemas/**"
  severity: warning
pattern-ban

Banned Patterns

Ban any regex pattern across the codebase with optional directory exclusions.

.arklint.ymlyaml
- id: no-print-statements
  type: pattern-ban
  description: "Use a logger instead of print statements"
  pattern: '(?<!\.)print\('
  exclude:
    - "tests/**"
    - "scripts/**"
  severity: warning
layer-boundary

Layered Architecture

Define layers and control which ones can import from which. Enforce strict dependency direction.

.arklint.ymlyaml
- id: layered-architecture
  type: layer-boundary
  description: "Enforce routes → services → repositories dependency direction"
  layers:
    - name: routes
      path: "routes/**"
    - name: services
      path: "services/**"
    - name: repositories
      path: "repositories/**"
  allowed_dependencies:
    routes: [services]
    services: [repositories]
    repositories: []
  severity: error

Rule Packs #

Rule packs are shareable bundles of arklint rules for a specific framework or architecture pattern. Use them to get started in seconds without writing rules from scratch.

Browsing packs

Terminalbash
$ arklint search fastapi
$ arklint search django
$ arklint search clean

Adding a pack

Terminalbash
$ arklint add arklint/fastapi
Fetching pack 'arklint/fastapi'…
✓ Added arklint/fastapi (4 rules) to .arklint.yml
  Run arklint validate to confirm.

This appends the pack to the extends list in your .arklint.yml. Your own rules always take precedence - if you define a rule with the same id as a pack rule, yours wins.

Official packs

Pack Rules Description
arklint/fastapi 4 FastAPI service/route/schema separation, single HTTP client
arklint/django 4 Django model/view/serializer placement, no raw SQL in views
arklint/nextjs 3 Next.js server/client boundary, no DB in server actions
arklint/express 3 Express route/service separation, no console.log in prod
arklint/clean-arch 2 Clean architecture layer ordering, no framework in entities

Using extends manually

.arklint.ymlyaml
# .arklint.yml
version: "1"
extends:
  - arklint/fastapi
  - arklint/clean-arch
  - ./local-packs/my-company.yml   # local file packs also work

rules:
  # project-specific rules - these override pack rules with the same id
  - id: fastapi/no-db-in-routes
    type: boundary
    description: "Customised version of the pack rule"
    source: "api/**"
    blocked_imports: ["sqlalchemy", "psycopg2", "motor"]
    severity: error

Local packs

Point extends at a relative path to share rules across a monorepo:

.arklint.ymlyaml
extends:
  - ../../shared/arklint-rules.yml

The referenced file must have the same structure as a named pack - a rules: list at the top level.

Contributing a pack

See packs/CONTRIBUTING.md for the full guide. No Python required - just YAML.

CLI Reference #

Every command and flag Arklint supports.

Command Description
arklint init Generate a starter .arklint.yml in the current directory
arklint init --force Overwrite an existing config file
arklint check Scan the codebase from the current directory
arklint check <path> Scan a specific directory
arklint check --strict Exit with code 1 on warnings (not just errors)
arklint check --quiet / -q Suppress passing rules - only show failures and warnings
arklint check --json Machine-readable JSON output for CI pipelines
arklint check --diff <ref> Only scan files changed vs a git ref
arklint check --github-annotations Emit GitHub Actions inline PR annotations
arklint check -c <path> Use a config file from a custom path
arklint validate Validate .arklint.yml without running any checks
arklint validate -c <path> Validate a config file at a custom path
arklint search <query> Search official rule packs by name, description, or tag
arklint add <pack> Add an official rule pack to .arklint.yml
arklint export --format <fmt> Export rules as an AI assistant instruction file
arklint export --output <dir> Write exported file to a specific directory
arklint learn --describe <text> Generate a rule from a plain-English description using AI
arklint learn --provider <name> AI provider: anthropic or openai (required)
arklint learn --append Append suggested rule to .arklint.yml without prompting
arklint visualize Print a Mermaid diagram of your architecture rules
arklint visualize -o <file> Write diagram to a file instead of stdout
arklint watch Watch for file changes and re-run checks automatically
arklint watch --strict Watch mode with strict severity
arklint mcp Start the MCP server (stdio) for AI agent integration
arklint --version Show version and exit

Watch Mode #

Re-run architecture checks automatically on every file save. Get instant feedback without switching to a terminal.

Terminalbash
$ arklint watch
$ arklint watch ./src
$ arklint watch --strict

How it works

Watch mode uses watchdog to monitor filesystem events in your project directory. On every file change, Arklint re-runs all checks and prints the updated results.

What triggers a re-run: - Any file save or creation in the watched directory tree - Changes to .arklint.yml itself

What is automatically ignored: - Hidden directories (.git, .venv, etc.) - __pycache__, dist, build, node_modules

Press Ctrl+C to stop.

Options

Flag Description
<path> Directory to watch. Defaults to current directory
--strict Treat warnings as errors
-c / --config <path> Use a config file from a custom path

Typical usage

Run it once when you start coding and leave it in the background. Any violation you introduce shows up immediately.

Terminalbash
$ arklint watch ./src --strict
Watching ./src for changes…  (Ctrl+C to stop)

[12:34:01] Change detected - re-running checks…

  ✗ FAIL  no-direct-db-in-routes
         routes/orders.py → imports 'psycopg2' - blocked

[12:34:09] Change detected - re-running checks…

  ✓ PASS  no-direct-db-in-routes
  ✓ PASS  no-print-statements
  ✓ PASS  layered-architecture

Diff Mode #

Scan only the files that changed - not the entire codebase. Keeps CI fast on large repositories and makes PR checks precise.

Terminalbash
$ arklint check --diff HEAD             # staged + unstaged changes vs HEAD
$ arklint check --diff origin/main      # files changed on your branch vs main
$ arklint check --diff main --strict    # fail on warnings too

How it works

Diff mode runs git diff --name-only <ref> under the hood to get the list of changed files, then restricts scanning to only those files. All rules still apply - only the file set is narrowed.

This means: - A boundary rule only fires if a changed file has the forbidden import - A pattern-ban rule only fires on changed files - dependency rules always scan the full dependency file (since any change can introduce a conflict)

Why use it

On a repo with thousands of files, arklint check scans everything every run. In CI, that can be slow. With --diff origin/main, only the files touched by the pull request are scanned - which is usually the right scope anyway.

Terminalbash
# In CI: only check what this PR changed
arklint check --diff origin/main --strict --github-annotations

Options

Flag Description
--diff <ref> Git ref to diff against (HEAD, origin/main, a commit SHA, etc.)
--strict Treat warnings as errors
--json Machine-readable JSON output
--github-annotations Emit inline PR annotations (for use inside GitHub Actions)
Diff mode requires a git repository. The --diff flag is ignored if no .git directory is found.

Visualize #

Generate a [Mermaid](https://mermaid.live) diagram of your architecture rules directly from `.arklint.yml`.

Terminalbash
$ arklint visualize

Output

The command prints a flowchart LR Mermaid block to stdout. You can paste it into any Markdown file or drop it into mermaid.live to render it interactively.

For a three-layer setup the output looks like:

Code
flowchart LR

    subgraph arch_layers ["Clean layers"]
        routes["routes\nroutes/**"]
        services["services\nservices/**"]
        repositories["repositories\nrepositories/**"]
        routes --> services
        routes -. blocked .-> repositories
        services --> repositories
        services -. blocked .-> routes
        repositories -. blocked .-> routes
        repositories -. blocked .-> services
    end

Solid arrows (-->) are allowed dependencies. Dashed arrows (-. blocked .->) are blocked ones.

Write to a file

Terminalbash
$ arklint visualize -o docs/architecture.md
✓ Diagram written to docs/architecture.md

You can then embed it in a Markdown page:

Codemarkdown
```mermaid
flowchart LR
    ...
```

GitHub and most documentation platforms render Mermaid natively inside fenced code blocks.

What gets visualised

Rule type Rendered as
layer-boundary Directed graph with allowed/blocked edges per layer
boundary Source directories → blocked import packages
dependency “choose one” node connected to competing packages
pattern-ban Not rendered (text-based, no graph structure)
file-pattern Not rendered (text-based, no graph structure)

Options

Flag Description
-o / --output <file> Write diagram to a file instead of stdout
-c / --config <path> Use a config file from a custom path

MCP Server #

Expose your architectural rules to AI agents via the Model Context Protocol. AI coding tools can check code before writing it - and refuse to generate violations automatically.

Terminalbash
$ pip install 'arklint[mcp]'
$ arklint mcp
The MCP server is bundled in the npm and .NET prebuilt binaries. No extra install needed - run arklint mcp directly.

Available tools

  • list_rules - Returns all configured rules from .arklint.yml with full config details.
  • get_rule_details - Inspect a single rule’s full configuration by its ID.
  • check_file - Validate an existing file against all rules and return violations.
  • check_snippet - Validate a code snippet before writing it to disk. Supports virtual paths for path-based rules.

The check_snippet tool is especially powerful: an AI agent validates code before it exists on disk. Pass a filename parameter (e.g. routes/user.py) so that path-based rules like boundary and file-pattern apply correctly.

Claude Code integration

Add to your Claude Code config (.claude/settings.json or ~/.claude/settings.json):

Configjson
{
  "mcpServers": {
    "arklint": {
      "command": "arklint",
      "args": ["mcp"]
    }
  }
}

Once connected, Claude Code calls check_snippet automatically before writing files that match your rules.

Cursor integration

Add to your Cursor MCP config (.cursor/mcp.json):

Configjson
{
  "mcpServers": {
    "arklint": {
      "command": "arklint",
      "args": ["mcp"]
    }
  }
}

Pair with export for best results

The MCP server handles runtime checks. For AI agents to understand your rules and avoid writing violations in the first place, also export your rules as native AI instructions:

Terminalbash
$ arklint export --format claude      # writes CLAUDE.md
$ arklint export --format cursorrules # writes .cursorrules

This two-layer approach - instructions at generation time, MCP validation at write time - gives the strongest architecture enforcement with AI tools.

Re-run arklint export whenever you update your rules to keep the AI instruction files in sync.

Export Rules #

Export your `.arklint.yml` rules as AI assistant instruction files so your coding tools respect the same architectural constraints.

Terminalbash
$ arklint export --format cursorrules
$ arklint export --format claude
$ arklint export --format copilot

Formats

Format Output file Used by
cursorrules .cursorrules Cursor IDE
claude CLAUDE.md Claude Code
copilot .github/copilot-instructions.md GitHub Copilot

Each file lists your rules with severity tags ([ERROR] / [WARN]) and descriptions in a format the AI understands natively.

Options

Flag Description
--format / -f Output format (required): cursorrules, claude, or copilot
--output / -o Directory to write into. Defaults to current directory
--config / -c Path to .arklint.yml. Auto-discovered if omitted

Example

Terminalbash
$ arklint export --format claude --output .

This writes CLAUDE.md in your project root. Claude Code will automatically pick it up on the next session and respect your architectural rules when generating code.

Re-run arklint export whenever you update your rules to keep the AI instruction files in sync.

AI Rule Generation #

Generate a valid `.arklint.yml` rule from a plain-English description using AI.

Terminalbash
$ arklint learn --describe "no raw SQL queries in route handlers" --provider anthropic
$ arklint learn --describe "no raw SQL queries in route handlers" --provider openai

Arklint prompts the AI with your description and the full rule schema. The AI returns a ready-to-use YAML rule block. You can review it and optionally append it to your .arklint.yml.

The anthropic and openai SDKs are bundled in the prebuilt binary, so arklint learn works out of the box regardless of whether you installed via pip, npm, or .NET. All you need is an API key.

pip install - optional extras

If you installed via pip, install the AI extra for your provider:

Terminalbash
$ pip install 'arklint[ai-anthropic]'   # Claude (Anthropic)
$ pip install 'arklint[ai-openai]'      # GPT-4o-mini (OpenAI)
Note: The pip extras are named ai-anthropic and ai-openai - with the ai- prefix. pip install arklint[anthropic] will fail. The --provider flag uses just anthropic or openai (no prefix) - a different naming from the pip extras.

Options

Flag Description
--describe / -d Plain-English description of the rule (required)
--provider / -p AI provider: anthropic or openai (required)
--api-key API key for the provider. Falls back to ANTHROPIC_API_KEY or OPENAI_API_KEY
--append / -a Append the rule to .arklint.yml without confirmation prompt
--config / -c Path to .arklint.yml. Auto-discovered if omitted

Example session

Terminalbash
$ arklint learn --describe "services must not import from routes" --provider anthropic

Generating rule via anthropic…

Suggested rule:

- id: no-routes-in-services
  type: boundary
  description: Services must not import from route handlers
  source: "services/**"
  blocked_imports:
    - "routes"
  severity: error

Append this rule to .arklint.yml? [y/N]: y
✓ Rule appended to /my-project/.arklint.yml
  Run arklint validate to confirm the config is valid.
Your API key is never stored by Arklint. It is read from the environment variable or --api-key flag and passed directly to the provider’s SDK at runtime.

CI / Pre-commit #

Block architectural violations automatically on every push or commit.

GitHub Actions

The simplest setup - add Arklint to any existing workflow:

.arklint.ymlyaml
- name: Run Arklint
  run: |
    pip install arklint
    arklint check --strict

For large repos, use diff mode to only scan changed files:

.arklint.ymlyaml
- name: Run Arklint (diff)
  run: |
    pip install arklint
    arklint check --diff origin/main --strict --github-annotations

The --github-annotations flag emits inline PR annotations so violations appear directly on the changed lines in the pull request.

Tip: For faster installs, use the GitHub Action directly - it handles caching and version pinning automatically.

pre-commit hook

Add to your .pre-commit-config.yaml:

.arklint.ymlyaml
- repo: local
  hooks:
    - id: arklint
      name: Arklint
      entry: arklint check
      language: python
      pass_filenames: false

Install the hook:

Terminalbash
$ pre-commit install

GitLab CI

.arklint.ymlyaml
arklint:
  stage: lint
  image: python:3.11-slim
  script:
    - pip install arklint
    - arklint check --strict

CircleCI

.arklint.ymlyaml
- run:
    name: Arklint
    command: |
      pip install arklint
      arklint check --strict

Exit codes

Code Meaning
0 All checks passed
1 One or more errors (or warnings with --strict)
2 Config file invalid or not found

All CI systems treat a non-zero exit code as a pipeline failure.

GitHub Action #

Use Arklint as a first-class GitHub Action with built-in diff mode, inline PR annotations, version pinning, and strict mode.

.arklint.ymlyaml
- uses: Kaushik13k/ark-lint@main
  with:
    strict: "true"
    diff: "origin/main"

Full example

.arklint.ymlyaml
name: Arklint

on:
  pull_request:
  push:
    branches: [main]

jobs:
  arklint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: Kaushik13k/ark-lint@main
        with:
          strict: "true"
          diff: "origin/main"
Set fetch-depth: 0 in actions/checkout so the full git history is available for diff mode. Without it, origin/main may not be resolvable.

Inputs

Input Description Default
version Arklint version to install. Pin for reproducible builds. latest
strict Treat warnings as errors ("true" / "false") "false"
diff Only scan files changed vs this ref (e.g. origin/main) (all files)
config Path to .arklint.yml. Auto-discovered if omitted. (auto)
working-directory Directory to run arklint in, for monorepos .

Prerequisites

The action requires a .arklint.yml in your repository root. If it’s missing you’ll see:

Code
Config error: No .arklint.yml found. Run 'arklint init' to create one.

Run this locally first and commit the file:

Terminalbash
arklint init
git add .arklint.yml
git commit -m "chore: add arklint config"
git push

If your config lives elsewhere (e.g. a monorepo), point the action to it explicitly:

.arklint.ymlyaml
- uses: Kaushik13k/ark-lint@main
  with:
    config: "services/api/.arklint.yml"

Inline PR annotations

When diff mode is enabled, the action automatically passes --github-annotations to emit inline annotations on the pull request. Violations appear directly on the changed lines - no need to scroll through logs.

Language Support #

Arklint is language-agnostic. Import extraction and dependency file parsing are built in for the most common languages and package managers - no plugins or configuration needed.

Import extraction

Arklint reads import statements from source files to enforce boundary and layer-boundary rules.

Language File extensions Import syntax detected
Python .py import x, from x import y
JavaScript .js, .mjs, .cjs import, require()
TypeScript .ts, .tsx import, require()
Go .go import "pkg", import ( ... )
Ruby .rb require, require_relative
Rust .rs use crate::, extern crate
Java .java import com.example.Class
C# .cs using Namespace
PHP .php use, require, include

Dependency file parsing

Arklint reads dependency files to enforce dependency rules (e.g. “keep only one HTTP client”).

Package manager File
Python (pip) requirements.txt
Python (modern) pyproject.toml
Node.js package.json
Go go.mod
Rust Cargo.toml
Ruby Gemfile

Language detection

Arklint detects language from file extension automatically. No configuration needed - rules based on file paths (like source: "routes/**") match regardless of the file’s language.

Missing a language? Open an issue or pull request on GitHub. See Contributing.

Contributing #

Arklint is open source and welcomes contributions. Every change goes through a pull request.

Dev setup

Terminalbash
$ git clone https://github.com/Kaushik13k/arklint
$ cd arklint
$ python -m venv .venv && source .venv/bin/activate
$ pip install -e ".[dev]"
$ pytest -v

Ground rules: every PR needs CODEOWNER approval, every source change needs a test, and all CI checks must pass. See CONTRIBUTING.md for the full guide.