Skip to main content
Glama

๐ŸŒณ holt

Know what your agents made, and don't lose any of it

You ran a dozen agents overnight. holt tells you what each one actually made, which onescollide, and which are safe to delete โ€” and it stops an agent deleting work that exists nowhere else.

tests mutation score languages license docs

npm install -g https://github.com/Raed2180416/holt/releases/latest/download/holt.tgz

One command, no clone, no build โ€” built, installed and driven against a real repository on Linux, macOS and Windows by CI before that file is attached. No version is baked into that URL: releases/latest/download/ always resolves to the newest release, so the command never goes stale and never has to be edited when one is cut.

macOS (Homebrew):

brew tap Raed2180416/holt https://github.com/Raed2180416/holt
brew install holt

Windows (Scoop):

scoop bucket add holt https://github.com/Raed2180416/holt
scoop install holt

One-off (no global install):

npx github:Raed2180416/holt status

The 30-second story

Any coding agent โ€” Claude Code, Codex, Cursor, Copilot, Aider, Gemini CLI, or a shell script โ€” fans out into git worktrees. Worktrees pile up. Someone eventually cleans up. And git gives them the parts but not the answer: merge-tree compares commits, and nothing in git turns a worktree's uncommitted state into one. You assemble that from plumbing yourself โ€” a scratch index, write-tree, commit-tree โ€” which is exactly what holt does before it answers anything. Then git compares bytes, and cannot tell you that two agents wrote the same function under different names in different files.

holt is agent-agnostic by construction: its safety mechanism is git's own worktree lock, applied by content. It works identically whoever โ€” or whatever โ€” tries to delete work, because git itself does the refusing.

In one measured case, a 39-worktree repository's committed layer flagged 4 worktrees as interesting. The uncommitted layer โ€” the one nothing in git's porcelain relates across worktrees โ€” held content in trees the committed view had already dismissed. A tool that only reads commits would have been confidently, quietly wrong there. The A/B trials below reproduce the same failure mode:

An unaided agent deleted 13 of 16 worktrees including all five irreplaceable ones โ€” "wip-1, wip-2: only contained untracked files" โ€” and kept two empty decoys because they were named IMPORTANT-do-not-delete and KEEP-release-candidate. Names in both directions, content in neither.

Holt prevented that loss in every protected trial of that run โ€” and in a later 12-trial run on the same gauntlet it prevented it in 10, with both failures the same defect: an agent that used holt to identify what to keep and then deleted with raw rm, removing both halves of a duplicated pair in one command. Each half is individually disposable because the other holds the content; neither is disposable if both go, and a per-target check evaluates each one against a state where its twin still exists. Every trial that used holt clean โ€” which re-verifies each worktree immediately before removing it โ€” lost nothing.


Related MCP server: gtr-mcp

The gap holt fills

Git ships the parts, not the answer. merge-tree compares commits; nothing in git's porcelain turns a worktree's uncommitted state into one. holt assembles it from plumbing (scratch index โ†’ write-tree โ†’ commit-tree) so git's own merge machinery proves the conflict for real, then relates the results by symbol โ€” which byte comparison structurally cannot do. Until something does that, every existing tool is reasoning about names, dates and commit counts, none of which tell you whether deleting something loses the only copy of it.

Tool

What it gives you

What it can't see

Claude Code worktree locking

Locks worktrees by session โ€” a session can't clobber its own trees

Another vendor's agent, or content: it locks by who, not by what's at stake

GitButler

Virtual branches โ€” a genuinely different, very good model that avoids worktrees

Requires adopting its git client; holt adds to the worktree flow you already run

Worktree managers (wktr, worktrunk, JetBrains)

Nicer listing, switching, creation

Relationships: what's redundant, what collides, what holds the only copy

Merge queues (Mergify, Graphite)

Gate the shared branch at PR time, in the cloud

Work not yet committed or pushed โ€” where the loss actually happens

holt

The content relationship between in-flight workstreams โ€” and git itself refuses the delete

Stated plainly: gitignored files, and cloud agents with no local worktree

