✔ Rust 1.90+ Static Binary ⚡ Zero C Runtime Dependencies 🔄 9 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 and mock-only tests, stub bodies, swallowed errors, test suppression, loosened toolchain configuration, widened agent and container sandboxes, and text aimed at the next agent, across pull requests and merge requests. And it guards its own trust boundary: a change cannot switch its run to advisory or excuse itself without review.

46

Fail-Closed Gates

14

AST Language Packs

9

Supported CI Integrations

0

Network Calls by the Default Gates

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 counts executable assertions and distinguishes real invariants from dead code: an assertion under if false or after a return counts for nothing, and a property-test budget inside a string or comment is not a budget. Fourteen packs: Rust, Python, JavaScript / TypeScript, Java, Go, PHP, C, C++, C#, Ruby, Kotlin, Swift, Scala and Objective-C, plus a section parser for PHPT test files.

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 and retries (#[ignore], @pytest.mark.flaky, it.skip), tautological or mock-only tests (assert!(true), toHaveBeenCalled alone), stealth test deletions, stub bodies even when padded with a log line (todo!(), raise NotImplementedError), swallowed errors (except: pass, a handler that only logs, let _ = fallible(), rescue nil, PHP @call()), a snapshot added for a test that already existed, a repointed lockfile entry, hard-coded sleeps and not-null-only assertions, and injection text in comments, PR descriptions or agent instruction files.

Claude Code Codex CLI Cursor Aider Copilot CLI Antigravity Qwen Code OpenCode MCP
🔒

Fail-Closed Engineering

If the base ref or the merge base cannot be resolved (a clone too shallow to reach it, a branch never fetched), 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. The trust boundary is guarded too: a change cannot switch its own run to advisory, disable config-integrity, loosen tsconfig.json / ruff.toml / [lints] / coverage floors, mask the CI step, or add a postinstall hook or a .npmrc registry that runs on every install, without a scoped directive.

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
Audit the Escape Hatches

Every waiver, loosened option, grandfathered finding and protected-path edit your merged history carried, ranked by what it could hide, with a link to the exact line on your forge.

discipline audit report: a ranked Needs a decision list led by a loosening of ratified-paths in #270, and a strip of checks marked found, checked or not checked discipline audit report: a ranked Needs a decision list led by a loosening of ratified-paths in #270, and a strip of checks marked found, checked or not checked

Ranked, not raw

Signals such as a loosened guard gate, a loosening pushed without a pull request, or one never tightened back lead the page, each with the next thing to check.

Honest about gaps

With --forge it reads owner ratifications, reviews and pull-request descriptions; with --replay, which waivers lifted anything. Whatever it cannot tell, such as which agent made a change, is marked not checked, never shown as clean.

One page, linked to the source

discipline audit --format html writes a self-contained page that loads nothing. Each row opens the file and line, the diff or the commit on GitHub, GitLab, Gitea or Forgejo.

Platform Integration Guides

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

Composite GitHub Action writing workflow annotations, a step summary and step outputs. comment: true adds one pull-request comment (needs pull-requests: write); DISCIPLINE_REPORT_SARIF plus an upload step adds code scanning (guide).

# .github/workflows/discipline.yml name: Discipline Sentinel on: pull_request: types: [opened, synchronize, reopened, edited] permissions: contents: read jobs: sentinel: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 # Ensure git merge-base is reachable - name: Run Discipline Sentinel uses: orieg/discipline@49f0d47e774244615e084e207784a9a0e6082cd5 # v0.29.0

The action is pinned by commit SHA because the default ci-integrity gate rejects a newly added action that is not, @v0 included. A SHA ref runs the binary of the release that commit names. The step fails on errors only; add fail_on_warnings: true under with: once the warnings are fixed or baselined.

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

# .gitlab-ci.yml including the Discipline job template, pinned to a release include: - remote: https://raw.githubusercontent.com/orieg/discipline/v0.29.0/templates/discipline.gitlab-ci.yml inputs: stage: test allow_failure: false # Or standalone job definition: discipline:gate: stage: test image: name: ghcr.io/orieg/discipline:v0 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 || 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

Runs under forgejo-runner from .forgejo/workflows/, with the base ref and pull-request event detected automatically. edited re-runs the check when the pull-request description (and a directive in it) changes.

# .forgejo/workflows/discipline.yml name: Forgejo Sentinel Gate on: pull_request: types: [opened, synchronize, reopened, edited] jobs: discipline: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false # the job's token can write - name: Run Discipline uses: https://github.com/orieg/discipline@49f0d47e774244615e084e207784a9a0e6082cd5 # v0.29.0 # Runner without internet access: with: { binary_path: /opt/discipline/discipline }

Runs under self-hosted Gitea act_runner. The action itself is shell-only; the runner image needs git, curl (or wget) and Node.js for actions/checkout. Reference the action by its full URL, since the runner resolves a bare owner/repo against your own instance.

# .gitea/workflows/discipline.yml name: Gitea Sentinel Gate on: pull_request: types: [opened, synchronize, reopened, edited] jobs: discipline: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false # the job's token can write - name: Run Discipline uses: https://github.com/orieg/discipline@49f0d47e774244615e084e207784a9a0e6082cd5 # v0.29.0 # Runner without internet access: 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" - name: pr-body value: "" - name: discipline-image value: "ghcr.io/orieg/discipline:v0"

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.29.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 # What a gate checks, and what your last 50 merged changes would have hit discipline explain assertion-reduction discipline replay --last 50

Tell the agent while it edits: after an edit that weakens a test, the hook hands the agent the finding and its repair, judged by the default branch's configuration so the change cannot switch its own check off. Where the agent supports it, a pre-tool entry refuses an edit into another worktree before it runs, and a session-start entry takes this worktree's lease.

# Claude Code, Codex, Cursor, Aider, Copilot CLI, agy, Qwen Code or OpenCode discipline hook install --agent claude-code # Any MCP client: register the server (tools: check_diff, list_gates, explain_finding) claude mcp add discipline -- discipline mcp # What the agent reads after an edit that weakens a test (exit 2) ### Issue 1 [assertion-reduction/assertions-reduced]: Assertion Count Decreased In Existing Test - Location: `tests/cart.rs:6` - Problem: ```text Test `adds`: effective assertions dropped from 2 to 0. ``` - Repair: Restore the assertions that were removed or weakened ...

Every agent's contract, the MCP registration for each client, and what a change cannot do to its check: Agent Hooks and MCP Server.

Azure Pipelines, Bitbucket Pipelines, CircleCI and Jenkins templates, and the full wiring for each platform: CI/CD Platform Integration Guide.

Active Gate Reference

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

Showing 46 of 46 gates
Gate ID Category Default Languages Rule Description
agents-md Agent Guard Warning Any AGENTS.md exists; CLAUDE.md / GEMINI.md do not fork it
assertion-reduction Agent Guard Error Rust, PHPT, Python, JS/TS, Java, Go, PHP, C/C++, C#, Ruby, Kotlin, Swift, Scala, Objective-C assertion count / strength must not drop in an existing test
vacuous-tests Agent Guard Error Rust, PHPT, Python, JS/TS, Java, Go, PHP, C/C++, C#, Ruby, Kotlin, Swift, Scala, Objective-C new tests must carry a non-tautological assertion
ignored-tests Agent Guard Error Rust, PHPT, Python, JS/TS, Java, Go, PHP, C/C++, C#, Ruby, Kotlin, Swift, Scala, Objective-C tests must not be newly #[ignore]d or skipped without directive
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 Warning Any no calendar / duration estimates in markdown or the PR body
pii Hygiene Error Any no home paths, LAN IPs, denylisted hostnames, or fixed-format token literals (private-key headers; AWS, GitHub, Slack, OpenAI and Anthropic token formats; literal bearer headers) in tracked text: literal format matching, not credential scanning
agent-scratch Hygiene Error Any agent scratch state is never tracked
shell-secrets Hygiene Error shell, docker, workflows no secrets on command lines, fixed-format token literals, or unverified piped scripts in shell, docker, or CI files: literal pattern matching, not secret scanning
issue-link Hygiene Off Any PR title or description links a tracking issue (#123, Fixes #123)
review-threads Hygiene Off Any the pull request has no unresolved review thread
ratified-paths Agent Guard Off Any edits to protected paths carry an owner's ratification on an issue the pull request closes
citation-metadata Hygiene Error Any CITATION.cff and .zenodo.json are valid, agree with each other, and cite the concept DOI
commit-provenance Hygiene Off Any commits carry the required trailers; an agent-produced commit carries a review by someone else
config-integrity Integrity Error Any a change cannot weaken its own discipline.toml without a token
stub-bodies Agent Guard Error Rust, Python, JS/TS, Java, Go, PHP, C/C++, C#, Ruby, Kotlin, Swift, Scala, Objective-C added functions are not stubs; existing bodies are not replaced by todo!() / NotImplementedError / return null
harness-tampering Agent Guard Error Go, Python, JS/TS, Rust a file the test runner loads does not make a failing run pass
error-swallowing Agent Guard Error Rust, Python, JS/TS, Java, Go, PHP, C/C++, C#, Ruby, Kotlin, Swift, Scala, Objective-C no new empty error handler or discarded Result outside tests
instruction-smuggling Agent Guard Error any (invisible characters, instruction files); Rust, Python, JS/TS, Java, Go, PHP, C/C++, C#, Ruby, Kotlin, Swift, Scala, Objective-C and prose files (phrases) no invisible Unicode, unreviewed agent-instruction edits, or instruction-like text in comments and prose
build-hooks Integrity Error package.json, build.rs, setup.py, .npmrc, .pypirc, pip.conf, .cargo/config.toml, .env* install and build hooks that gain network or shell access, and package-manager configuration edits, need a token
toolchain-config Integrity Error tsconfig, ruff, mypy, pytest (addopts flags and -k / -m selection), coverage, flake8, Cargo lints, rustflags, nextest, eslintrc, golangci, jest and vitest (JSON or a literal object), package.json test scripts, codecov, phpstan, phpunit, and compiler warning flags in Makefile, CMake, setup.py and build.rs compiler, linter, type-checker, test-runner and coverage configuration cannot be loosened without a token
sandbox-config Integrity Error Claude Code, Codex, Gemini CLI, Qwen Code, OpenCode, Cursor and Copilot CLI settings, MCP server lists, devcontainer.json, Docker Compose, CI job and service containers a change cannot widen an agent's permissions or sandbox, or a container's isolation, without a token
scope-confinement Agent Guard Off Any changes stay inside authorized paths
suppression-delta Agent Guard Warning per pack newly added linter / compiler suppression annotations
provenance-tags Hygiene Off Any published numerics carry (measured|target|projected)
ci-integrity Integrity Error Any workflow weakening: continue-on-error, || true, unpinned actions
ci-skip-set Integrity Error Any rollup skip set matches each job's `if:` under the observed filter outputs
test-floor Integrity Error Any test-count ratchet read from the base ref
golden-output Integrity Error Any prevents stealth edits to committed golden/test output files without explicit override
dependency-delta Integrity Error Any manifest diff inspection: zero wildcards, source/license allowlists, and deny.toml verification
test-budget Integrity Error Rust, Python, JS/TS, Go, any property-test and fuzz effort ratchet (cases, shrink iters, fuzztime, seed corpus)
pr-checklist Hygiene Off Any ticked PR checkboxes and declared touched surfaces are reconciled against the diff
command Verification Error Any fail-closed wrapper for any tool: zero-tests guard, canary, count ratchet
sanitizers Verification Off Rust, C/C++ ASan / TSan preset with audited suppressions and a race canary
msrv Quality Off Rust cargo check under the pinned MSRV
miri Verification Off Rust Miri tiers with zero-tests guard
unsafe-budget Verification Off Rust unsafe count ratchet
bench-regression Performance Warning Rust, Go, Python, C/C++ benchmark drift via harness adapters (deterministic counts or BCa intervals)
archive-contents Integrity Off Any distribution archive must contain required paths and zero forbidden developer artifacts
manifest-sync Integrity Off Any reconcile git-tracked files against packaging manifest declarations
version-lockstep Integrity Off Any version declarations across headers, manifests, and files must remain in lockstep
gate-command-lint Agent Guard Off markdown, shell reject vacuous, masked, or inverted verification commands in plan files
mechanism-sections Hygiene Off markdown require (inferred) or (verified: <target>) evidence tags in root cause sections
citation-anchors Hygiene Off markdown, any verify path:line@sha citations against quoted text and git history, and relative Markdown links against the tree
claim-labels Hygiene Off markdown, any require RUN or READ labels on verification claims in PR bodies, commits, and Markdown

Audit-Trailed Override Directives

Legitimate deletions or changes are authorized through explicit, scoped directives in the PR description or commit message; on a push to the default branch, the merged pull request's body is read through the forge (merged-pr-body), because a squash or rebase merge drops it from the commit message. Every applied override is recorded in the report; directives.max_overrides caps them per change, and directives.require_approval makes them count only once the forge shows an approving review of the head commit by a listed reviewer other than the author. policy_from: base judges a change by the base branch's discipline.toml, so a policy edit takes effect once it has merged.

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 allow-stub: validate schema lands with the next migration allow-toolchain-weakening: strict migrating the legacy tree file by file allow-sandbox-widening: defaultMode the eval harness runs in a throwaway VM with no credentials allow-agent-instructions: AGENTS.md the new rule was reviewed in #90 allow-build-hook: prepare husky installs the commit hooks allow-gate-weakening: ci-integrity the discipline step runs on pull_request only; merged-pr-body covers pushes

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 default discipline.toml is absent, built-in defaults apply (each gate at its built-in default enablement and severity); any other path that does not exist is an error (exit 2).
suite all Suite to run: all, agent-guard, hygiene, integrity, quality, verification, bench
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 the overrides a change writes as failures (requires human sign-off); inline markers already in the tree are not counted.
advisory false Advisory mode: run all checks and emit reports, but exit code 0 even if violations occur.
comment false Post the report as one pull-request comment, edited on every run. Needs `pull-requests: write` (GitHub) or a token that can comment; a fork's read-only token is reported, not failed.
token ${{ github.token }} Forge token handed to discipline: read by the gates that ask the forge (issue-link verify_references, ratified-paths, review-threads, require_approval; GitHub GraphQL needs a token), and used to post the comment when `comment` is true.
policy_from head Which side's discipline.toml judges the change: 'head' (the change's own copy) or 'base' (the base ref's, so a policy edit takes effect once merged; config-integrity still reports it).
actor ${{ github.event.pull_request.user.login || github.actor }} Login judged against allowed_override_actors. Default: the pull request author (github.event.pull_request.user.login), which the server sets; otherwise github.actor or the forge equivalent. The triggering login is not used on a pull request, since whoever edits the description must not be able to authorize their own override.
directive_sources (none) Comma-separated list of allowed directive sources (pr-body, commits, merged-pr-body). merged-pr-body reads, on a push event, the body of the merged pull request each pushed commit arrived through.
pr_body ${{ github.event.pull_request.body }} PR description: carries override directives and is itself scanned by hygiene gates.
pr_title ${{ github.event.pull_request.title }} PR title: checked by hygiene gates (e.g. issue-link).
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 (`@vX.Y.Z`); for a major tag, a commit SHA or a branch, the release in the action''s own Cargo.toml; the latest release only when neither is available.
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: https://, file://, or http:// to a loopback address. Set DISCIPLINE_INSTALL_ALLOW_INSECURE_HTTP=1 in the environment to accept another cleartext mirror.
require_provenance false Fail the install, before the binary runs, when its build provenance cannot be verified (provenance output unverified). A binary_path binary is accepted. Set it on a mirror install once the mirror serves discipline.intoto.jsonl and the runner has gh.
trusted_root (none) Path on the runner to a Sigstore trusted root (the output of gh attestation trusted-root) for the bundle check of a mirror install, so it needs no network. Never take it from the mirror itself. Default: Sigstore TUF repository, online.
install_only false Install discipline and put it on PATH for the steps that follow, without running a check. For `.github/workflows/copilot-setup-steps.yml`, so the hooks of Copilot cloud agent find the binary.
baseline_file (none) Path to grandfathering baseline file (defaults to discipline-baseline.toml if present).
no_baseline false Ignore grandfathering baseline even if present.
ci_context (none) Rollup job only: `toJson(needs)` of the rollup job (inline JSON, or a path to a file holding it) for the ci-skip-set gate. Empty: the gate reports "not evaluated".
test_report (none) Path to test report XML file relative to repo root (JUnit XML) for test-floor identity ratcheting.
test_base_report (none) In-job base test report XML file for test-floor identity ratcheting in dual-report mode.
test_head_report (none) In-job head test report XML file for test-floor identity ratcheting in dual-report mode.

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
baselined Number of grandfathered findings matching baseline (not blocking)
overridden_gates Comma separated ids of the gates that had an override applied
passed_gates Number of passing gates
examined_items Total number of items examined across all enabled gates
report Path of the JSON report
provenance How the binary was checked: verified (the build provenance attestation of the discipline release workflow, from the GitHub API or from the Sigstore bundle discipline.intoto.jsonl of a mirror), unverified (SHA256SUMS of the release store only: no gh, or a mirror without the bundle), or local (binary_path)
install_error Why installing the binary failed (empty on success)
bin Path to the installed discipline executable
Architecture & Execution Model

Zero-dependency, standalone binary. With the default gates, a pull-request run reads git in memory and makes no network requests; the forge-reading gates (issue-link verification, review-threads, ratified-paths) and --comment are opt-in.

PR / MR Head Git Commit Working copy / incoming push ref GitCtx: Resolves merge-base against Target Ref In-memory git2 diff • No network with the default gates • Exit 2 when no merge base resolves Tree-Sitter AST Diff Engine 14 language packs behind shared fact model Assertion count & strength ratchets Vacuous & ghost test rejection // SAFETY: justification invariants Skips, retries, stubs, mocks & swallowed errors Hygiene, Integrity & Policy Whole-tree text, manifest & metadata sweeps No calendar deadlines or time estimates Workstation paths, LAN IPs & PII scrub Agent scratch state deny (.claude/, scratch/) Lockfile, toolchain, CI, build-hook & config integrity Gate Evaluator: Computes Outcomes & Verifies Floors Strict 5-layer config resolution • Truthful examined counts • Line-anchored directives GitLab & Multi-CI • Code Quality (gl-codequality.json) • JUnit XML test reports • SARIF & JSON machine output GitHub & Forgejo Checks • PR review comments & summaries • Native workflow annotations • GitHub Code Scanning SARIF Fail-Closed Exit Code 0: All gates pass 1: Policy or AST violations 2: Gate error or unresolved base
Installation & Distribution

Available as a one-line installer, native APT/RPM packages, Homebrew formula, pre-compiled static binary, container image, or from source via Cargo.

Install the binary

Quick install Linux & macOS

Download, verify, run. Or the one-liner curl -fsSL https://orieg.github.io/discipline/install.sh | bash.

curl -fsSL -o install.sh https://orieg.github.io/discipline/install.sh \ && bash install.sh

Homebrew macOS & Linux

Native formula for Apple Silicon, Intel macOS, and Linux.

brew install orieg/tap/discipline

APT Debian / Ubuntu

Signed APT repo for Debian 11+ and Ubuntu 20.04+. Browse repo →

curl -fsSL https://orieg.github.io/discipline/apt/discipline-archive-keyring.gpg \ | sudo tee /usr/share/keyrings/discipline-archive-keyring.gpg >/dev/null \ && echo "deb [signed-by=/usr/share/keyrings/discipline-archive-keyring.gpg] \ https://orieg.github.io/discipline/apt/ stable main" \ | sudo tee /etc/apt/sources.list.d/discipline.list \ && sudo apt update && sudo apt install -y discipline

RPM RHEL / Fedora

Signed RPM repo (repository metadata is GPG-verified) for RHEL 8/9/10, Fedora, CentOS, Rocky, Alma. Browse repo →

sudo dnf config-manager --add-repo \ https://orieg.github.io/discipline/rpm/discipline.repo \ && sudo dnf install -y discipline

MacPorts macOS

A generated Portfile is attached to each release; install it from a local ports tree (see the README).

mkdir -p ~/ports/devel/discipline \ && curl -fsSL -o ~/ports/devel/discipline/Portfile \ https://github.com/orieg/discipline/releases/latest/download/Portfile

Cargo crates.io

Builds with rustc 1.90+ and a C compiler (vendored libgit2 and the C tree-sitter grammars).

cargo install discipline

Docker container

Non-root Alpine container with static binary.

docker pull ghcr.io/orieg/discipline:latest

Shell completions

The APT, RPM, Homebrew and MacPorts packages install bash, zsh and fish completions, and a release tarball carries them under completions/. For a Cargo install, generate them into your shell's completion directory and regenerate after each upgrade (see the README).

discipline completions zsh > ~/.zfunc/_discipline

Add it to CI and hooks

GitHub Action

Composite action with automatic binary bootstrap. Pinned by commit SHA, which the default ci-integrity gate requires.

uses: orieg/discipline@49f0d47e774244615e084e207784a9a0e6082cd5 # v0.29.0

GitLab CI/CD

Job template with spec: inputs (GitLab 16.0+), pinned to a release.

include: - remote: https://raw.githubusercontent.com/orieg/discipline/v0.29.0/templates/discipline.gitlab-ci.yml

Forgejo Action

Compatible with Forgejo Actions and forgejo-runner.

uses: https://github.com/orieg/discipline@49f0d47e774244615e084e207784a9a0e6082cd5 # v0.29.0

Gitea Action

Compatible with self-hosted Gitea and act_runner.

uses: https://github.com/orieg/discipline@49f0d47e774244615e084e207784a9a0e6082cd5 # v0.29.0

pre-commit hook

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

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