Skip to content

Boundary CLI guide

The complete reference for the local first-pass gate: install, run, configure, read receipts, and automate. This page renders the same guide that lives in the repository, so it moves when the CLI moves.

API reference →

CodeTruss is the first-pass gate for AI-written code. Its local Boundary puts an agent run inside an inspectable quality boundary. It records what you asked for, captures the starting Git state, runs any coding agent or shell command, and then answers four questions before a pull request exists:

  1. Did the agent stay inside the paths it was allowed to change?
  2. Did it touch a sensitive surface such as CI, infrastructure, migrations, secrets, or lockfiles?
  3. Did the 15 deterministic registry analyzers shared with the hosted product, plus the local security pass, find a regression in the diff?
  4. Did the repository's own verification commands pass?

Each run produces a Markdown receipt for humans and a JSON receipt for tools, with a deterministic PASS, REVIEW_REQUIRED, or FAILED verdict and the reasons that caused it. Static analysis stays on your machine. Optional LLM review uses your provider and credentials. Nothing is uploaded to CodeTruss unless you explicitly run codetruss sync.

The product layers remain distinct: Boundary is the local agent-time CLI, History begins only when a user explicitly syncs a privacy-minimized receipt, and Health is the hosted full-codebase audit.

The CLI runs a local security pass of its own: the shared SAST engine over the JavaScript, TypeScript and TSX in the repository, plus Python when the optional grammar pack is installed. It is a subset of the rule pack — the hosted symbol graph and the remaining security rules run only in a hosted scan, and each receipt names the classes it did not check rather than staying silent about them. Local receipts therefore record the local-registry-v5 analysis profile and show hosted Health scores as N/A; they do not manufacture scores from the incomplete local pass set.

Quickstart

Install the CLI on macOS or Linux (Node.js 20.9 or newer is required):

curl -fsSL https://codetruss.com/install.sh | sh

Windows PowerShell users can run:

irm https://codetruss.com/install.ps1 | iex

The installers use HTTPS release metadata to locate a versioned tarball served by CodeTruss, then compare the downloaded archive with the metadata's SHA-256. This detects a mismatch between those two downloads; it is not independent package provenance. The tarball contains one bundled executable with no runtime npm dependencies. You can invoke that cross-platform path directly, without an npm registry account:

npm install --global https://codetruss.com/downloads/codetruss-cli-latest.tgz

Release metadata and the SHA-256 digest are published at https://codetruss.com/downloads/codetruss-cli-latest.json; the raw checksum is available beside the tarball as .tgz.sha256, and the same metadata links the CycloneDX SBOM included in the package. To install the current artifact in one repository rather than globally:

pnpm add --save-dev https://codetruss.com/downloads/codetruss-cli-latest.tgz

For an immutable pin, read the current version from the release metadata and replace latest with that exact version.

@codetruss/cli is also published to the npm registry. The npm release can trail the hosted tarball, so check npm view @codetruss/cli version against codetruss-cli-latest.json before assuming the two agree, and prefer the hosted tarball when you need the newest build.

The examples below assume the global install and use codetruss directly. For a repository-pinned install, prefix the same commands with pnpm exec.

Run guided setup once inside the Git repository:

codetruss setup

Setup proposes conventional source roots without silently allowing the entire repository, displays detected verification commands and their exact path-bound fingerprint before trust, installs the selected pre-commit and agent hooks, and runs hook diagnostics. It is local-only. Codex requires one remaining action: open /hooks and approve the exact project hook. After that, keep using your agent or normal commit flow; no per-change CodeTruss command is required.

CodeTruss is also enrolling a 14-day local-only design-partner cohort. No repository access, CodeTruss account, or receipt sync is required. The consent request is:

I am testing whether CodeTruss catches meaningful AI-agent scope or quality problems before a PR. The 14-day design-partner test is local-first. You can participate without giving us repository access or syncing a receipt. May I record your product-use outcomes and contact you up to twice about this test? Receipt sharing, quotes, and case-study publication are separate opt-ins.

Email your opt-in to zack@codetruss.com. Enrollment begins only after a dated affirmative email response. An install, link click, or synced receipt is not consent.

To review a real working-tree change immediately without configuring anything:

codetruss review --task "Review my current agent changes"
codetruss verify latest

