✔ Rust 1.80+ Static Binary ⚡ Zero C Runtime Dependencies 🔄 7 CI/CD Platforms 🤖 AI Agent Drift Sentinel

Universal CI/CD Diff Sentinel &
AI Coding Agent Gatekeeper

Traverses AST diffs via tree-sitter over merge-base git graphs. Rejects assertion weakening, vacuous tests, unannotated unsafe, test suppression, and algorithmic regressions across pull requests and merge requests.

12

Active Fail-Closed Gates

4

AST Language Packs (RS, PY, TS, PHPT)

7

Supported CI Integrations

0

External Network Calls

Why Discipline?

Autonomous AI agents in an iterate-until-green loop optimize for passing tests, not preserving invariants. Discipline halts erosion at the gate.

🌳

Tree-Sitter AST Diff Inspection

Unlike fragile regex checks that trigger on comments or log messages, Discipline parses the complete AST of changed functions against the merge base. It accurately counts executable assertions and distinguishes real invariants from dead code.

tree-sitter-rust tree-sitter-python tree-sitter-javascript
🤖

AI Coding Agent Guardrails

Flags silent test erosion: assertion count reductions (e.g. assert_eq!assert!), test suppression (#[ignore], @pytest.mark.skip, it.skip), tautological vacuous tests (assert!(true)), and stealth test deletions.

Claude Code Gemini CLI Codex / Copilot
🔒

Fail-Closed Engineering

If git history cannot be resolved, a clone is shallow, or a configuration file is malformed, Discipline exits with code 2. It never yields a false-positive pass on broken pipelines or empty diff outputs.

exit 0: pass exit 1: violation exit 2: error
📊

Native MR & PR Reporting

Discipline emits industry-standard reports without external plugins: GitLab Code Quality diffs, JUnit test widgets, GitHub PR comments, GitHub Actions Annotations, and SARIF security tabs.

SARIF 2.1.0 JUnit XML Code Climate JSON
Platform Integration Guides

First-class support across all enterprise CI/CD systems, container runtimes, and local developer hooks.

Composite GitHub Action publishing workflow annotations, SARIF code scanning results, and PR status checks.

# .github/workflows/discipline.yml name: Discipline Sentinel on: pull_request: types: [opened, synchronize, reopened, edited] permissions: contents: read pull-requests: write security-events: write jobs: sentinel: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Ensure git merge-base is reachable - name: Run Discipline Sentinel uses: orieg/discipline@v0 with: fail_on_warnings: false

Native GitLab CI/CD integration. Populates GitLab Merge Request Code Quality diffs and JUnit test reports.

# .gitlab-ci.yml using the Discipline CI/CD Component include: - component: $CI_SERVER_FQDN/orieg/discipline/discipline@v0.1.0 inputs: stage: test allow_failure: false # Or standalone job definition: discipline:gate: stage: test image: name: ghcr.io/orieg/discipline:latest entrypoint: [""] variables: GIT_STRATEGY: clone GIT_DEPTH: 0 rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH before_script: - git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME --depth=100 || true script: # Under $GITLAB_CI, automatically outputs gl-codequality.json and junit.xml - discipline check artifacts: reports: codequality: gl-codequality.json junit: junit.xml paths: - gl-codequality.json - junit.xml when: always

Native support for Forgejo Actions running via forgejo-runner. Supports workflows in .forgejo/workflows/ with automatic base ref and PR event detection.

# .forgejo/workflows/discipline.yml name: Forgejo Sentinel Gate on: pull_request: types: [opened, synchronize] jobs: discipline: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run Discipline uses: https://github.com/orieg/discipline@v0 with: binary_path: /opt/discipline/discipline

Runs seamlessly under self-hosted Gitea act_runner. Zero JavaScript runtime required.

# .gitea/workflows/discipline.yml name: Gitea Sentinel Gate on: pull_request: types: [opened, synchronize] jobs: discipline: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run Discipline uses: https://github.com/orieg/discipline@v0 with: binary_path: /opt/discipline/discipline

Kubernetes-native pre-merge gating for GitOps and continuous deployment pipelines.

# Argo Workflow DAG Task Reference - name: run-discipline-gate templateRef: name: discipline-sentinel template: discipline-gate arguments: parameters: - name: repo-url value: "https://github.com/org/repo.git" - name: target-branch value: "main" - name: source-branch value: "feat/my-pr"

Non-root, minimal static Alpine image for local containers or custom CI runners.

# Pull official static container image docker pull ghcr.io/orieg/discipline:latest # Mount repository and execute diff check against origin/main docker run --rm \ -v "$PWD":/workspace \ -w /workspace \ ghcr.io/orieg/discipline:latest check --base origin/main

Git hook configuration preventing non-compliant commits before they reach remote branches.

# .pre-commit-config.yaml repos: - repo: https://github.com/orieg/discipline rev: v0.1.0 hooks: - id: discipline # Compiles via cargo # - id: discipline-system # Or uses binary on PATH

Direct command-line execution for local developers, script automation, and self-checks.

# Run full gate check against merge-base discipline check --base origin/main # Run check on staged changes before committing discipline check --staged # Inspect registry of gates and current configuration discipline gates # Run embedded verification controls discipline self-test
Active Gate Reference

Every gate operates with fail-closed semantics, truthful examination counts, and explicit remediation instructions.

Gate ID Category Severity Languages Rule Description
agents-md Agent Guard Error Any AGENTS.md exists; CLAUDE.md / GEMINI.md do not fork it
assertion-reduction Agent Guard Error Rust, Python, JS/TS, PHPT, Java, Go assertion count / strength must not drop in an existing test
vacuous-tests Agent Guard Error Rust, Python, JS/TS, PHPT, Java, Go new tests must carry a non-tautological assertion
ignored-tests Agent Guard Error Rust, Python, JS/TS, PHPT, Java, Go tests must not be newly #[ignore]d
unsafe-safety-comment Agent Guard Error Rust unsafe blocks / impls carry a // SAFETY: comment
deletion-rationale Agent Guard Error Any deleted files and removed tests need a scoped removes: rationale
time-estimates Hygiene Error Any no calendar / duration estimates in markdown or the PR body
pii Hygiene Error Any no home paths, LAN IPs, or denylisted hostnames in tracked text
agent-scratch Hygiene Error Any agent scratch state is never tracked
config-integrity Integrity Error Any a change cannot weaken its own discipline.toml without a token
golden-output Integrity Error Any prevents stealth edits to committed golden/test output files without explicit override
bench-regression Performance Error Rust, Go, Python, C/C++ benchmark drift via harness adapters (deterministic counts or BCa intervals)

Audit-Trailed Override Directives

Legitimate deletions or changes are authorized through explicit, scoped directives in the PR description or commit message:

removes: tests/legacy/ replaced by proptest property suite
allow-assertion-drop: test_allocator single large allocation split into benchmark
allow-ignore: test_darwin_kqueue requires macos runner environment
allow-golden-update: tests/snapshots/v2.snap updated for new serializer format

Composite Action Inputs

Complete input parameters for GitHub Actions, Gitea Actions, and Forgejo Actions:

Input Default Description
config discipline.toml Path to discipline.toml. When the file is absent, built-in defaults apply (every available gate on).
suite all Suite to run: all, agent-guard, hygiene, integrity
base_ref (none) Branch or commit the change is measured against. Default: PR base branch, else the pushed-from commit, else the default branch.
enable (none) Gate ids to force on (comma or newline separated). See `discipline gates`.
disable (none) Gate ids to force off (comma or newline separated), e.g. "time-estimates, pii".
config_override (none) Inline TOML merged over discipline.toml: tables merge, lists append, scalars replace.
hostname_denylist (none) Hostnames the pii gate must reject (comma or newline separated). Pass a secret; matches are never echoed.
fail_on_warnings false Treat warnings as failures.
fail_on_overrides false Treat applied overrides as failures (requires human sign-off).
directive_sources (none) Comma-separated list of allowed directive sources (pr-body, commits).
pr_body ${{ github.event.pull_request.body }} PR description: carries override directives and is itself scanned by hygiene gates.
working_directory . Directory of the repository to check.
version (none) Release to download (e.g. v0.1.0). Default: the tag this action was referenced by, else the latest release.
binary_path (none) Use this discipline binary instead of downloading one (air-gapped Gitea/Forgejo runners, self-tests).
download_url https://github.com/orieg/discipline/releases Base URL of the release store, for mirrors.

Composite Action Outputs

Step outputs emitted by the composite action:

Output Description
status pass, fail, or error
errors Number of blocking violations
warnings Number of non-blocking violations
failed_gates Comma separated ids of the gates that reported a violation
overrides Number of applied override directives
overridden_gates Comma separated ids of the gates that had an override applied
report Path of the JSON report
install_error Why installing the binary failed (empty on success)
Architecture & Execution Model

Zero-dependency, standalone binary operating entirely in-memory and offline.

┌───────────────────────────────┐ │ PR / MR Head Git Commit │ └───────────────┬───────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ GitCtx: Resolves merge-base against Target Ref │ │ (git2 in-memory diff, fail-closed on shallow) │ └──────────────────────────┬──────────────────────────┘ │ ┌──────────────┴──────────────┐ ▼ ▼ ┌────────────────────────┐ ┌────────────────────────┐ │ Tree-Sitter AST Diff │ │ Hygiene & Policy │ │ • Assertion counters │ │ • No time estimates │ │ • Vacuous test AST │ │ • PII & LAN scrub │ │ • // SAFETY: comments │ │ • Scratch state deny │ │ • Test skip detection │ │ • Directives parsing │ └────────────┬───────────┘ └────────────┬───────────┘ │ │ └──────────────┬──────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ Gate Evaluator: Computes outcomes & verifies floors │ └──────────────────────────┬──────────────────────────┘ │ ┌─────────────────────────┼─────────────────────────┐ ▼ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ GitLab Reports │ │ GitHub Checks │ │ Exit Code │ │ • Code Quality │ │ • PR Comments │ │ • 0: Pass │ │ • JUnit XML │ │ • Workflow Annot │ │ • 1: Violations │ │ • JSON / SARIF │ │ • SARIF Upload │ │ • 2: Gate Error │ └──────────────────┘ └──────────────────┘ └──────────────────┘
Installation & Distribution

Available as a pre-compiled static binary, container image, or from source via Cargo.

Cargo (From Source)

cargo install --git https://github.com/orieg/discipline

Pure Rust build requiring rustc 1.80+.

Docker Container

docker pull ghcr.io/orieg/discipline:latest

Non-root Alpine container with static binary.

GitLab CI/CD Component

component: $CI_SERVER_FQDN/orieg/discipline@v0.1.0

GitLab 16.0+ CI/CD Catalog Component.

GitHub Action

uses: orieg/discipline@v0

Composite action with automatic binary bootstrap.

Forgejo Action

uses: https://github.com/orieg/discipline@v0

Compatible with Forgejo Actions and forgejo-runner.

Gitea Action

uses: https://github.com/orieg/discipline@v0

Compatible with self-hosted Gitea and act_runner.

Pre-Commit Hook

repo: https://github.com/orieg/discipline

Local git pre-commit hook (discipline / discipline-system).