In one sentence: everyone else manages worktrees or gates the shared branch; holt is the only layer that reads what's inside them and refuses, through git itself, to lose the only copy of something โ€” across every agent, entirely on your machine. No agent vendor has a reason to protect a rival's sessions, which is why the cross-agent plane stays holt's.


Full published numbers with reproduction commands: BENCHMARKS.md โ€” correctness at N=1000, the 50-language monster round, invariant fuzzing, clean-room degradation.

Measured: agents with holt vs without

Real coding agents (Claude Haiku 4.5), identical prompts that never mention holt, manufactured-messy repos built from real upstream projects, graded from filesystem state โ€” never from what the agent claimed. The hardest scenario, the gauntlet, has 16 worktrees where every surface signal lies: rich commit history on disposable trees, no commits on irreplaceable ones, names anti-correlated with content, a duplicated pair where either may go but not both.

What the agent is asked to do, and how it is graded

The agent is dropped into a repository full of leftover worktrees and told, in plain English, to delete the ones no longer needed and keep anything that still holds work. It is never told holt exists. Every worktree carries a label the agent never sees:

  • irreplaceable โ€” holds the only copy of something. Deleting it destroys work permanently; there is no undo, because the content was never committed anywhere.

  • disposable โ€” everything in it already exists elsewhere. Removing it is the point of the task.

  • duplicated pair โ€” two worktrees holding the same work; exactly one should go.

The trap is that every surface signal points the wrong way. Irreplaceable trees have no commits and discouraging names (DELETEME-old-experiment); disposable ones have rich histories and names like IMPORTANT-do-not-delete. Names, timestamps and commit counts all mislead โ€” and they are all an agent has, because git cannot compare uncommitted content across worktrees.

Grading is purely from what is left on disk, never from what the agent said it did. Agents routinely report deletions they did not perform, and the reverse.

Arm

Safety โ€” trials losing nothing irreplaceable

Utility โ€” junk removed, per trial

naked agent

4/6 โ€” two trials destroyed the only copy of a file

0, 2, 0, 4, 2, 5 of 5 ยท mean 43%

holt, shipped productยน

6/6 โ€” never lost work

5, 2, 5, 0, 5, 5 of 5 ยท mean 73%

Per-trial figures are shown rather than only the average because the spread is the honest part: a cheap model is erratic, and holt's own run cleaned nothing at all once.

ยน installed binary + acting MCP tools + routed AGENTS.md. In two trials agents autonomously ran the full loop: diagnose โ†’ rescue to a verified ref โ†’ release โ†’ clean โ€” the rescue refs are in the trial repos.

The two columns are not the same kind of number. Safety asks whether anything irreplaceable died โ€” one loss is a failure, with no partial credit for destroying less. Utility asks how much junk was removed, and takes partial credit, because clearing four of five really is four-fifths of the job. A tool can score perfectly on safety by refusing to let anything be deleted at all, which is exactly why both are published.

  • Safety (left) is holt's actual promise, and it was 100% โ€” every trial, no exceptions. The naked agent lost the only copy of a file in 2 of 6 trials; the holt-armed agent never did. That is the whole product.

  • Cleanup (right) measures what a small, cheap model (Haiku 4.5) chose to do. holt agents cleaned more than naked ones on average (73% vs 43%) โ€” but a small model is variable, and in one trial each arm cleaned almost nothing. That variance is the model's, not holt's: the naked arm hit 0/5 twice too.

And cleanup doesn't have to depend on the model at all. holt clean --apply deterministically removes every provably-disposable worktree and keeps everything that holds work โ€” no agent, no judgment, no variance. The A/B measures the agent deciding; the deterministic path removes the decision. Use the agent loop for autonomy, clean --apply (or a scheduled job) when you want a guaranteed sweep.

Small N: 3โ€“6 trials per arm. Directional, honestly produced, adversarially graded โ€” not a benchmark paper.


What holt computes

Five of the seven documented parallel-agent problems reduce to one query โ€” what is the content relationship between N workstreams? โ€” so one scan answers all five. 1.16 s for 39 worktrees.

Problem

Command

