Enforce your team's architecture rules on every PR. Deterministic, config-first, free to scan.
3
stars
37
commits
TypeScript
primary language
Aug 23, 2026
updated
Enforce your team's architectural contracts on every pull request — deterministically, at zero scan token cost, with instant AI remediation.
$ npx archsentry scan --config archsentry.yml --path src --explain
❌ ArchSentry found 1 violation(s) (1 error, 0 warnings):
• [error] no-direct-sql src/controllers/user.controller.ts:7
All database writes must go through the repository layer.
> await db.query("INSERT INTO users (email, name) VALUES ($1, $2)", [payload.email, payload.name]);
💡 Remediation: All database writes must go through the repository layer. Move this call
behind the appropriate service or repository layer so the access path is centralized
and reviewable, rather than issued directly from `src/controllers/user.controller.ts`.
$ echo $?
1
AI coding assistants (Cursor, Copilot, Claude Code) generate thousands of lines of code per day. While standard linters catch syntax errors and SAST tools detect known CVE vulnerabilities, neither understands your system's architecture.
LLM review bots burn hundreds of dollars per repo summarizing diffs without guaranteeing architectural compliance.
ArchSentry solves this with a two-phase architecture:
| Feature | Legacy SAST (SonarQube, Snyk) | Linters (ESLint, Biome) | AI Review Bots (Codium, Copilot PR) | 🛡️ ArchSentry |
|---|---|---|---|---|
| Primary Focus | Known CVEs & security vulnerabilities | Code style, syntax, and formatting | Generic natural language commentary | Custom architectural boundaries & contracts |
| Scan Cost | Heavy license fees | Free | $0.05–$0.50+ per PR diff in LLM tokens | $0 (Deterministic AST & Pattern Engine) |
| Scan Latency | 20s – 5 mins | < 1s | 15s – 60s (LLM API queue) | < 100ms |
| Deterministic Guarantee | ✅ Yes | ✅ Yes | ❌ No (LLM hallucinations & flakiness) | ✅ 100% Deterministic |
| Architectural Scope | ❌ None (generic rules) | ⚠️ Limited (complex plugin ASTs) | ⚠️ Probabilistic (misses subtle invariants) | ✅ Declarative YAML Contracts |
| Actionable AI Fix Hints | ❌ Generic docs link | ❌ Static message | ⚠️ Verbose noise | ✅ Targeted, contextual fix explanations |
npx)No installation required. Run directly in any repository:
# Scan a path against your contract
npx archsentry scan --config archsentry.yml --path .
# With optional AI remediation hints:
npx archsentry scan --config archsentry.yml --path . --explain
# Filter findings to modified lines in a git diff:
git diff main...HEAD | npx archsentry scan --config archsentry.yml --diff -
0: Clean scan. All architectural invariants satisfied.1: Architectural violations detected (severity: error).2: Runtime error (missing configuration file, malformed YAML, or invalid path).Add .github/workflows/archsentry.yml to your repository:
name: ArchSentry Architectural Gate
on:
pull_request:
branches: [main, master, develop]
push:
branches: [main, master]
jobs:
archsentry-scan:
name: Architectural Integrity Gate
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Run ArchSentry Gate
run: npx --yes archsentry scan --config archsentry.yml --path .
env:
# Optional: provides instant AI remediation hints on violations
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
ArchSentry can also run as a dedicated Probot-powered GitHub App that automatically reviews PRs, posts inline architectural remediation comments, and cleans up stale comments upon push.
# Clone & install dependencies
pnpm install
# Configure credentials
cp .env.example .env
# Set APP_ID, WEBHOOK_SECRET, PRIVATE_KEY_PATH, and OPENROUTER_API_KEY
# Start Probot webhook listener
pnpm start
Fail-closed mode: by default the App logs (but does not surface) a failure to load
archsentry.yml from a repo that has one. Set ARCHSENTRY_FAIL_CLOSED=1 to instead post a
warning comment stating the rules were not verified — the right choice for teams that
treat unverified rules as a blocker.
Architectural contracts are declared in archsentry.yml at the root of your project:
version: 1
rules:
# 1. Zero-dependency Pattern Matcher
- id: no-direct-db-in-controllers
type: pattern
severity: error
description: "Controllers must route data queries through the repository layer."
match:
patterns:
- "db.query("
- "connection.query("
- "INSERT INTO"
- "UPDATE "
- "DELETE FROM"
paths:
- "src/controllers/**"
- "apps/api/controllers/**"
exclude:
- "src/repositories/**"
- "**/tests/**"
# 2. AST-Aware Semgrep Matcher (Auto-upgrades when semgrep CLI is available)
- id: no-raw-eval
type: semgrep
severity: error
description: "Do not call eval() or new Function() in application code."
semgrep:
languages: ["typescript", "javascript"]
pattern-either:
- pattern: eval(...)
- pattern: new Function(...)
paths:
include:
- "src/**"
exclude:
- "**/*.spec.ts"
# 3. Warning Severity Rule
- id: avoid-console-log-in-production
type: pattern
severity: warn
description: "Use structured logger (logger.info / logger.error) instead of console.log."
match:
patterns:
- "console.log("
paths:
- "src/**"
exclude:
- "src/scripts/**"
# 4. Dependency Boundary Rule (zero-dependency, understands imports)
# Files matching `from` may not import targets matching `forbid`.
# Relative imports are resolved to project paths first, so this catches
# "../repositories/user" from a controller even without file extensions.
- id: controllers-import-only-domain
type: import
severity: error
description: "Controllers may import only from their own domain and shared code."
remediation: "Move shared logic into src/shared or the controller's own domain module."
import:
from: ["src/controllers/**"]
forbid:
- "src/repositories/**"
- "src/other-domain/**"
allow:
- "src/shared/**"
# 5. Multi-line Pattern Rule (matches across the whole file)
- id: no-multiline-fetch
type: pattern
severity: error
description: "No direct fetch calls, even when the call spans multiple lines."
match:
patterns:
- "fetch("
multiline: true
paths:
- "src/**"
| Field | Type | Required | Description |
|---|---|---|---|
version | number | Yes | Contract schema version (must be 1). |
rules[].id | string | Yes | Unique identifier ([a-zA-Z0-9_-]). |
rules[].type | "pattern" | "semgrep" | "import" | Yes | Rule engine backend. pattern requires 0 external tools; semgrep runs AST queries; import enforces dependency boundaries. |
rules[].description | string | Yes | Plain-English rationale for the rule. |
rules[].severity | "error" | "warn" | No | Default error. error exits 1; warn informs without breaking the build. |
rules[].remediation | string | No | Author-provided fix guidance. Shown in reports and used as ground truth by the AI explainer. |
rules[].match.patterns | string[] | Yes (pattern) | Substrings / tokens that trigger violations. |
rules[].match.multiline | boolean | No | Default false (line-by-line). When true, patterns match across the whole file so multi-line constructs are caught. |
rules[].match.paths | string[] | No | Globs specifying which file paths are subject to enforcement. |
rules[].match.exclude | string[] | No | Globs specifying paths exempt from this rule. |
rules[].import.forbid | string[] | Yes (import) | Import targets that are not allowed. Relative specifiers are resolved to project paths before matching; bare specifiers match as-is. |
rules[].import.from | string[] | No | Globs for files this boundary applies to (default: all files). |
rules[].import.allow | string[] | No | Exceptions to forbid (checked first). |
rules[].import.regex | boolean | No | Treat forbid/allow as real RegExp instead of globs. |
rules[].semgrep | object | Yes (semgrep) | Native Semgrep rule definition object (pattern, pattern-either, languages). |
When --explain is enabled (or running via PR comment bot), ArchSentry derives remediation hints using whichever provider key is detected in the environment:
| Provider | Environment Variable | Default Model | Notes |
|---|---|---|---|
| OpenRouter | OPENROUTER_API_KEY | nvidia/nemotron-3-ultra-550b-a55b:free | 100% Free Tiers Available (no card required) |
| OpenAI | OPENAI_API_KEY | gpt-4o-mini | High-speed, commercial grade |
| Ollama | OLLAMA_MODEL | Set by env (e.g. llama3) | 100% Local & Air-gapped (localhost:11434) |
| Offline Fallback | (None) | Built-in Template Engine | Zero-cost, zero-network deterministic hints |
# Clone the repository
git clone https://github.com/comerade2134/archsentry.git
cd archsentry
# Install dependencies
pnpm install
# Run unit & integration test suites
pnpm test
# Typecheck and build standalone binary
pnpm typecheck
pnpm run build
MIT © comerade2134
37 commits
TypeScript
99.4%
Enforce your team's architecture rules on every PR. Deterministic, config-first, free to scan.
3
stars
37
commits
TypeScript
primary language
Aug 23, 2026
updated
Enforce your team's architectural contracts on every pull request — deterministically, at zero scan token cost, with instant AI remediation.
$ npx archsentry scan --config archsentry.yml --path src --explain
❌ ArchSentry found 1 violation(s) (1 error, 0 warnings):
• [error] no-direct-sql src/controllers/user.controller.ts:7
All database writes must go through the repository layer.
> await db.query("INSERT INTO users (email, name) VALUES ($1, $2)", [payload.email, payload.name]);
💡 Remediation: All database writes must go through the repository layer. Move this call
behind the appropriate service or repository layer so the access path is centralized
and reviewable, rather than issued directly from `src/controllers/user.controller.ts`.
$ echo $?
1
AI coding assistants (Cursor, Copilot, Claude Code) generate thousands of lines of code per day. While standard linters catch syntax errors and SAST tools detect known CVE vulnerabilities, neither understands your system's architecture.
LLM review bots burn hundreds of dollars per repo summarizing diffs without guaranteeing architectural compliance.
ArchSentry solves this with a two-phase architecture:
| Feature | Legacy SAST (SonarQube, Snyk) | Linters (ESLint, Biome) | AI Review Bots (Codium, Copilot PR) | 🛡️ ArchSentry |
|---|---|---|---|---|
| Primary Focus | Known CVEs & security vulnerabilities | Code style, syntax, and formatting | Generic natural language commentary | Custom architectural boundaries & contracts |
| Scan Cost | Heavy license fees | Free | $0.05–$0.50+ per PR diff in LLM tokens | $0 (Deterministic AST & Pattern Engine) |
| Scan Latency | 20s – 5 mins | < 1s | 15s – 60s (LLM API queue) | < 100ms |
| Deterministic Guarantee | ✅ Yes | ✅ Yes | ❌ No (LLM hallucinations & flakiness) | ✅ 100% Deterministic |
| Architectural Scope | ❌ None (generic rules) | ⚠️ Limited (complex plugin ASTs) | ⚠️ Probabilistic (misses subtle invariants) | ✅ Declarative YAML Contracts |
| Actionable AI Fix Hints | ❌ Generic docs link | ❌ Static message | ⚠️ Verbose noise | ✅ Targeted, contextual fix explanations |
npx)No installation required. Run directly in any repository:
# Scan a path against your contract
npx archsentry scan --config archsentry.yml --path .
# With optional AI remediation hints:
npx archsentry scan --config archsentry.yml --path . --explain
# Filter findings to modified lines in a git diff:
git diff main...HEAD | npx archsentry scan --config archsentry.yml --diff -
0: Clean scan. All architectural invariants satisfied.1: Architectural violations detected (severity: error).2: Runtime error (missing configuration file, malformed YAML, or invalid path).Add .github/workflows/archsentry.yml to your repository:
name: ArchSentry Architectural Gate
on:
pull_request:
branches: [main, master, develop]
push:
branches: [main, master]
jobs:
archsentry-scan:
name: Architectural Integrity Gate
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Run ArchSentry Gate
run: npx --yes archsentry scan --config archsentry.yml --path .
env:
# Optional: provides instant AI remediation hints on violations
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
ArchSentry can also run as a dedicated Probot-powered GitHub App that automatically reviews PRs, posts inline architectural remediation comments, and cleans up stale comments upon push.
# Clone & install dependencies
pnpm install
# Configure credentials
cp .env.example .env
# Set APP_ID, WEBHOOK_SECRET, PRIVATE_KEY_PATH, and OPENROUTER_API_KEY
# Start Probot webhook listener
pnpm start
Fail-closed mode: by default the App logs (but does not surface) a failure to load
archsentry.yml from a repo that has one. Set ARCHSENTRY_FAIL_CLOSED=1 to instead post a
warning comment stating the rules were not verified — the right choice for teams that
treat unverified rules as a blocker.
Architectural contracts are declared in archsentry.yml at the root of your project:
version: 1
rules:
# 1. Zero-dependency Pattern Matcher
- id: no-direct-db-in-controllers
type: pattern
severity: error
description: "Controllers must route data queries through the repository layer."
match:
patterns:
- "db.query("
- "connection.query("
- "INSERT INTO"
- "UPDATE "
- "DELETE FROM"
paths:
- "src/controllers/**"
- "apps/api/controllers/**"
exclude:
- "src/repositories/**"
- "**/tests/**"
# 2. AST-Aware Semgrep Matcher (Auto-upgrades when semgrep CLI is available)
- id: no-raw-eval
type: semgrep
severity: error
description: "Do not call eval() or new Function() in application code."
semgrep:
languages: ["typescript", "javascript"]
pattern-either:
- pattern: eval(...)
- pattern: new Function(...)
paths:
include:
- "src/**"
exclude:
- "**/*.spec.ts"
# 3. Warning Severity Rule
- id: avoid-console-log-in-production
type: pattern
severity: warn
description: "Use structured logger (logger.info / logger.error) instead of console.log."
match:
patterns:
- "console.log("
paths:
- "src/**"
exclude:
- "src/scripts/**"
# 4. Dependency Boundary Rule (zero-dependency, understands imports)
# Files matching `from` may not import targets matching `forbid`.
# Relative imports are resolved to project paths first, so this catches
# "../repositories/user" from a controller even without file extensions.
- id: controllers-import-only-domain
type: import
severity: error
description: "Controllers may import only from their own domain and shared code."
remediation: "Move shared logic into src/shared or the controller's own domain module."
import:
from: ["src/controllers/**"]
forbid:
- "src/repositories/**"
- "src/other-domain/**"
allow:
- "src/shared/**"
# 5. Multi-line Pattern Rule (matches across the whole file)
- id: no-multiline-fetch
type: pattern
severity: error
description: "No direct fetch calls, even when the call spans multiple lines."
match:
patterns:
- "fetch("
multiline: true
paths:
- "src/**"
| Field | Type | Required | Description |
|---|---|---|---|
version | number | Yes | Contract schema version (must be 1). |
rules[].id | string | Yes | Unique identifier ([a-zA-Z0-9_-]). |
rules[].type | "pattern" | "semgrep" | "import" | Yes | Rule engine backend. pattern requires 0 external tools; semgrep runs AST queries; import enforces dependency boundaries. |
rules[].description | string | Yes | Plain-English rationale for the rule. |
rules[].severity | "error" | "warn" | No | Default error. error exits 1; warn informs without breaking the build. |
rules[].remediation | string | No | Author-provided fix guidance. Shown in reports and used as ground truth by the AI explainer. |
rules[].match.patterns | string[] | Yes (pattern) | Substrings / tokens that trigger violations. |
rules[].match.multiline | boolean | No | Default false (line-by-line). When true, patterns match across the whole file so multi-line constructs are caught. |
rules[].match.paths | string[] | No | Globs specifying which file paths are subject to enforcement. |
rules[].match.exclude | string[] | No | Globs specifying paths exempt from this rule. |
rules[].import.forbid | string[] | Yes (import) | Import targets that are not allowed. Relative specifiers are resolved to project paths before matching; bare specifiers match as-is. |
rules[].import.from | string[] | No | Globs for files this boundary applies to (default: all files). |
rules[].import.allow | string[] | No | Exceptions to forbid (checked first). |
rules[].import.regex | boolean | No | Treat forbid/allow as real RegExp instead of globs. |
rules[].semgrep | object | Yes (semgrep) | Native Semgrep rule definition object (pattern, pattern-either, languages). |
When --explain is enabled (or running via PR comment bot), ArchSentry derives remediation hints using whichever provider key is detected in the environment:
| Provider | Environment Variable | Default Model | Notes |
|---|---|---|---|
| OpenRouter | OPENROUTER_API_KEY | nvidia/nemotron-3-ultra-550b-a55b:free | 100% Free Tiers Available (no card required) |
| OpenAI | OPENAI_API_KEY | gpt-4o-mini | High-speed, commercial grade |
| Ollama | OLLAMA_MODEL | Set by env (e.g. llama3) | 100% Local & Air-gapped (localhost:11434) |
| Offline Fallback | (None) | Built-in Template Engine | Zero-cost, zero-network deterministic hints |
# Clone the repository
git clone https://github.com/comerade2134/archsentry.git
cd archsentry
# Install dependencies
pnpm install
# Run unit & integration test suites
pnpm test
# Typecheck and build standalone binary
pnpm typecheck
pnpm run build
MIT © comerade2134
37 commits
TypeScript
99.4%