Installation
Install the shk CLI with npm, bun, the bundled installer script, Homebrew, or from source.
On this page
shk is distributed as a single CLI binary.
npm
Each tagged CLI release publishes the security-harness-kit package to npm. The installed command is shk:
npm install -g security-harness-kit
shk --versionThe npm package is generated by dist from the same release. On install it fetches the matching prebuilt release archive for your platform and exposes the shk command, so it supports the same platforms as the release archives.
For one-off runs without a global install:
npx security-harness-kit scanbun
The same package works with bun. The package's postinstall script downloads the binary at install time; when bun skips lifecycle scripts, which is its default for packages it does not trust, the shk launcher fetches the matching release archive on the first run instead, so the install still works:
bun add -g security-harness-kit
shk --versionFor one-off runs without a global install:
bunx security-harness-kit scanInstall With Script
macOS and Linux releases can be installed with the bundled installer:
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/Kazuki-tam/security-harness-kit/releases/latest/download/shk-cli-installer.sh | shWindows releases can be installed from PowerShell:
powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://github.com/Kazuki-tam/security-harness-kit/releases/latest/download/shk-cli-installer.ps1 | iex"-ExecutionPolicy Bypass is scoped to this one PowerShell process, so it avoids common script policy failures without changing the user's machine or profile policy. If you are already in PowerShell, this equivalent form also works:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force; irm https://github.com/Kazuki-tam/security-harness-kit/releases/latest/download/shk-cli-installer.ps1 | iexIf your organization enforces PowerShell through MachinePolicy or UserPolicy, the script installer may still be blocked. In that case, install with npm or bun instead, or download the .zip archive and verify its checksum by hand (see Download A Release Archive).
The installers are generated by dist and download the latest matching release archive. The shell installer verifies the selected archive against the SHA-256 checksum embedded at release time before installing shk. The generated PowerShell installer does not currently perform checksum verification; Windows users who require verification should verify the .zip archive manually. By default, script installers use the Cargo-style install path ($CARGO_HOME/bin, or ~/.cargo/bin when CARGO_HOME is unset).
Download A Release Archive
Tagged releases publish platform archives, per-archive checksums, installers, a Homebrew formula, maintainer WinGet manifests, and a CycloneDX SBOM:
shk-cli-aarch64-apple-darwin.tar.xz
shk-cli-aarch64-unknown-linux-gnu.tar.xz
shk-cli-x86_64-apple-darwin.tar.xz
shk-cli-x86_64-pc-windows-msvc.zip
shk-cli-x86_64-unknown-linux-gnu.tar.xz
shk-cli-installer.sh
shk-cli-installer.ps1
shk-winget-manifests.zip
shk.rb
shk-cli-npm-package.tar.gz
*-dist-manifest.json
*.sha256
shk-sbom.cdx.jsonVerify the archive before unpacking:
shasum -a 256 -c shk-cli-x86_64-unknown-linux-gnu.tar.xz.sha256Each archive contains the shk binary. Tagged releases also generate GitHub artifact attestations for release assets. Verify a downloaded asset with the GitHub CLI:
gh attestation verify shk-cli-x86_64-unknown-linux-gnu.tar.xz \
--repo Kazuki-tam/security-harness-kitOn Windows, download shk-cli-x86_64-pc-windows-msvc.zip and its .sha256 file, compare Get-FileHash -Algorithm SHA256 against the checksum, unpack shk.exe, and place it in a directory on PATH (the installer default is %USERPROFILE%\.cargo\bin).
Verified Archive Install
For CI or security-sensitive environments, install from a pinned release tag and verify both the checksum and the GitHub artifact attestation before placing the binary on PATH:
version=v0.7.0
target=x86_64-unknown-linux-gnu
asset="shk-cli-${target}.tar.xz"
repo=Kazuki-tam/security-harness-kit
gh release download "$version" -R "$repo" -p "$asset" -p "${asset}.sha256"
shasum -a 256 -c "${asset}.sha256"
gh attestation verify "$asset" -R "$repo"
tmp="$(mktemp -d)"
tar -xJf "$asset" -C "$tmp"
install -m 755 "$tmp/shk-cli-${target}/shk" "$HOME/.cargo/bin/shk"Replace target with the archive that matches your platform. Avoid latest in CI so builds are reproducible and reviewable. shk ci init github generates a workflow that performs exactly this verified install.
Homebrew
Each tagged CLI release publishes the generated Homebrew formula to the public tap Kazuki-tam/homebrew-tap. Install with:
brew install Kazuki-tam/homebrew-tap/shkHomebrew drops the homebrew- prefix, so the short form also works:
brew install kazuki-tam/tap/shkThe formula always tracks the latest release. To upgrade later, run brew upgrade shk.
Alternatively, the formula (shk.rb) is attached to each release as an asset and can be installed directly without the tap:
brew install --formula https://github.com/Kazuki-tam/security-harness-kit/releases/latest/download/shk.rbTo install a pinned release this way, replace latest/download with download/<tag> (e.g. download/v0.7.0).
Intel macOS, Apple Silicon macOS, Linux x86_64/aarch64, and Windows x86_64 are supported. Scoop manifests are not published by the current release pipeline.
Desktop App
The desktop app is distributed separately from the CLI. Releases are published
from desktop-vX.Y.Z (or combined shk-vX.Y.Z) tags as shk-desktop_* assets
on GitHub Releases. Starting with desktop-v0.6.0, macOS builds are
Developer ID signed, notarized, and stapled. Windows installers are currently
not Authenticode-signed (see
Windows SmartScreen below).
See desktop-release.md for maintainer release steps.
Choose an installer
| Platform | Asset pattern | Notes |
|---|---|---|
| Linux x86_64 | shk-desktop_*_x86_64-unknown-linux-gnu_*.AppImage or *.deb |
AppImage needs chmod +x |
| Linux aarch64 | shk-desktop_*_aarch64-unknown-linux-gnu_*.AppImage or *.deb |
Same as above |
| macOS Intel | shk-desktop_*_x86_64-apple-darwin_*.dmg |
Signed and notarized; drag shk.app to /Applications |
| macOS Apple Silicon | shk-desktop_*_aarch64-apple-darwin_*.dmg |
Same as above |
| Windows x86_64 | shk-desktop_*_x86_64-pc-windows-msvc_*setup.exe or *.msi |
Currently unsigned |
Stable download links
The desktop-latest release always carries the installers from the newest
signed desktop release under version-free names, so these URLs never change:
desktop-latest also carries shk-desktop.sha256sum for the stable names and
shk-desktop-latest.json, whose release_tag says which versioned release the
stable files currently come from. The files are byte-identical to the
shk-desktop_* assets of that release, so its provenance attestation verifies
them too.
Verify a stable download:
curl -LO https://github.com/Kazuki-tam/security-harness-kit/releases/download/desktop-latest/shk-desktop-aarch64-apple-darwin.dmg
curl -LO https://github.com/Kazuki-tam/security-harness-kit/releases/download/desktop-latest/shk-desktop.sha256sum
awk '$2 == "shk-desktop-aarch64-apple-darwin.dmg"' shk-desktop.sha256sum \
| shasum -a 256 -c -To pin a specific version instead, download the versioned shk-desktop_*
assets and shk-desktop.sha256sum from that tag's release page, for example
desktop-v0.7.0.
macOS
Installers from desktop-v0.6.0 onward are Developer ID signed and notarized;
Gatekeeper opens them without workarounds. If you still run an older unsigned
early access build, replace it with a signed .dmg install — the in-app
updater also migrates existing installs because all releases share the same
Tauri updater signing keys.
Windows SmartScreen
Windows installers are currently not Authenticode-signed, so SmartScreen may show Windows protected your PC. Choose More info → Run anyway if you trust the release checksum and attestation.
Blocked-activity notifications
While the app is open it tails .shk/audit.log for every project in the
sidebar and raises an OS notification when a hook blocks AI activity, so an
agent running in the background is visible without switching to the app. The
bell menu in the top bar turns notifications off, or narrows them to one kind
of block; both kinds are on by default.
Details worth knowing:
- Only blocks recorded after a project appears in the sidebar are announced — existing history never produces a backlog of notifications.
- Blocks arriving within a few seconds collapse into a single notification.
- Notification text is limited to the block reason, the risky-action category, and the AI tool. File paths are deliberately left out, because notifications render on the lock screen and are persisted by the OS; use the Blocked AI activity panel to see them.
- Turning notifications off stops the banners, not the tailing: the audit panel still updates while the app is open.
- The first block prompts for OS notification permission (on macOS the
installed app appears as shk; a
tauri devbinary sends through the Terminal identity instead, so allow Terminal notifications when testing). - No banner but blocks listed in the panel almost always means macOS is suppressing display: check Focus mode, and the per-app notification style in System Settings → Notifications.
In-app updates
The desktop app checks desktop-latest/latest.json on GitHub for updater
metadata. Updater packages are always signed with the project Tauri updater
key, independent of OS code signing.
Build From Source
Building from source requires Rust 1.88 or newer.
git clone https://github.com/Kazuki-tam/security-harness-kit.git
cd security-harness-kit
cargo build --releaseThe release binaries are written to:
target/release/shkUninstall
shk does not ship a dedicated shk uninstall command. Removal has two layers: the CLI binary, and any project or user-level files written by shk while it was in use.
1. Remove The Binary
Pick the method that matches how shk was installed.
Script installer (default ~/.cargo/bin):
rm -f "${CARGO_HOME:-$HOME/.cargo}/bin/shk"Windows (PowerShell installer; default %USERPROFILE%\.cargo\bin when CARGO_HOME is unset):
$BinDir = if ($env:CARGO_HOME) { Join-Path $env:CARGO_HOME "bin" } else { "$env:USERPROFILE\.cargo\bin" }
Remove-Item (Join-Path $BinDir "shk.exe") -ErrorAction SilentlyContinueHomebrew formula:
brew uninstall shk
# If installed from a tap, you can also remove it:
# brew untap Kazuki-tam/homebrew-tapnpm package:
npm uninstall -g security-harness-kitbun package:
bun remove -g security-harness-kitSource build: run cargo clean in the cloned repository to remove build output, or remove target/release/shk directly. If you copied that binary into a directory on PATH, remove the copied binary there as well.
2. Remove Project Artifacts
shk does not modify project files unless you explicitly run a command that writes to disk. The artifacts created by those commands are listed below. Remove any that you no longer need from each project.
| Source | Path | Notes |
|---|---|---|
shk init / shk policy init |
shk.toml |
Project policy file. |
shk init with npm hardening |
.npmrc, pnpm-workspace.yaml, .yarnrc.yml, bunfig.toml as applicable |
Project package-manager hardening files. Remove only settings added for ignore-scripts or package age gates if the file also contains your own package-manager configuration. |
shk scan --audit, audit-mode hooks |
.shk/audit.log and the .shk/ directory |
Metadata-only audit log. |
shk hooks install |
.git/hooks/pre-commit |
Managed block delimited by # shk-managed-start / # shk-managed-end. Delete the file if shk is the only owner, or remove just the managed block to keep other pre-commit logic. |
shk hooks install-ai (Claude Code) |
.claude/settings.json |
Remove entries tagged with "_shk_managed": true. Delete the file if it has no remaining entries. If you used --apply-deny or --apply-sandbox, also review the permissions.deny and sandbox settings that were merged into the same file. |
shk hooks install-ai (Cursor) |
.cursor/hooks.json |
Remove entries tagged with "_shk_managed": true. |
shk hooks install-ai (Codex) |
.codex/config.toml |
Remove the block delimited by # shk-managed-start / # shk-managed-end, and features.hooks = true if no longer needed. The managed block covers PreToolUse, PermissionRequest, UserPromptSubmit, and PostToolUse. If you used --apply-sandbox, also review the top-level sandbox_mode and approval_policy values. |
shk hooks install-ai (Copilot) |
.github/hooks/shk-security.json |
Remove entries whose command contains shk scan --hook-mode copilot. |
shk hooks install-ai (Antigravity) |
.agents/hooks.json |
Remove the top-level shk-security entry (its hook entries are tagged with "_shk_managed": true). Delete the file if it has no remaining entries. |
shk hooks install-ai (Windsurf) |
.windsurf/hooks.json |
Remove entries whose command contains shk scan --hook-mode windsurf. Delete the file if it has no remaining entries. |
shk skills install (Claude Code) |
.claude/skills/shk/SKILL.md |
Bundled skill file. Installs from 0.3.17 or earlier used .claude/skills/shk.md; remove that file too if present. |
shk skills install (Copilot) |
.github/skills/shk/SKILL.md |
Bundled skill file. |
shk skills install (Codex / Cursor / Antigravity) |
.agents/skills/shk/SKILL.md |
Bundled skill file. |
shk skills install (Windsurf) |
.windsurf/skills/shk/SKILL.md |
Bundled skill file. |
shk ci init github |
.github/workflows/shk.yml by default |
Generated GitHub Actions workflow. If you passed --output, remove that custom path instead. |
For commands that support it, re-running with --dry-run is a safe way to confirm the exact paths used in your project before deleting them. This applies to shk hooks install-ai, shk skills install, and shk ci init github; shk hooks install and shk init do not have a dry-run mode.
3. Remove User-Level Files
--global installs write to the user's home directory instead of the project. Remove these only if you want to disable shk for every project on this machine.
| Source | Path |
|---|---|
shk hooks install-ai --global --tool claude-code |
~/.claude/settings.json (managed entries, plus any permissions.deny or sandbox settings you explicitly enabled) |
shk hooks install-ai --global --tool codex |
~/.codex/config.toml (managed block, plus top-level sandbox settings if you used --apply-sandbox) |
shk hooks install-ai --global --tool cursor |
~/.cursor/hooks.json (managed entries) |
shk hooks install-ai --global --tool copilot |
~/.copilot/hooks/shk-security.json (managed entries) |
shk hooks install-ai --global --tool antigravity |
~/.gemini/config/hooks.json (managed shk-security entry) |
shk hooks install-ai --global --tool windsurf |
~/.codeium/windsurf/hooks.json (managed entries identified by --hook-mode windsurf) |
shk skills install --global --tool claude-code |
~/.claude/skills/shk/SKILL.md (or the legacy ~/.claude/skills/shk.md from 0.3.17 or earlier) |
shk skills install --global --tool codex / --tool cursor |
~/.agents/skills/shk/SKILL.md |
shk skills install --global --tool copilot |
~/.copilot/skills/shk/SKILL.md |
shk skills install --global --tool antigravity |
~/.gemini/config/skills/shk/SKILL.md |
shk skills install --global --tool windsurf |
~/.codeium/windsurf/skills/shk/SKILL.md |
Managed entries use the same markers as project installs ("_shk_managed": true for JSON files, # shk-managed-start / # shk-managed-end for shell and TOML files). Copilot and Windsurf keep schema-clean JSON and are identified by their --hook-mode <tool> command strings. Settings merged by --apply-deny and --apply-sandbox are not individually tagged; review them before removing so you do not discard unrelated user configuration.
4. Remove Stored Env Keys
If you used shk env dotenvx import-keys or shk env key import / shk env encrypt, delete stored private keys before removing the binary so they are not orphaned. Stored keys are scoped to the canonical project root, so run this from each project where keys were stored:
shk env dotenvx delete --all
shk env key delete --allWhen [env].secret_store = "keyring" (the default), dotenvx keys live under the OS credential service security-harness-kit/dotenvx, and native keys live under security-harness-kit/env. If shk has already been removed, search for those service names in the platform credential store UI.
When [env].secret_store = "1password", keys are stored as tagged 1Password items (shk tag) in the vault configured by env.onepassword.vault. Item titles look like shk:{project_id}:env:DOTENV_PRIVATE_KEY or shk:{project_id}:dotenvx:DOTENV_PRIVATE_KEY_PRODUCTION. Delete them from the vault UI, or migrate back to the keyring first:
shk env key migrate --to keyringVerify the keyring copy, then remove the old tagged items explicitly from 1Password. Automatic source deletion is intentionally refused for a shared 1Password source.