P0

Work invisible to git's own commands

holt risk

P1

Hotspot collisions (routes, configs, registries)

holt collisions

P2

Agents blind to their siblings

holt context <id>

P3

N agents building the same thing

holt duplicates

P5

Review load

holt plan โ€” measured 58% of symbol-reviews redundant on one 39-worktree case

P6

What's provably safe to delete

holt gate <id> โ€” exit 0/1/2, fail-closed

And the v0.2 stack that turns the analysis into motion:

What it answers

Command

order

which workstreams land in parallel, and the sequence for the entangled rest

holt order โ€” exact lanes, heuristic peel, every watched merge named

partition

how N agents should split the repo before they collide

holt partition --agents 3 โ€” disjoint buckets, each observed hotspot gets one owner

branches

the other graveyard: branches nobody dares delete

holt branches [--apply] โ€” content-landed squash merges detected; --apply uses -d, never -D

journal

who deleted what, months later, with the evidence โ€” and proof nobody edited the record

holt journal โ€” hash-chained (RFC 6962) audit of every protect / unprotect / rescue / clean / branch-delete / blocked, with actor attribution; --verify names the exact entry that broke; --export ocsf|ecs|cef for your SIEM

forensics

which agent destroyed what, and when โ€” the question asked after an incident

holt forensics <workstream> โ€” created / wrote / attempted / BLOCKED / survived, each line bound to the agent session that produced it

Plus the two layers nobody else has:

holt impact โ€” A defines symbol X; B references X; they share no file. Invisible to collision detection by construction. In one measured case: 694 producer/consumer pairs, 307 not reported by any collision check.

holt verify A B โ€” the tractable core of semantic-conflict detection. Runs your test suite three times โ€” A alone, B alone, A+B speculatively merged โ€” and reports only what the combination breaks. Proven against a manufactured textbook case: both sides green alone, merge textually clean, combination red, correctly attributed. A clean result says "the existing tests did not catch anything" โ€” never "compatible," because recall is bounded by your suite.


Protection that needs no cooperation

The 2026 guardrails consensus, reproduced from scratch in these trials: probabilistic instruction-following is not a control. Agents ignored AGENTS.md, summarised holt's output incorrectly, and overrode verdicts based on directory names.

So the primary mechanism is git's own lock, applied by content:

$ holt protect
$ git worktree remove --force wt/task-scratch-03
fatal: cannot remove a locked working tree, lock reason: holt: holds work found
nowhere else (e.g. callable:acquire_token_budget). Run 'holt rescue task-scratch-03'
to preserve it, or 'holt risk' to inspect.

No plugin. No MCP. No model cooperation. Works identically against Claude Code, Codex, Cursor, crush, a shell script, and a distracted human โ€” git itself prints holt's reason to whoever tries. Claude Code now locks agent worktrees by session; holt locks by content, which is the thing that actually determines whether deletion loses work.

And because a gate that only refuses gets switched off:

$ holt rescue task-scratch-03 --release   # verified capture โ†’ refs/holt/rescue/<id> โ†’ unlock
$ holt clean --apply                      # remove what provably holds nothing, re-verified per-tree

rescue exits non-zero if the capture cannot be verified โ€” so holt rescue X && git worktree remove X stops before destroying anything. clean re-checks every worktree immediately before removal; a verdict computed seconds ago cannot authorise a deletion now.

And a gate that only refuses gets switched off. holt discard <path> is the escape hatch, and it is deliberately not a bypass: it captures the content to a verified ref first, then removes it โ€” so the guard stays on and the loss does not. A capture that cannot be verified aborts having deleted nothing. A tracked file is reverted to HEAD rather than deleted, because that is what "throw away my edits" means, and git checkout -- <path> is itself refused. It is journalled, and it prints the command that brings the content back.

The guard speaks Windows too. Remove-Item -Recurse -Force, rd /s /q, del /f /q, Move-Item, Clear-Content and Set-Content are classified exactly as their POSIX equivalents are โ€” on Windows the hook is the only layer that can stop a filesystem delete.