That manual path needs no account, .codetruss.yml, or sync. With no allow policy, changed files are deliberately classified as unexpected. The result is a valid REVIEW_REQUIRED receipt and exit code 1—not a broken run. An unchanged repository can produce PASS, so evaluate first value with a real change.

Unattended setup remains explicit:

codetruss setup --yes \
  --allow "src/**" --allow "tests/**" \
  --deny "infra/production/**" \
  --trust-verify

--yes never implies verification-command trust, but it does supply an allow scope. With no --allow it adopts the conventional source directories that exist at the repository root (src, app, apps, packages, lib, components, server, client, public, test, tests, e2e, spec, docs) as <dir>/** and prints them, refusing only when it finds none. Pass --allow explicitly, as above, whenever the scope matters. Add --trust-verify only after inspecting the detected commands and fingerprint. Use --hooks none to prepare policy without installing automatic checks.

Wrap any agent command:

codetruss run \
  --task "Add password-reset rate limiting" \
  -- claude -p "Implement password-reset rate limiting"

After hook setup, keep using Claude Code or Codex normally. Add task-specific --allow, --deny, or --verify only when a wrapped run intentionally differs from the committed repository policy.

The command after -- is not special to CodeTruss. It can be claude, codex exec, another agent CLI, or an ordinary shell command. CodeTruss does not stage, commit, reset, or clean the agent's work.

Review changes that already exist instead:

# Working tree: tracked and untracked changes
codetruss review \
  --task "Review the current agent changes" \
  --allow "src/**" \
  --verify "pnpm test"

# Only the index that the next commit would contain
codetruss review --staged --task "Pre-commit review"

Inspect and validate the resulting evidence:

codetruss report latest
codetruss report latest --json
codetruss list
codetruss metrics --json
codetruss verify latest

# Optional: connect one receipt-only hosted organization.
codetruss auth login
codetruss sync latest

When developing CodeTruss itself from this monorepo, build and run the workspace package directly:

pnpm --filter @codetruss/cli build
pnpm --filter @codetruss/cli exec codetruss --help

What a run records

codetruss run records the starting commit and working-tree state before it launches the agent. When the command exits, it inventories committed, staged, unstaged, renamed, deleted, and untracked changes attributable to the session. For renames, both the old and new paths are evaluated so a protected file cannot be moved into an allowed directory to evade policy.

Every changed path is classified as:

  • allowed: it matches at least one allow glob and no deny glob;
  • denied: it matches a deny glob, even if it also matches an allow glob;
  • unexpected: it matches neither list.

An empty allow list approves nothing. That fail-closed default makes a missing policy visible instead of silently treating the whole repository as in scope. Pre-existing dirty changes are reported as an attribution limitation; run from a clean tree when the receipt needs to prove exactly what one agent changed.

CodeTruss also labels sensitive paths independently of scope. The built-in categories cover CI and policy files, infrastructure-as-code and deployment configuration, database migrations, secret material, dependency manifests, and lockfiles. An allowed sensitive change is still called out for review.

After scope classification, CodeTruss runs all 15 analyzers in its shared, database-free registry against the local diff, then the local security pass, and executes each configured verification command. Local security findings are reported for review and do not fail the verdict on their own. Analyzer findings, command exit codes, bounded command output, and coverage limitations become receipt facts; the verdict is calculated from those facts rather than generated by a model.

Commands

Table: Command, Purpose
CommandPurpose
codetruss setup [--allow <glob>] [--deny <glob>] [--hooks <target>]Guide policy, exact verification-command trust, automatic hook installation, and diagnostics without uploading anything.
codetruss run --task "..." [flags] -- <agent-cmd>Wrap an agent command, attribute its changes, analyze and verify them, then write a receipt.
codetruss review [--staged] [flags]Analyze an existing working-tree or staged diff without launching an agent.
codetruss report [id|latest] [--json]Print the human-readable or machine-readable form of a receipt.
codetruss listList local receipts, newest first.
codetruss metrics [--json]Verify local receipts and print privacy-safe aggregate activity, invocation, D7 receipt-pattern, and hook-health signals without network access.
codetruss init [--allow <glob>] [--deny <glob>]Create a documented .codetruss.yml; repeat the flags to set the repository policy before installing hooks.
codetruss verify [id|latest]Re-check a receipt's integrity and referenced evidence against the signers this repository trusts.
codetruss verify-receipt <receipt.json|dir> [--public-key <file>]Check a receipt produced elsewhere: integrity from the receipt itself, and provenance only against a key supplied out of band. Needs no repository.
codetruss sync [id|latest]Explicitly upload one selected receipt to the configured CodeTruss organization.
codetruss auth loginOpen a short-lived browser confirmation and select the organization used by explicit sync.
codetruss auth statusVerify the saved credential against the CodeTruss session endpoint without displaying its bearer token or sending repository data.
codetruss auth logoutRevoke the saved credential at the CodeTruss session endpoint, then delete the local copy.
codetruss hooks install [pre-commit|claude|codex|all]Idempotently install automatic staged or agent-change review hooks.
codetruss hooks doctor [pre-commit|claude|codex|all]Validate hook files, runner integrity, policy, executable resolution, and manual trust checks.
codetruss verify-policy [trust]Show the detected verification commands and their exact path-bound fingerprint, and record trust for them. Commands stay untrusted — and therefore unrun — until this succeeds.
codetruss grammars <list|status|install|uninstall> [pack]Manage the optional grammar packs that extend the local security pass beyond the JavaScript family. install is the only command that downloads anything at analysis time.

Every newly issued receipt records typed invocation provenance: manual_run, manual_review, pre_commit, or agent_hook; agent-hook receipts also record claude or codex and the issuing CLI version. Manual invocation is labeled direct; the generated pre-commit environment marker is explicitly self_attested because a user can reproduce it outside Git; and agent Stop receipts use hook_context after authenticating the private prompt-time state. The field is optional when reading receipt-v1 files so existing signed receipts and explicit sync remain valid.

codetruss metrics --json verifies every local receipt before counting it. Its D7 receipt-pattern signal requires at least two verified receipts across at least two UTC day buckets, including one during the explicit 144-to-192-hour window after the first verified receipt. It reports no_receipts, not_eligible, pending, observed, or not_observed and exposes the total, active-day, in-window, and agent-hook receipt counts behind that state. Self-attested pre-commit counts are never presented as authenticated hook evidence. The output includes first/last UTC dates, but no receipt identifiers, repository or task names, paths, findings, commands, diff facts, or signing material. It is neither telemetry nor an upload; users must copy the aggregate themselves if they choose to share it. Cryptographic verification establishes receipt integrity, not whether a session was external, genuine product use, a fixture, or internal dogfood; cohort adjudication remains separate.

The most useful repeatable run and review flags are --allow <glob>, --deny <glob>, and --verify <command>. --llm adds the optional local-key slop review; pair it with --provider anthropic|openai|claude to choose the credential path explicitly. --no-verify skips configured project commands for lightweight manual checks; scope, sensitive-surface, and analyzer checks still run. Command-line values are useful for one task; .codetruss.yml stores the repository defaults.

Configuration

Run codetruss setup once at the Git root. It writes .codetruss.yml; commit that policy so agents and teammates use the same scope and verification rules. Use codetruss init --allow "src/**" --allow "tests/**" only when you want the lower-level manual path. The --allow and --deny flags are repeatable. Omitting --allow is safe for a first manual review: changed paths remain unexpected, and CodeTruss warns that agent hooks cannot be installed until the policy contains at least one allow glob. A minimal configuration looks like this:

# .codetruss.yml
allow:
  - "src/**"
  - "tests/**"

# Deny wins over allow.
deny:
  - ".env*"
  - "infra/production/**"

# Keep files OUT of analysis — the escape hatch for something CodeTruss cannot
# read locally, such as a file the bundled grammar rejects. An excluded path is
# still inventoried as a changed file and still classified against scope; it is
# simply never handed to an analyzer, and the receipt names the globs and the
# paths they matched so the exclusion is on the record.
exclude:
  - "vendor/generated/**"

verify:
  - "pnpm lint"
  - "pnpm test"

receipts:
  dir: ".codetruss/receipts"

# Optional provider defaults. A model is valid only with its provider.
llm:
  provider: openai
  model: gpt-5.6-terra
  maxDiffBytes: 200000

# Written by setup/init. Commit this public key to detect a change of local signing key.
signing:
  publicKey: |-
    -----BEGIN PUBLIC KEY-----
    ...
    -----END PUBLIC KEY-----

When present, CLI --allow, --deny, and --verify values replace their corresponding config lists for that run (repeat a flag for multiple values). Quote globs so the shell does not expand them before the CLI receives them. .codetruss.yml is the reviewable policy and may be committed. .codetruss/ contains local receipts, patches, snapshots, signatures, signing material, and generated runners. CodeTruss protects that directory through the repository-local Git exclude, verifies those paths remain ignored, and refuses to continue if evidence is tracked or routed through unsafe paths. A normal git add . therefore does not stage the private evidence.

Use the smallest allow list that describes the task. A broad --allow "**" removes the most valuable scope-drift signal, although sensitive-surface and analyzer checks still run.

Optional local-provider LLM review

Deterministic scope, sensitive-surface, analyzer, and verification checks never need an LLM. Add --llm when you also want a focused review for AI slop: unnecessary abstractions, duplicated logic, placeholder code, verbose comments, speculative compatibility layers, and changes that are technically in-path but do not serve the stated task.

ANTHROPIC_API_KEY=... codetruss run --llm \
  --provider anthropic \
  --task "Simplify the billing retry path" \
  --allow "src/billing/**" \
  -- claude -p "Simplify the billing retry path"

OPENAI_API_KEY=... codetruss review --llm \
  --provider openai \
  --task "Review the staged implementation" \
  --staged

Use --provider anthropic with ANTHROPIC_API_KEY, --provider openai with OPENAI_API_KEY, or --provider claude with an authenticated local Claude Code installation. If you omit the flag, CodeTruss uses the configured provider or the first usable provider in that same order. A configured llm.model requires llm.provider; a conflicting command-line provider is rejected rather than silently sending the request to a different model family. Codex remains a supported wrapped agent and hook target, but it is not an LLM review provider in this release because its CLI does not expose the tool-free filesystem boundary required for this privacy promise.

Before any provider call, CodeTruss bounds the task to 32 KB and the reviewed diff to llm.maxDiffBytes (200 KB by default, 2 MB maximum). The receipt records both reviewed and total diff bytes. If the review sees only a prefix, the deterministic verdict is at least REVIEW_REQUIRED, even when the provider says the reviewed prefix is clean. Provider responses are also bounded, must match a strict schema, and must complete within 120 seconds.

For direct APIs, CodeTruss constructs a request containing the bounded task, reviewed diff, fixed review instructions, and response schema. OpenAI requests set store: false; provider-side abuse monitoring or retention is still governed by your provider agreement. For local Claude Code, CodeTruss disables tools, customizations, session persistence, and prompt history, runs from a temporary empty directory, and passes a minimal environment allowlist. It deliberately withholds ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN; use --provider anthropic for API-key billing and --provider claude for the authenticated Claude Code login. The PATH-resolved Claude binary must support the required --safe-mode, tool-disable, settings-isolation, and structured-output flags; CodeTruss refuses older binaries with upgrade guidance rather than weakening the boundary. The Claude client can still add its own runtime instructions or metadata under Anthropic's terms. No provider path falls back to a CodeTruss-owned key or sends the request through CodeTruss.

LLM output is advisory evidence. The deterministic facts and explicit verdict reasons remain visible so a reviewer can distinguish a model opinion from a failed test or an out-of-scope file.

Privacy model

Table: Action, Leaves the machine?, Destination
ActionLeaves the machine?Destination
Installers and direct package installYes, during installCodeTruss release metadata and package artifact
Git inventory, diff classification, sensitive-path checksNoLocal process only
CodeTruss 15 registry analyzers and the local security pass (hosted scores are not computed locally)NoLocal process only
grammars installYes, only when invokedDownloads the pinned grammar pack; the only command that fetches anything at analysis time
Verification commandsOnly if the command itself uses the networkWhatever that project command contacts
--llmYesAnthropic or OpenAI directly, or Anthropic through your local Claude Code login
report, list, metrics, verifyNoLocal receipt directory only
auth loginYes, only when invokedCodeTruss device/session endpoints; no source, patch, or receipt upload
auth status, auth logoutYes, only when invokedVerify or revoke the saved credential at the CodeTruss session endpoint; no source, patch, or receipt
syncYes, only when invokedThe only command that uploads a receipt to the CodeTruss organization selected during login

Deterministic run, review, report, list, metrics, init, verify, verify-receipt, verify-policy, and hook checks do not contact CodeTruss. There is no background usage telemetry, implicit receipt upload, background synchronization, or CodeTruss-server fallback. sync is a separate, deliberate command so that local review and hosted collaboration have a visible boundary. Website install-command copy and design-partner-link analytics are non-PII distribution and interest proxies; neither proves installation, activation, consent, or enrollment. The CLI first verifies the local receipt against the public key pinned by init, redacts the absolute repository path, agent arguments/start errors, verification commands/output, and local evidence filenames, then signs the minimized copy. The API verifies that signature, pins the signer to that API credential on its first sync, and keeps each session append-only:

# Inspect first, upload second.
codetruss auth login
codetruss report 20260712T184500Z-a1b2c3
codetruss sync 20260712T184500Z-a1b2c3

auth login follows a short-lived device-authorization flow. The browser shows the same code as the terminal, requires an explicit organization choice, and asks the developer to confirm that the code is physically visible in their own terminal. A Member, Admin, or Owner role is required for the selected organization. The resulting 90-day credential has exactly receipts:read and receipts:write; neither scope grants repository access or permission to start hosted scans, and ordinary plans do not gain the Enterprise scan API. The plaintext is delivered once, stored only in private user config, and never written into .codetruss.yml or another repository file.

Use codetruss auth status to validate the saved credential against the CodeTruss session endpoint. codetruss auth logout revokes the server-side credential and then deletes the local copy; if revocation fails, the local copy is retained for retry. Removing the granting developer from the organization also invalidates the credential. For headless Enterprise CI, CODETRUSS_API_KEY remains an explicit override; give it only the required receipt scopes and keep it in the CI secret store.

Each receipt-sync credential pins the first local Ed25519 signer it sees. Use one login per developer machine or CI signer; log out and authenticate again when that signing identity rotates.

The hosted product can add organization history, collaboration, and richer reporting after a receipt is synced. It is not in the execution path for local analysis.

The Ed25519 signature proves only that the signed receipt bytes and referenced evidence hashes have not changed since that key signed them. The first sync associates the public key with an API credential for later key continuity. It does not prove trusted execution, external signer identity, or that the source machine recorded truthful analysis.

Verifying a receipt you did not produce

codetruss verify [id|latest] checks a receipt against the signing keys this repository trusts, which is what you want for your own history and no use at all to the client, auditor, or acquirer you hand a receipt to: they have no such key, and verify refuses their copy with a signer mismatch.

codetruss verify-receipt is for that reader. It takes the receipt file (or the directory it arrived in), needs no repository, no account, and no configuration, and reports two separate claims that it never merges:

Table: Claim, What it means, What establishes it
ClaimWhat it meansWhat establishes it
IntegrityThese receipt bytes have not changed since they were signed.The receipt alone: the Ed25519 signature over its JSON, verified with the public key the receipt carries, plus the recorded digests of the Markdown rendering and the patch.
ProvenanceA party you trust signed them.A public key you obtained from that party out of band, passed as --public-key. Repeat the flag for several accepted signers.
codetruss verify-receipt ./evidence/20260807T194119099Z-233d7e.json
codetruss verify-receipt ./evidence --public-key ./their-signing-key.pem

A receipt vouching for its own key proves nothing about who wrote it — anyone can generate a keypair and sign a receipt with it — so a run without --public-key can only ever establish integrity, and says so in those words. The exit codes keep that distinction machine-readable:

Table: Exit, Meaning
ExitMeaning
0Integrity and provenance established against a key you supplied.
1The bytes are intact, but nothing establishes who signed them: no key was supplied, or the signer is not among the keys you supplied.
2The bytes are not what was signed. Provenance is not evaluated at all.
3Usage or environment error; no verification was performed.

The Markdown rendering is checked by reproducing it from the signed JSON, and every superseded profile wording stays reproducible, so a receipt signed by an older CLI still verifies byte-for-byte. Evidence a publisher withheld — most often the patch, which is the only part of a receipt that quotes source — is reported as not checked, alongside the digest the signature does cover, rather than passed over.

Neither claim says the analysis actually ran or that its conclusions are correct. Reproducing the run is the only thing that speaks to that.

Verdicts

Verdicts are ordered by severity; the highest applicable result wins.

Table: Verdict, Meaning, Typical reasons
VerdictMeaningTypical reasons
PASSThe command completed, every changed file was allowed, deterministic analysis found no blocking regression, and every configured verification passed.Only expected files changed; checks passed.
REVIEW_REQUIREDThe work may be valid but needs a person to accept risk or scope.Denied, unexpected, or sensitive files; pre-existing dirty state; medium-or-higher analyzer findings; advisory LLM slop finding.
FAILEDThe agent command or a required executable/security quality gate failed.Agent command failed; required verification failed; changed code contains a high/critical security or dependency finding; requested LLM review could not run.

run and review return 0 for PASS, 1 for REVIEW_REQUIRED, and 2 for FAILED, so a receipt verdict can be used directly in a hook or CI gate. Invalid usage/configuration and environment/runtime errors use separate nonzero codes because no trustworthy verdict was produced.

The receipt always includes explicit reasons. Do not treat REVIEW_REQUIRED as an opaque failure: read the reasons, decide whether the change is intentional, and either repair it or document the exception. Hooks and CI can choose whether to block both non-pass verdicts or only FAILED.

Example receipt

The Markdown and JSON files are two renderings of the same receipt model under .codetruss/receipts/:

# CodeTruss receipt — REVIEW_REQUIRED

**Session:** `20260712T184500Z-a1b2c3`
**Task:** Add password-reset rate limiting
**Start commit:** `7d3a1f9`
**Agent:** `claude -p ...` (exit 0)

## Verdict reasons

- `src/auth/rate-limit.ts` and `tests/auth/rate-limit.test.ts` were allowed.
- `.github/workflows/ci.yml` touched the sensitive `ci` surface.
- 15 registry analyzers and the local security pass completed; 1 medium finding requires review.
- `pnpm test --filter auth` passed (exit 0, 8.4s).

## Changed files

| Path | Change | Scope | Sensitive | Diff |
|---|---|---|---|---:|
| `src/auth/rate-limit.ts` | added | allowed | — | +84/−0 |
| `tests/auth/rate-limit.test.ts` | added | allowed | — | +61/−0 |
| `.github/workflows/ci.yml` | modified | unexpected | ci | +2/−1 |

## Analyzer findings

| Severity | Analyzer | Location | Finding |
|---|---|---|---|
| medium | complexity | `src/auth/rate-limit.ts:43` | Retry branch is more complex than the configured threshold. |

## Analysis profile

Profile: `local-registry-v5`.

The 15 deterministic registry analyzers ran locally on this machine, plus a
local security pass: the shared SAST engine — the same rules and the same
source-to-sink taint tracking as the hosted audit — over the JavaScript,
TypeScript and TSX in this repository.

### What the local security pass checked

- **SQL injection (CWE-89).**
- **Mass assignment (CWE-915).**
- **Un-awaited database writes, swallowed errors, coercion-prone `==`
  comparisons, and N+1 queries in loops.**

### What did not run

- **The rest of the security rule pack.** Command injection, code injection,
  path traversal, SSRF, open redirect, XSS and insecure deserialization were
  **not** checked. Absence of a finding in those classes means they were not
  analyzed, not that the code is clean.
- **Python.** The optional grammar pack is not installed.
- **Hosted symbol graph.** No cross-file call or data-flow graph was built.
- **Abstraction-shape analysis.** Requires the cross-file symbol graph.
- **Optional LLM review.** No model read this diff.
- **Hosted Health scores.** Not calculated, reported as **N/A**.

## Verification

| Command | Exit | Duration |
|---|---:|---:|
| `pnpm test --filter auth` | 0 | 8.4s |

**Verdict: `REVIEW_REQUIRED`**

The JSON twin carries the full file inventory, analyzer findings, explicit analysis profile and not-computed score status, verification output, coverage notes, hashes, provider disclosure when --llm was used, and structured verdict reasons. Use JSON for agent repair loops and CI; use Markdown for human review.

Suggested fixes

When a finding's own evidence determines a single correct change, the receipt adds a Suggested fixes section between the findings table and the analysis profile: a fix object on the JSON finding, and a fenced diff or snippet in the Markdown, each with its own safety note. CodeTruss never applies, writes, or runs them — a change derived from one matched line cannot see the rest of the codebase, so a suggestion is something to review, never something that happened. Where the right fix is ambiguous, the finding keeps its prose suggestion and carries no fix at all. Under an agent hook the highest-severity suggestion is also appended to the Stop summary, so the agent can correct the change before a person opens the receipt. Suggested fixes stay local: they are stripped from the hosted sync copy.

Automation

The strongest boundary is still the wrapper: codetruss run observes the starting state before an agent can edit anything. Hooks are a convenient second line of defense for agent sessions that were not wrapped.

Git pre-commit

Review exactly what is staged for the next commit:

codetruss hooks install pre-commit

The installer appends an idempotent CodeTruss block only to a new or recognized POSIX-shell hook. It refuses to modify Python, Node, or other hook formats; add the review command through that hook manager instead. Its equivalent shell block resolves the repository root, so it also works when Git was invoked from a subdirectory:

#!/bin/sh
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
if [ -x "$ROOT/node_modules/.bin/codetruss" ]; then
  "$ROOT/node_modules/.bin/codetruss" review --staged --task "pre-commit"
else
  codetruss review --staged --task "pre-commit"
fi

Save that as .git/hooks/pre-commit and make it executable:

chmod +x .git/hooks/pre-commit

If the repository already manages hooks with Lefthook, Husky, or another hook runner, add the codetruss review --staged command there instead of replacing the existing hook. Keep --llm out of the default pre-commit path unless the team explicitly wants networked provider review on every commit.

Claude Code

Install the project hook with codetruss hooks install claude.

Claude Code loads project hooks from .claude/settings.json. The installer safely merges valid JSON, refuses to overwrite malformed settings, and writes a platform-neutral Node runner under .codetruss/hooks/agent.cjs. It installs three coordinated events:

  1. UserPromptSubmit captures the exact Git-visible state before the turn.
  2. PostToolUse gives a fast scope and sensitive-surface warning after native Edit or Write calls.
  3. Stop captures the exact final state, runs the analyzers and trusted verification commands once, and writes one receipt for the whole turn.

A PASS returns no warning and lets Claude stop. REVIEW_REQUIRED warns the developer without forcing another model turn. FAILED returns Claude's structured decision: "block" feedback once so the agent can repair the change; when stop_hook_active is already true, CodeTruss reports the result without requesting another continuation. This avoids an unbounded Stop loop.

The generated Claude handlers use its cross-platform exec form:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node",
            "args": ["${CLAUDE_PROJECT_DIR}/.codetruss/hooks/agent.cjs", "claude"],
            "timeout": 60,
            "statusMessage": "Capturing CodeTruss turn baseline"
          }
        ]
      }
    ]
  }
}

The fast matcher intentionally covers native edits; the turn-level final snapshot also catches files changed through Bash or another tool. Agent-hook installation refuses an empty allow policy, because an automatic boundary needs an explicit approved surface. See the official Claude Code hooks guide for the host's trust and event model.

Codex

Install the trusted-project hook with codetruss hooks install codex.

Codex reads project hooks from .codex/hooks.json (or inline hook tables in .codex/config.toml) after the project hook is reviewed and trusted. This hook uses the same baseline / fast feedback / final receipt lifecycle and maps the result back into the session so Codex can repair it. The generated command has separate POSIX and native PowerShell forms:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node \"$(git -c core.longpaths=true rev-parse --show-toplevel)/.codetruss/hooks/agent.cjs\" codex",
            "commandWindows": "$root = git -c core.longpaths=true rev-parse --show-toplevel; if ($LASTEXITCODE -eq 0) { node (Join-Path $root '.codetruss/hooks/agent.cjs') codex }",
            "timeout": 60,
            "statusMessage": "Capturing CodeTruss turn baseline"
          }
        ]
      }
    ]
  }
}

Open /hooks in Codex to review and trust the repository hook once. Codex records trust for the exact hook-definition hash, so reinstalling or changing the definition can require another review. codetruss hooks doctor codex cannot read that user-controlled trust state and therefore always prints this manual check as a warning.

The installed runner lets PASS stop quietly, surfaces REVIEW_REQUIRED as a developer warning, and returns structured decision: "block" feedback once for FAILED. It includes a native PowerShell command override. The final snapshot is the coverage boundary; the fast per-tool callback is model-visible feedback, not the source of the signed evidence. Use codetruss run -- ... when a separate wrapper process is the better fit. See the official Codex hooks reference for current events, matcher behavior, and hook output rules.

Agent repair loop

Receipts are designed to be useful to the agent that created the change, not just to a later reviewer:

codetruss report latest --json > /tmp/codetruss-receipt.json
# Give the structured reasons to the agent, repair, then review the new diff.
codetruss review --task "Repair CodeTruss findings"
codetruss verify latest

The CLI prints the receipt ID and path after every run, so scripts do not need to scrape prose. scripts/demo-codetruss-cli.sh exercises the three verdicts in isolated temporary Git repositories when CODETRUSS_BIN points to a built CLI executable.