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:
- Did the agent stay inside the paths it was allowed to change?
- Did it touch a sensitive surface such as CI, infrastructure, migrations, secrets, or lockfiles?
- Did the 15 deterministic registry analyzers shared with the hosted product, plus the local security pass, find a regression in the diff?
- 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
| Command | Purpose |
|---|---|
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 list | List 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 login | Open a short-lived browser confirmation and select the organization used by explicit sync. |
codetruss auth status | Verify the saved credential against the CodeTruss session endpoint without displaying its bearer token or sending repository data. |
codetruss auth logout | Revoke 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
| Action | Leaves the machine? | Destination |
|---|---|---|
| Installers and direct package install | Yes, during install | CodeTruss release metadata and package artifact |
| Git inventory, diff classification, sensitive-path checks | No | Local process only |
| CodeTruss 15 registry analyzers and the local security pass (hosted scores are not computed locally) | No | Local process only |
grammars install | Yes, only when invoked | Downloads the pinned grammar pack; the only command that fetches anything at analysis time |
| Verification commands | Only if the command itself uses the network | Whatever that project command contacts |
--llm | Yes | Anthropic or OpenAI directly, or Anthropic through your local Claude Code login |
report, list, metrics, verify | No | Local receipt directory only |
auth login | Yes, only when invoked | CodeTruss device/session endpoints; no source, patch, or receipt upload |
auth status, auth logout | Yes, only when invoked | Verify or revoke the saved credential at the CodeTruss session endpoint; no source, patch, or receipt |
sync | Yes, only when invoked | The 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:
| Claim | What it means | What establishes it |
|---|---|---|
| Integrity | These 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. |
| Provenance | A 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:
| Exit | Meaning |
|---|---|
0 | Integrity and provenance established against a key you supplied. |
1 | The bytes are intact, but nothing establishes who signed them: no key was supplied, or the signer is not among the keys you supplied. |
2 | The bytes are not what was signed. Provenance is not evaluated at all. |
3 | Usage 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.
| Verdict | Meaning | Typical reasons |
|---|---|---|
PASS | The 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_REQUIRED | The 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. |
FAILED | The 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:
UserPromptSubmitcaptures the exact Git-visible state before the turn.PostToolUsegives a fast scope and sensitive-surface warning after nativeEditorWritecalls.Stopcaptures 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.