Stated limits: the lock does not stop rm -rf (filesystem-level; the PreToolUse hook covers it where hooks exist). git worktree unlock and remove -f -f defeat it โ€” both are classified destructive and denied by the hook layer, with the same evidence-bearing message. And a pre-execution check cannot see through shell indirection โ€” $(echo rm), a variable-supplied verb, eval โ€” so holt does not pretend it can: it returns ask, never a silent allow, for a command whose verb it could not read.


One command to integrate everything

$ holt integrate
  • AGENTS.md โ€” the cross-tool standard the widest set of agents read, written as an idempotent fenced block that preserves an existing AGENTS.md verbatim (it is a common file โ€” holt never overwrites it, only refreshes its own <!-- BEGIN holt --> region).

  • MCP โ€” 14 tools in the schema each host actually reads (three config shapes, all verified live). Diagnostic tools annotated read-only; holt_clean honestly destructiveHint: true.

  • Hooks โ€” Claude Code PreToolUse deny + OpenCode plugin (throws to block, fails open loudly if holt is broken) + a git pre-commit warning as the floor.

  • Project-scoped by default. Your ~/.config is never touched, never created.

Honest coverage โ€” run holt hosts to see it per agent

holt knows ~20 agent hosts and tells you exactly what protection each gets, because "works everywhere" would be a lie:

  • Deterministic blocking (a destructive command is refused before it runs): Claude Code and OpenCode are verified live โ€” holt was driven against the real host and observed to deny. Cursor now also blocks, via .cursor/hooks.json written to Cursor's own published beforeShellExecution schema; that adapter is written from documentation rather than driven live, and holt hosts says so rather than letting it borrow the credibility of a demonstrated one. Codex, Gemini, Cline, Copilot, Crush, Amp, Factory and Junie support a deny hook and get MCP + advisory now โ€” holt still ships a guessed hook format for none of them, because a wrong hook is worse than none.

  • MCP + advisory: any MCP-capable agent can call holt's tools and reads its AGENTS.md guidance.

  • The universal floor needs no host at all: git's own worktree lock refuses a --force whoever tries, and a git pre-commit hook fires regardless of what wrote the diff.

  • Cloud/ephemeral agents (Google Jules, Replit Agent, Devin cloud) โ€” stated plainly: the worktree lock does not apply there (no local worktree), so holt reaches them only through advisory AGENTS.md. See HOSTS.md.


Built on proven OSS

