ArchRails is the only governance product that gates AI agents before they write code — then enforces the same rules at PR-time. Agentic-friendly auth, federated cross-repo enforcement on the FINOS CALM v1 standard, audit-grade evidence, BYOC deployment. Built for regulated institutions.
logger.info(`tax_id=${trade.tax_id}`)
no-pii-in-logs · matched: tax_idlogger.info(`trade=${trade.id}`)
Every other architecture / governance / lint tool waits for PR-time. By then your agent has already written the wrong code. ArchRails runs inside the agent's MCP session — your controls fire before the diff exists. Then the same engine runs at PR-time as backstop.
Long-lived API keys for AI agents, CI pipelines, and IDE plugins. Humans sign in once at the dashboard to issue a key; agents then run headless. No interactive browser sign-in mid-coding. Designed for autonomous workflows from day one.
Agents can't edit your CALM files to make non-compliant code legal. Architecture changes go through your normal human-reviewed PR process. The gate can't be rewritten by the thing it's gating.
If an agent is bypassed (raw git push, manual edit, a different agent), the merge gate runs the identical Python functions and still catches the violation. Two surfaces, one source of truth.
ArchRails deploys into your AWS account. Your code never leaves your perimeter. The control plane runs in your VPC; architecture files, graphs, and audit artifacts stay in your buckets and your KMS keys. Audit-evidence bundles are written to your storage, not ours. GCP and Azure on the roadmap, available on request.
Architecture governance has lived at PR review forever. ArchRails keeps it there — and ALSO pushes the same rule engine into your IDE so agents catch violations before any code is written. Devs ship faster. Regulators still get the audit trail.
Cursor attempts a forbidden DB call during a 3 AM hotfix. ArchRails MCP blocks it inline; the agent rewrites against the CALM-permitted intermediary. Production stays in PCI scope.
ArchRails doesn't invent standards. It enforces what your team defines in a CALM document, and cites every node it used.
If a node, relationship, or interface constraint isn't in your calm.json, ArchRails won't enforce it. Full stop.
Feedback cites the exact CALM node ID, relationship ID, or interface that triggered it — so teams align faster and argue less.
Reviews resolve only the CALM nodes touched by the PR diff. Less noise, fewer false positives, no cross-service contamination.
This is the architecture graph ArchRails renders for every pull request. Drag nodes. Hover for details. Click any node to see how violations trace back to your CALM definition.
OrderService calls PaymentService directly — must route via service-api-gatewayOrderDatabase accessed via HTTP — node declares JDBC:5432 onlyInventoryService changes scoped to service-inventory — no leakagePaste your calm.json to instantly check for interface violations, missing controls, and structural issues — then render your architecture graph interactively. No account required.
.github/workflows/. Works with self-hosted runners, GitHub Enterprise Server, and air-gapped environments. Architecture review fires on every PR.ARCHRAILS_TENANT_ID and auth uses X-ArchRails-Token. GITHUB_TOKEN is auto-provisioned by Actions.Drop this file into .github/workflows/archrails.yml. Set three repository secrets — GITHUB_TOKEN is provided automatically by GitHub Actions.
# ArchRails Architecture Governance — GitHub CI Mode
# Required secrets: ARCHRAILS_TENANT_ID · ARCHRAILS_TOKEN · ARCHRAILS_WEBHOOK_URL
# GITHUB_TOKEN is auto-provisioned by Actions — no configuration needed.
name: ArchRails Architecture Check
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
jobs:
archrails-check:
name: Architecture Governance
runs-on: ubuntu-latest
permissions:
contents: read # read repo contents for diff fetch
pull-requests: write # post review comments
statuses: write # write commit status
steps:
- name: Send PR event to ArchRails
env:
ARCHRAILS_TENANT_ID: ${{ secrets.ARCHRAILS_TENANT_ID }}
ARCHRAILS_TOKEN: ${{ secrets.ARCHRAILS_TOKEN }}
ARCHRAILS_URL: ${{ secrets.ARCHRAILS_WEBHOOK_URL }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_EVENT: ${{ toJson(github.event) }}
RUN_ID: ${{ github.run_id }}
RUN_ATTEMPT: ${{ github.run_attempt }}
run: |
# Inject archrails_tenant_id and github_token into the PR event payload.
# The workflow's own GITHUB_TOKEN lets downstream Lambdas fetch the diff
# and post review results — no separate installation token required.
PAYLOAD=$(echo "$PR_EVENT" | jq \
--arg tenant_id "$ARCHRAILS_TENANT_ID" \
--arg github_token "$GITHUB_TOKEN" \
'. + {archrails_tenant_id: $tenant_id, github_token: $github_token}')
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
--max-time 30 \
-X POST "$ARCHRAILS_URL" \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: pull_request" \
-H "X-GitHub-Delivery: ${RUN_ID}-${RUN_ATTEMPT}" \
-H "X-ArchRails-CI: github" \
-H "X-ArchRails-Token: $ARCHRAILS_TOKEN" \
-d "$PAYLOAD")
echo "ArchRails response: $HTTP_STATUS"
# 202 = queued | 204 = ignored (draft, disabled, etc.)
# 4xx/5xx = configuration problem — surface it.
if [[ "$HTTP_STATUS" -ge 400 ]]; then
echo "::error::ArchRails rejected the payload (HTTP $HTTP_STATUS). Check ARCHRAILS_TOKEN and ARCHRAILS_TENANT_ID."
exit 1
fi
echo "ArchRails review queued successfully."
https://api.archrails.io/webhook
GitLab integration runs via CI pipeline. Add the job below to your .gitlab-ci.yml and set three CI/CD variables.
stages:
- review
archrails_review:
stage: review
image: alpine:3.20
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
before_script:
- apk add --no-cache curl
script:
- |
curl --silent --fail -X POST "${ARCHRAILS_ENDPOINT}" \
-H "X-Gitlab-Token: ${GITLAB_WEBHOOK_SECRET}" \
-H "X-Gitlab-Event: Merge Request Hook" \
-H "Content-Type: application/json" \
-d "{
\"archrails_tenant_id\": \"${ARCHRAILS_TENANT_ID}\",
\"object_kind\": \"merge_request\",
\"project\": {
\"id\": ${CI_PROJECT_ID},
\"path_with_namespace\": \"${CI_PROJECT_PATH}\"
},
\"object_attributes\": {
\"iid\": ${CI_MERGE_REQUEST_IID},
\"action\": \"update\",
\"last_commit\": { \"id\": \"${CI_COMMIT_SHA}\" }
}
}"
calm.json. Every comment is traceable to a node ID you authored. It's deterministic, not probabilistic, and the same gate runs at PR time and inside the coding agent — so the agent can't reach an API your architecture forbids. As Adam Bender put it at SE@TP 2026: “all of your APIs just became public” the moment you let agents loose. ArchRails is the contract that says which ones they're allowed to call.calm.json at the repo root describes your full system graph, and ArchRails only evaluates the slice of the graph a given PR actually touches — a payment-service change won't trigger inventory-service checks. This is deliberate: dependency graphs scale quadratically with codebase size, so at the 10× AI-driven velocity everyone is preparing for, evaluating everything on every PR is how you burn your test budget into the ground.
Founder & Engineer
ArchRails started as a practical system: keep architecture consistent as teams scale — without relying on tribal knowledge. By grounding reviews in a CALM architecture graph rather than generic training data, every violation is provable and every comment is traceable.
Start with one repo and one CALM document. ArchRails will enforce it on every pull request.