Repository navigation
v3.37.0
Guard 3.37.0 is a stable release cut from 3efd6a6.
36 commits • 35 merged pull requests • 8 contributors since Guard 3.36.1.
Features
- gauntlet: Run the catalog through Claude Code, Codex and Cursor (#3818)
- guard: Add agi-memory command safety extension (#2921)
- extension: Add Formicx agent command safety extension (#2914)
- guard: Add rungs command classification extension (#2818)
- guard: Review Dispat release starts with an opt-in extension (#2813)
- extensions: Add pyrig command protection (#3674)
- guard: List detected CLIs and add a Cloudflare Wrangler profile (#3795)
- extensions: Add publisher listing for mcp.mail-server (#3805)
- extensions: Require approval for mcp-mail-server permanent deletion (#3278)
- business: Classify business operations and add Drive export (#3798)
BusinessOperationV1::action_class()maps every operation to one ofread,draft,send,share,export,update,deleteoradmin. The class comes from the operation alone. A producer cannot supply it, and…drive_exportis a Google Drive operation. Its audience must beprivateorunknown. A public or named export isInconsistent, because handing a file to someone else isdrive_share.- The policy schema (both copies) accepts
drive_export, and a selector may now list up to 12 operations. The review summary, the review queue and the dashboard label it "Export Drive files".
- guard: Detect package-runner CLIs such as npx wrangler (#3792)
Fixes
- runtime: Name the business context floor for shell-wrapped Workspace CLIs (#3826)
- guard: Repair extension-control catalog bound and error type (#3817)
ExtensionControlApiErrorwas a@dataclass(frozen=True, slots=True)exception.contextlibassigns__traceback__on raise, sosuper()inside the slots class raisedTypeError: super(type, obj)and froze.…- Parallelized the coverage critical path: shards run
xdist -n 3 --dist=loadfile --max-worker-restart 0; Rust nextest--test-threads 4.pytest_duration_reportwrites only from the controller so workers cannot… - Serialized the collection-time
git diff/fetchinextension_freshnessacross xdist workers with anfcntllock (concurrent module imports raced.git).
- package-shims: Judge the dashboard intercept test by shell-profile PATH (#3827)
- The dashboard Package managers -> Test action now judges PATH activation with
package_shim_dashboard_status, the same shell-profile projection the status cards use. The resident daemon never loads shell profiles… probe_package_shim_interceptsgains aproject_shell_profileoption. The CLI and runtime callers keep probing against the caller's real PATH.- New
hol-guard package-shims test [--manager <name>] --jsonsubcommand runs the intercept proof from a shell, behind the same approval gate as the dashboard action.
- The dashboard Package managers -> Test action now judges PATH activation with
- guard: Load Cursor hooks by replacing unsupported beforeWriteFile (#3825)
- New hook entry. Guard now installs a
preToolUseentry withfailClosed: true. Itsmatcheris^(Write|Edit|StrReplace|MultiEdit|Delete)$, so the entry only fires for file mutation tools. Shell, MCP, and read… - Review decisions become deny. Cursor only stops a
preToolUsecall when the answer isdeny; anasklets the tool run. Guard therefore answers review decisions for these tools withdeny, the same way it… - Reinstall cleans up the old entry. Reinstalling or upgrading removes the
beforeWriteFileentries that earlier Guard releases wrote, so Cursor loads the file again. Hooks written by other tools under that event…
- New hook entry. Guard now installs a
- sync: Scrub CLI credential arguments from synced receipt commands (#3824)
- When a receipt had no full action envelope,
envelopeRedactedwas forwarded as stored,commandincluded, even if the current sync level isfull. raw_command_textand the encoded receipt command were sanitized withredact_sensitive_textonly. Cloud review events already use the stronger scrubber, which also removes those credential arguments.
- When a receipt had no full action envelope,
- guard: Let routine Codex apply_patch edits pass native review (#3821)
- Parse the patch with the same grammar as Codex's own
apply_patchparser, including where Codex trims a line before matching a hunk header. Every header Codex would act on is checked. Any line Codex would not accept… - Grant
native_exact_safe_file_writeonly when every target passes the existing workspace write check (workspace or registered worktree, sensitive-path, hidden-path, hard-link and autostart checks). - Also refuse targets that are agent instruction files (
AGENTS.md,CLAUDE.mdand similar) or sit under agent or VCS metadata directories (.codex,.claude,.cursor,.agents,.gitand others). Both the name…
- Parse the patch with the same grammar as Codex's own
- runtime: Retire the managed resident when its Guard home is deleted (#3822)
- codex: Stop holding ordinary Codex Git reads and skill reads, and explain authority repair (#3808)
- Codex Git reads.** The Codex hook bridge did not forward its execution environment to the daemon. The Claude Code, OpenCode, and bounded CLI bridges already do. Without it, the native Git-helper check treated the…
- daemon: Read camelCase toolInput from ZCode, Devin and Grok hooks (#3820)
- native reviews never offered Always allow exact action; only "Allow just this once" appeared, and
raw_command_textwas empty - saved exact-action allow/block decisions were never looked up
- custom extension rules (for example blocking
wrangler delete) were ignored on the daemon path
- native reviews never offered Always allow exact action; only "Allow just this once" appeared, and
- daemon: Retire a superseded same-install daemon after a native-only upgrade (#3815)
- A daemon left running across an in-place upgrade that changes only the native runtime is now retired instead of staying wedged on
native_policy_not_ready. - The runtime manifest is part of the daemon runtime fingerprint, so a native-only upgrade changes the install's identity.
- The daemon pins its fingerprint when it is constructed. A previous-generation process can no longer advertise the replacement install's identity by computing it lazily after the upgrade.
- A daemon left running across an in-place upgrade that changes only the native runtime is now retired instead of staying wedged on
- supply-chain: Restore paid first-time protection without approval loops (#3814)
- Let paid Cloud access restore package protection before any shims are installed. Keep local-only recovery limited to tools already protected.
- Check repair eligibility before asking for local approval. Refresh access before a repair and offer an access check instead of repeating password requests after a Cloud denial.
- Show each recovery error once and use a single restore action with issue details collapsed.
- uninstall: Rewrite group-writable user files and run self-uninstall from the desktop core (#3813)
- Runtime transitions clear group and world write bits (
mode & ~0o022) from the mode they publish when they rewrite an existing unpinned user file, so shell profiles and harness configs at 0664 (umask 0002) or 0666 no… - Still rejected: setuid/setgid/sticky bits, group- or world-writable modes requested for new files, and group-writable modes on pinned artifacts (
expected_digest/artifact_identity). file_mode_invalidnow names the offending path.
- Runtime transitions clear group and world write bits (
- dashboard: Keep extension inventory rendering when a launch kind is unknown (#3811)
mcp_launch.kindvalues the dashboard does not recognize now normalize to anunsupportedlaunch for that entry. Previously one unknown value threw and the whole Extensions inventory failed to load when the daemon…- The MCP server defaults card shows an "update Guard" note for unsupported launches and offers no launch details for them.
- Unknown
icon.kindfalls back tonone, and an unknownsurfacedrops only the MCP fields for that entry. Policy fields (trust_class,source,activation, modes, tool states) still reject unknown values.
- runtime: Recover a stale resident-update marker and report the real native failure (#3812)
hol-guard daemon repairre-points aresident-update.v1.lockmarker left behind by an interrupted update at the digest of the runtime Guard admits; when no compatible runtime is admitted it reportsunavailable…- Marker writes no longer truncate first. The new value overwrites the old one in place, the file shrinks only afterwards, and a failed write (for example
ENOSPC) restores the previous bytes. The file stays the flock… native_mcp_descriptor_digest_unavailablenow carries the transport's reason code, such asnative_resident_runtime_identity_mismatch. The CLI printsnative_*_unavailableerrors as runtime errors instead of usage…
- runtime: Require business context for local, Windows and launcher Google CLIs (#3799)
- Windows
.cmdshims (gws.cmd,GOG.CMD), which both extensions declare. - Package launchers:
npx gws,npx -y @scope/gws@1.2.0,pnpm exec gog,bunx gws. The parser records the launcher as the executable. - Workspace-local paths (
./gws,./node_modules/.bin/gws). These already resolved by basename; the new test now pins them.
- Windows
- contracts: Raise managed-controls catalog payload cap to 8MB (#3816)
- The daemon's extension-control
catalog()response serializes the entire built-in command registry and is bounded byMAX_CATALOG_PAYLOAD_BYTES(1MB inmanaged-controls/v1). - Main is currently at 987,939 / 1,000,000 bytes across 127 extensions — ~12KB of headroom. Any merged extension larger than ~12KB now trips
service.catalog()into413 catalog_payload_limit_exceeded, and the… - Raising the shared bound to 8MB gives ~900 extensions of headroom at the current ~7.8KB average wire size, applied consistently to: the runtime constant,
contracts/managed-controls/v1/limits.json, the catalog…
- The daemon's extension-control
- guard: Recognize npx wrangler as a CLI and parse yargs help rows (#3809)
npx wranglerpaste was rejected. Recognize treats any package-launcher command as a possible MCP server. The stdio probe ofnpx wranglerfailed, and the command was rejected withalready_built_in. A package…- Wrangler help produced junk command ids. Wrangler prints yargs-style help, where every row starts with the program and parent path (
wrangler d1 list List D1 databases). The parser took the first token, so it…
- codex: Read app inventory from native daemons and bound tool summaries (
9ed4ba2) - runtime: Refuse multi-record business dispatch (#3800)
Documentation
- guard: List business app compatibility by command and mode (#3803)
Tests
- policy: Add a canonical hash vector for business selectors (#3830)
- gauntlet: Cover Google Workspace CLI calls under the business policy (#3802)
CI & automation
- Report Google Discovery changes for reviewed gws methods (#3804)
Internal
- release: 3.37.0 (#3801)
- extensions: Publish missing command descriptors and resync stale fixtures (#3796)
Install
Install this release:
uv tool install "hol-guard[cisco]==3.37.0"Full changelog: v3.36.1...v3.37.0
Thanks @zerocodefast, @kdbhalala, @Abbilaash, @ThroughTheWind, @yohimik, ZCF, @Winipedia, @yunfeizhu!
Package publication and Desktop update availability are separate. Desktop updates are ready when the signed Core assets and update manifests appear below; macOS feed status shows signing and verification progress.