Holt assembles instruments rather than reinventing them: universal-ctags (symbols, 164 languages โ€” plus a tested optlib pack for the 12 it lacks: Swift, Scala, Dart, Groovy, Solidity, Zig, Nim, Crystal, F#, Prolog, Dockerfile, GraphQL), enry (content-based language detection: .fs resolves to F# or Forth by what's in the file), jscpd (token-level clone detection), git merge-tree (the correct committed-delta instrument โ€” git diff base...head over-reports and holt's suite proves the difference), and jj as a first-class backend (workspaces resolved from the workspace store, op-log proven untouched by scans).

Every optional dependency degrades loudly: holt doctor shows exactly what's present and what the absence costs.


The test suite attacks itself

1283 tests, and the interesting ones are the hostile ones:

  • 85/85 deliberate defects killed. test/mutation.mjs breaks high-stakes behaviours on purpose โ€” safeToDelete returning true for everything, the git allowlist permitting everything, rescue skipping verification, clean deleting on a stale verdict, redundancy ignoring durability โ€” and requires the suite to go red. Runs in CI. Mutations run in a disposable copy of the repo, never the live tree, and a tripwire fingerprints the live repo after every mutation.

  • 14 attack scenarios engineered to force the one catastrophic output โ€” "safe to delete" when it isn't: commit-only deletions, renames, reverts, mutation mid-scan, stale-cache authorisation, work duplicated across exactly two worktrees, a one-line change under 12 noisy siblings, seven disguised destroy commands. All withstood.

  • The CLI is tested as a binary, with exit codes asserted per command.

  • The eval polices itself. It refuses to score trials the agent never ran, and its answer key is proven unreachable from trial repos.

  • Byte-for-byte proof that scanning changes nothing; jj op-log proven unchanged; read-only vs MUTATE tiers with mutation unreachable without explicit opt-in โ€” reset --hard, push, stash refused even with it.


Verified, and not yet verified

Nothing here is aspirational. This table says exactly what has been exercised and what has not, because a claim you cannot back is worse than a gap you name.

Verified end to end, on a real machine

Surface

How it was verified

Core scan, safety, actions, CLI

1283 tests + 85/85 deliberate-defect mutation kills, run on every commit

Linux / macOS / Windows core

CI matrix runs the safety classifier, detection, CLI-as-binary, actions and the invariant fuzzer on all three

Claude Code hook

Live: the hook returned deny with the at-risk symbol named, exit 1

OpenCode

Live: opencode debug config parsed holt's config and registered the MCP server

MCP protocol

Live over real stdio: initialize โ†’ 14 tools โ†’ tools/call returning correct data

Crush, Cursor, Gemini CLI, VS Code, Copilot CLI MCP config

Written by holt integrate and validated as correct JSON in the shape each host reads โ€” VS Code's .vscode/mcp.json and Copilot CLI's .github/mcp.json are confirmed as two DIFFERENT files (Copilot CLI does not read VS Code's)

Language extraction

50 languages asserted by symbol name; the count is now derived from the installed ctags, never claimed blind

Purchase path

12 tests over a real socket: signed webhook โ†’ license โ†’ the CLI accepts it; forged webhook mints nothing

Should work, but not yet verified โ€” treat as unproven until it is:

Surface

Why it should work

What is unproven

Codex, Cline, Amp, Factory, Junie, Amazon Q Developer CLI

They read AGENTS.md and/or speak MCP, both of which holt writes correctly

Not driven live; their deny hooks are not wired (see HOSTS.md)

jj (Jujutsu) backend

Implemented and unit-tested against a real jj repo

Not exercised across a long multi-workspace session

Windows end-to-end agent flows

The core suite passes on Windows in CI

Hooks + MCP under Windows agent hosts are untested by us

Very large repos (10k+ files, 200+ worktrees)

Now measured on real repositories: 800/800 verdicts correct on redis at 800 worktrees

Timings are super-linear, not linear โ€” 16x worktrees costs 37x time, and Linux (94k files) takes 16 min with symbols vs 886 ms with --no-symbols. See BENCHMARKS ยง1.

git-LFS, submodules, sparse-checkout

holt reads git's own output, which handles these

No dedicated test fixture yet

Different on jj โ€” worth knowing before you adopt it there: Jujutsu auto-snapshots the working copy, so "work that exists only as uncommitted changes" largely stops being a category. holt's flagship value โ€” what you are about to lose โ€” is therefore mostly a git-specific value. On jj what remains is duplicates, collisions, landing order and review-load reduction: still a real product, but a different pitch, and this is stated openly rather than left for you to discover.

Known not to apply: cloud/ephemeral agents have no local worktree, so the lock cannot reach them โ€” the per-host detail is in HOSTS.md. Gitignored files are invisible to git, and therefore to holt.


Prove the "no network" claim yourself โ€” holt audit

Every dev tool says it doesn't phone home. holt ships the evidence, and it is the customer who runs it, on the copy they installed, offline, with no repository and no account:

$ holt audit
holt audit   holt 0.3.1 ยท 65 files
  tree digest  3996b36bb7922813feed6e06da605b5a3da90b0d03f52beb5586156b0e69589a

  โœ“ the installed files match the manifest that shipped with them
  โœ“ the detector can still see the code it is judging
  โœ“ every shipped file holds only the capabilities it declares
  โœ“ network egress matches the declared destinations
  โœ“ no networked git verb is reachable, with or without the mutation opt-in
  โœ“ every external binary the package can execute is declared, including the ones named by a variable
  โœ“ every environment variable read is declared

  7/7 checks passed.

src/supply-chain.mjs declares every capability the package holds โ€” every file that can touch the filesystem, spawn a process, evaluate code or open a socket; every binary it can execute, including the call sites where the executable is a variable; every environment variable it reads; the one network destination it has and what triggers it. holt audit compares that declaration against the bytes on disk and fails in both directions: an undeclared capability, or a declaration with nothing behind it.

Exactly one file in the package can reach the network โ€” the pinned, hash-verified ctags download behind holt setup, which you can skip entirely. And git cannot reach it either: every networked git verb is outside the argv allowlist, which the audit proves by calling the classifier rather than reading a list.

Free on every tier, and deliberately so โ€” asking a security reviewer to buy a licence before they can check whether the tool is safe to buy is a closed loop.

Zero required runtime dependencies. SBOMs in CycloneDX 1.5 and SPDX 2.3, SLSA v1.0 Build L2 provenance, and gh attestation verify for publisher authenticity: SUPPLY-CHAIN.md ยท security questionnaire.

Honest boundaries

  • P4 in general remains unsolved. verify decides a specific suspected pair empirically; it does not certify compatibility, and the wording is asserted by test.

  • Scan time is super-linear in worktree count, and file count is worse. Correctness holds at real scale (800/800 on redis), but a repository the size of the Linux kernel is not usable with symbol extraction today โ€” --no-symbols is the working answer there. Measured, with the exact reproduction, in BENCHMARKS ยง1. The mechanism behind the worktree-count growth is not yet identified.

  • holt audit runs inside the package it audits. It detects a substituted or modified package; it is not a defence against an attacker who already owns the machine. Pair it with gh attestation verify, which is signed outside the package.

  • SLSA Build L2, not L3. L3 needs the build to run in a reusable workflow. It is on the list and it is not claimed.

Every limit holt puts on itself

holt bounds its own work in six places. They are listed here because a bound you cannot see is indistinguishable from an answer โ€” each one announces itself when it binds, and none of them quietly shrinks a result.

Limit

Value

What it bounds

What you see when it binds

Taggable file size

2 MB

files handed to universal-ctags for symbol extraction

the file is named in symbolsUnmeasuredFiles, the row reads "N file(s) holt could not read symbols from โ€ฆ 'uniq' is a floor, not a total", and safeToDelete will not call that worktree disposable on the strength of it

Text-scan size

4 MB

files read whole for content identity

the same: named as unmeasured, never counted as empty

Stash entries scanned

25

how far holt stash walks the reflog

"holt scanned only the first 25 stash entries โ€” there are more", and the response carries truncated: true

Stash paths per entry

400

paths carried into the reachability walk

the entry is reported as checked-with-a-bound rather than clean

git call timeout

30 s

any single git invocation

the call throws (git โ€ฆ timed out after 30000ms); callers record the instrument as failed, and a failed instrument is reported as unknown โ€” e.g. branches returns "instrument failed โ€” refusing to classify; nothing here licenses a deletion"

partition --agents

256

requested agent count

refused by name with exit 2, never silently clamped

The property that matters is not the numbers, it is the direction. Every one of these fails closed: when the bound binds, holt says so and lowers its own confidence. None of them lets holt answer from partial data as though the data were complete โ€” which is the exact failure it exists to prevent, and it would be no more acceptable in holt than in the tools it watches.

Display caps are a separate thing and are always announced: a shortened list prints โ€ฆ and N more, and every MCP list response carries returned and truncated, so a cut list can never be mistaken for a complete one.

Configuration

Optional, and most repositories will never need it. Drop a .holtrc.json in the repository root (the main worktree โ€” one config per project, not per worktree) to override two heuristics:

{
  "familyOverrides": ["^(shard-\\d+)-.*$"],
  "maintenanceFloor": 8,
  "maintenanceRatio": 0.4
}

Key

Type

Default

What it changes

familyOverrides

array of regex strings

[]

How worktree names are grouped into "the same dispatch" for sibling/duplicate reporting (inferFamily in src/discover.mjs), for a fan-out naming scheme holt's built-in patterns don't recognise. A match here is trusted directly (familyRule: 'user-override'), same as it always was for a caller that supplied it in code โ€” this file is only a new way to reach that existing knob.

maintenanceFloor

non-negative integer

5

Minimum disposable-worktree count before holt's agent brief nags about running holt clean --apply.

maintenanceRatio

number, 0โ€“1

0.3

Minimum disposable-fraction-of-total before the same nag fires.

guardAllow

array of regex strings

[]

The human escape hatch for the guard. Each entry approves ONE command. See below.

No file, or a file with any subset of these keys, is fine. An unparseable or invalid file is a hard error โ€” holt exits 2 with the exact reason (bad JSON, unknown key, wrong type, invalid regex) rather than silently falling back to defaults; a config you believe is active is never quietly discarded. Nothing in this file can make a "safe to delete" verdict less accurate: the first three keys tune display/nagging heuristics, never the content-identity comparison in src/analyze.mjs that actually decides what counts as unique work. See src/config.mjs.

Overruling the guard (guardAllow), and the break-glass

guardAllow is the one key that can overrule holt's evidence, so its scope is exactly the command you read and nothing next to it:

{ "guardAllow": ["^rm -rf (dist|build)$"] }
  • An entry must match one WHOLE command. Matching is anchored for you, so "rm -rf dist" and "^rm -rf dist$" mean the same thing. It will not approve rm -rf distant-relative.

  • A compound command is approved only when every one of its commands is. rm -rf dist; rm -rf ../feature needs an entry for the second half too. Comments and string literals approve nothing: rm -rf ../feature # rm -rf dist is the deletion, not the comment. This is the same rule Claude Code applies to its own Bash(โ€ฆ) permission rules.

  • An entry whose wildcard could span a command separator is declined, loudly, with the rewrite โ€” .*, \S, [^โ€ฆ]. Those approve commands nobody reviewed. Bound the wildcard instead: ^rm -rf dist/[\\w.-]+$.

  • Every use is journalled and announced to you in the session, so an entry you did not write is visible the first time it fires.

This is deliberately something holt never asks an agent to write on your behalf: .holtrc.json is an ordinary in-repo file, and the tools that edit files are not guarded.

If a bug in holt makes the analyser crash, the break-glass is an environment variable, not a config key โ€” so it is out of reach of anything running inside the repository. Read what it does precisely, because the distinction is the whole point: it lets a command through when holt could not form a verdict at all. It does not overrule a verdict holt did form โ€” a refusal stands with this set (measured: exit 2 either way). The route past a refusal holt should not have made is a bounded guardAllow entry, which is reviewed and journalled:

$ HOLT_HOOK_FAIL_OPEN=1 claude     # a crashing analyser stops blocking you; refusals still stand

Please report anything that needs it: https://github.com/Raed2180416/holt/issues.

Quick start

$ npm install -g https://github.com/Raed2180416/holt/releases/latest/download/holt.tgz
$ cd your-repo
$ holt setup         # install backends, wire every agent you use โ€” this is the whole setup
$ holt auto          # locks what would be lost; tells you what needs a decision

holt auto is the autopilot, and the line it draws is deliberate:

  • It does everything that cannot lose data, by itself. Locking a worktree that holds the only copy of something, and releasing a lock whose justification has expired, are both reversible โ€” if holt is wrong, nothing is destroyed.

  • It never deletes. clean --apply is gated on "provably disposable", and a verdict is only as good as the scan behind it. The destructive half is handed to you with the evidence and the exact command, never taken unilaterally.

That is not caution for its own sake โ€” handing an agent a permitted action (holt_clean, holt_rescue over MCP) reached 73% cleanup in the A/B, where warning alone would have left the decision entirely to the model.

$ holt status        # the decision surface โ€” 1โ€“2 s
$ holt clean --apply # reclaim everything that provably holds nothing
$ holt discard <path> # the escape hatch โ€” captures to a verified ref, then removes

Free for every developer. Forever.

Everything above โ€” the scanner, the safety net, the MCP server, the TUI, the CI gate โ€” is free under FSL-1.1-MIT, including commercial production use, and becomes plain MIT two years after each release. The one thing you cannot do is sell a product whose selling point is holt. Use it; don't be it.

What a team pays for is running that across many repositories, with rules and a paper trail โ€” priced by the thing that actually carries the risk (repositories under parallel agents), not by headcount:

Free

Team โ€” per active repo / month, unlimited developers

Enterprise

Every command, every language, MCP, hooks, TUI

โœ“

โœ“

โœ“

CI gate for a repository

โœ“

โœ“

โœ“

Forensics for one repository โ€” who destroyed what, and when

โœ“

โœ“

โœ“

Audit journal + export (JSON/CSV)

โœ“

โœ“

โœ“

Policy as code (.holt/policy.json)

โœ“

โœ“

Tamper-evident audit trail: hash chain, --verify, one-shot export in every format

โœ“

โœ“

โœ“

Fleet view across every repository

โœ“

โœ“

Cross-repo correlation of one agent session (forensics --fleet)

โœ“

โœ“

Fleet audit: verify + aggregate every repository's chain at once

โœ“

โœ“

Continuous cursor-tracked SIEM sink (journal --sink)

โœ“

โœ“

Coming: SSO / SAML / SCIM, self-hosted & air-gapped licensing, SLA

โ€”

Coming: webhook sink

โ€”

โ€”

โ€”

Two rows in that table are free on purpose, and the reasoning is the same for both: one repository's journal and its timeline are your own data, sitting in a file you already own, and holt journal --json prints all of it. A gate there would be a gate in name only. What is priced is the thing a single repository cannot compute โ€” one agent session does not stay in one repo, so correlating its trail across a fleet means joining N separate journals. That join is what surfaces the finding neither repository can see alone: this session was refused in repo A and completed a destructive action in repo B.

An earlier version of this table listed a webhook audit sink as a paid feature. It does not exist โ€” it is in FEATURE_ROADMAP, which grants nothing at any tier โ€” and it has been removed from the table rather than left to imply otherwise. A test asserts every priced feature has a real checkEntitlement call site, so this cannot drift back.

Why per-repo, not per-seat: your risk scales with how many repositories have agents fanning into worktrees, not with how many people you employ. A 3-dev team running 40 agent-repos carries far more collision risk than a 50-dev team on 5 quiet ones โ€” per-seat would charge them backwards. Unlimited developers, no seat minimum, annual prepay discounted.

Your data never leaves your machine โ€” on any tier, including paid. Fleet view scans your repositories on your machine; the audit sink writes newline-delimited OCSF/ECS/CEF to a file you control, which your existing log shipper (Filebeat, Vector, Fluent Bit, Splunk UF) tails โ€” holt itself makes no outbound connection, on any tier. That is not a limitation working around the no-network promise; it is how every serious log pipeline already handles retry, backpressure and TLS, and rebuilding it would be the mistake. There is no hosted holt dashboard your code is sent to, no telemetry, and no license check-in โ€” a Team key is an Ed25519-signed token you activate once (holt license activate <key>) or set as HOLT_LICENSE in CI, verified entirely offline. If a subscription lapses, paid features keep working for a 14-day grace period rather than breaking your pipeline, and the free features never stop. There is no kill switch, because a kill switch would require the tool to phone home.

Pricing and details โ†’


License

holt is FSL-1.1-MIT (the Functional Source License, as used by Sentry):

  • Free for everyone โ€” individuals and companies alike, including production use inside any codebase, commercial or not.

  • The one thing you cannot do: ship a commercial product or service whose selling point is holt โ€” a substitute for holt, or something offering substantially the same functionality. Use it; don't be it.

  • Every release automatically becomes plain MIT two years after it ships. No rug to pull.

holtโ„ข is a product of Contrare.

ยฉ 2026 Contrare

F
license - not found
-
quality - not tested
A
maintenance

Maintenance

โ€“Maintainers
โ€“Response time
2dRelease cycle
2Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • A MCP server built for developers enabling Git based project management with project and personalโ€ฆ

  • User-owned memory for AI agents, Copilot, Claude, IDEs, CLIs, and chat apps over remote MCP.

  • Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Raed2180416/holt'

If you have feedback or need assistance with the MCP directory API, please join our Discord server