GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • 🛡️ Discipline
  • Tutorial
  • Docs
  • APT
  • RPM
  • GitHub

This view

  • Original page
  • New address

GeezerVison is showing orieg.github.io — Discipline — Universal CI/CD Diff Sentinel & AI Coding Agent Gatekeeper

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 of this repository's last 200 merged changes: the headline, a strip of checks marked found, checked or not checked, and a ranked Needs a decision list discipline audit report of this repository's last 200 merged changes: the headline, a strip of checks marked found, checked or not checked, and a ranked Needs a decision list

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.

Open this repository's audit → Read the reference
Results

Discipline 0.32.0 blocked 17% of merged agent pull requests; a simple baseline rule that blocks any change to a test, CI or configuration file blocked 56%. 84% of discipline's blocks are correct (likely 76–90%), against 2% for that rule. Each agent edit is checked in a few seconds. It does not yet catch most test gaming: on a public benchmark it blocked 8% of agents' edits that made impossible tests pass, short of the 80% set in advance.

How often does it block?

Discipline 0.32.0 blocked 40 of 232 merged coding-agent pull requests (17%); a simple rule that blocks any change to a test, CI or configuration file blocked 130 (56%). Discipline 0.32.0 blocked 40 of 232 merged coding-agent pull requests (17%); a simple rule that blocks any change to a test, CI or configuration file blocked 130 (56%).

Were those blocks right?

84% of discipline's blocks are correct: 103 of 122, likely 76–90%, or 59–95% per pull request. The simple rule: 3 of 150 (2%). By check: CI workflow changes 66 of 66, swallowed errors 10 of 11, changed expected outputs 11 of 13, new dependencies 9 of 20. 84% of discipline's blocks are correct: 103 of 122, likely 76–90%, or 59–95% per pull request. The simple rule: 3 of 150 (2%). By check: CI workflow changes 66 of 66, swallowed errors 10 of 11, changed expected outputs 11 of 13, new dependencies 9 of 20.

AI models graded every finding, not people. Two models from different vendors agreed on 266 of 276; a third, from one of those vendors, settled the other 10. One pull request holds 52 of the 122 findings, so the per-pull-request range is wider.

How long does each check take?

Each agent edit is checked in 7.9 seconds on this repository and 4.3 seconds on ripgrep when the hook can block, and in under 0.1 second in observe mode; a full CI check takes 19.5 and 6.3 seconds. Each agent edit is checked in 7.9 seconds on this repository and 4.3 seconds on ripgrep when the hook can block, and in under 0.1 second in observe mode; a full CI check takes 19.5 and 6.3 seconds.

Does it catch test gaming?

Not yet, mostly (#838).

On a benchmark of impossible tests, discipline 0.26.0 caught 11 of 138 agent edits that made a test pass by changing it (8%, likely 4.5–14%), short of the 80% bar set in advance. Simple rules that block any changed test line, or any test, CI or configuration file, caught 82% and 91%. Honest solutions wrongly blocked: discipline 11 of 644 (1.7%), the simple rules 1 and 2. On a benchmark of impossible tests, discipline 0.26.0 caught 11 of 138 agent edits that made a test pass by changing it (8%, likely 4.5–14%), short of the 80% bar set in advance. Simple rules that block any changed test line, or any test, CI or configuration file, caught 82% and 91%. Honest solutions wrongly blocked: discipline 11 of 644 (1.7%), the simple rules 1 and 2. The same 138 cases on later builds: 0.31.0 caught 12, the 0.32.0 code before its last three fixes 14, and 0.32.0 21 (15%, likely 10–23%). Those fixes were written from misses on these cases. Honest solutions wrongly blocked stay at 11 of 644. The same 138 cases on later builds: 0.31.0 caught 12, the 0.32.0 code before its last three fixes 14, and 0.32.0 21 (15%, likely 10–23%). Those fixes were written from misses on these cases. Honest solutions wrongly blocked stay at 11 of 644.

The verdict is fixed by the release chosen before the study, 0.26.0: it fails its bar. 75 of the 138 cases are tests the benchmark itself broke (they do not parse, or the changed line sits outside any test), so a diff check has nothing to see; on the other 63, discipline caught 8. The later builds catch more, but they were fixed using these same cases, so only fresh cases can show whether that holds. The simple rules catch more because they block every test edit; on real pull requests the file rule blocked 56%.

Judge it on your own repository

discipline replay --last 50 shows what discipline would have blocked in your last 50 merged changes, without blocking anything.

How each study was run, with its raw data
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@f3d6d4a0bc4f1f60f63fa101aa27e1a17d0d5276 # v0.32.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.32.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@f3d6d4a0bc4f1f60f63fa101aa27e1a17d0d5276 # v0.32.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@f3d6d4a0bc4f1f60f63fa101aa27e1a17d0d5276 # v0.32.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.32.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 47 of 47 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
companion-edit Integrity Off Any a change to one path set must also change its companion path set

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

Commands

Every subcommand of the binary. discipline <command> --help and man discipline list each one's options; CONFIGURATION.md has them as tables.

Command Description
discipline check Run the configured gates. Exit 0 = pass, 1 = violations, 2 = could not check
discipline diff Shorthand for checking uncommitted or working tree changes against HEAD
discipline baseline Record or manage grandfathered finding baselines
discipline init Write a minimal discipline.toml: gates run at their built-in defaults; commented examples show what to change
discipline gates List every gate: id, suite, availability, and effective state
discipline schema Print the JSON Schema for discipline.toml
discipline self-test Run the embedded negative / positive controls against this binary
discipline completions Generate shell completion script to stdout (bash, zsh, fish, powershell, elvish)
discipline install-hooks Install pre-commit hook in the local git repository
discipline hook Run the gates inside a coding agent's edit loop (Claude Code, Codex, Cursor, Aider, Copilot CLI, agy, Qwen Code, OpenCode)
discipline explain Explain a gate: what it checks, its state here, and the directive that lifts a finding
discipline replay Replay the last N merged changes through a configuration: what it would have blocked
discipline audit List the escape hatches the last N merged changes carried: directives, configuration loosenings, baseline growth, inline markers
discipline mcp Serve the gates to an MCP client over stdio (read-only tools: check_diff, list_gates, explain_finding)
discipline bench Benchmark tooling for the bench-regression gate
discipline doctor Check that the repository and its platform enforce discipline: workflows, CODEOWNERS, branch protection, and the local agent settings. Exit 0 = healthy, 1 = a failing check, 2 = could not check
discipline lease Claim this worktree's branches for one agent session, so other worktrees' sessions do not move them (kept in the common git directory, never committed)

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.

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@f3d6d4a0bc4f1f60f63fa101aa27e1a17d0d5276 # v0.32.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.32.0/templates/discipline.gitlab-ci.yml

Forgejo Action

Compatible with Forgejo Actions and forgejo-runner.

uses: https://github.com/orieg/discipline@f3d6d4a0bc4f1f60f63fa101aa27e1a17d0d5276 # v0.32.0

Gitea Action

Compatible with self-hosted Gitea and act_runner.

uses: https://github.com/orieg/discipline@f3d6d4a0bc4f1f60f63fa101aa27e1a17d0d5276 # v0.32.0

pre-commit hook

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

repo: https://github.com/orieg/discipline
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.