Skip to content
Security
Hook

Hooks

What stm runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
stm
45 commands4 hooks

Claude Code

> /plugin marketplace add matterhornso/subscribetome
> /plugin install stm@subscribetome

What fires, and when

PreToolUse

  • MatchesBash|Write|Edit|MultiEdit|NotebookEdit"${CLAUDE_PLUGIN_ROOT}"/hooks/pretooluse.sh

PostToolUse

  • MatchesBash"${CLAUDE_PLUGIN_ROOT}"/hooks/posttooluse.sh

UserPromptSubmit

Fires before Claude sees each prompt you send. A plugin can use it to inject context, so the same instruction reaches the model every turn instead of only at session start.

  • "${CLAUDE_PLUGIN_ROOT}"/hooks/userpromptsubmit.sh

SessionStart

Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.

  • "${CLAUDE_PLUGIN_ROOT}"/hooks/sessionstart.sh
Read hooks/hooks.json

Where it lives

  • hooks/posttooluse.shRunsGitHub
    Read the script
    #!/usr/bin/env bash
    # subscribetome PostToolUse hook — flags command output that leaked a key.
    # Thin wrapper; all logic is in src/hooks.ts (postToolUse).
    ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
    . "$ROOT/hooks/resolve-bun.sh"
    if ! stm_resolve_bun; then
      stm_bun_missing "PostToolUse hook"
      exit 0
    fi
    exec "$BUN" "$ROOT/src/cli.ts" hook posttooluse
    
  • hooks/pretooluse.shRunsGitHub
    Read the script
    #!/usr/bin/env bash
    # subscribetome PreToolUse hook — placeholder injection + leak guards.
    # Thin wrapper; all logic is in src/hooks.ts (preToolUse).
    ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
    . "$ROOT/hooks/resolve-bun.sh"
    if ! stm_resolve_bun; then
      stm_bun_missing "PreToolUse hook"
      exit 0
    fi
    exec "$BUN" "$ROOT/src/cli.ts" hook pretooluse
    
  • hooks/resolve-bun.shGitHub
    Read the script
    #!/usr/bin/env bash
    # Shared bun resolution for every stm shell entrypoint.
    #
    # WHY THIS EXISTS: hooks are spawned by the agent host (Claude Code / Codex),
    # whose environment is NOT the user's interactive shell. A GUI/Dock launch or
    # an IDE host commonly has a minimal PATH with no Homebrew on it. The old
    # one-liner
    #
    #     BUN="$(command -v bun || echo "$HOME/.bun/bin/bun")"
    #
    # had two defects: it only knew the official-installer location (missing
    # Homebrew's /opt/homebrew/bin/bun — which README.md itself recommends), and
    # it never checked that the fallback was executable, so a miss produced a
    # cryptic `exec: ... cannot execute` instead of a usable message.
    #
    # The failure was not cosmetic. With bun unresolvable the UserPromptSubmit
    # paste guard exited 0 without scanning — a security control silently failing
    # OPEN, with the user still believing pasted keys were being blocked.
    #
    # Mirrors resolveBunPath() in src/agents/codex-mcp-install.ts, which already
    # solved this for the Codex MCP surface.
    
    # Sets $BUN to an executable bun. Returns 0 on success, 1 if none found.
    stm_resolve_bun() {
      local candidate
      # 1. PATH first — covers the normal case and any custom install.
      candidate="$(command -v bun 2>/dev/null || true)"
      if [ -n "$candidate" ] && [ -x "$candidate" ]; then
        BUN="$candidate"
        return 0
      fi
      # 2. Known install locations, most likely first. Each is checked for
      #    executability, so a stale/partial install falls through instead of
      #    becoming an exec failure.
      for candidate in \
        "$HOME/.bun/bin/bun" \
        "/opt/homebrew/bin/bun" \
        "/usr/local/bin/bun" \
        "/home/linuxbrew/.linuxbrew/bin/bun" \
        "/snap/bin/bun"
      do
        if [ -x "$candidate" ]; then
          BUN="$candidate"
          return 0
        fi
      done
      return 1
    }
    
    # Loud, actionable message when bun can't be found. $1 = hook/entrypoint name.
    # Never silent: a guard that cannot run must say so rather than let the user
    # assume they are protected.
    stm_bun_missing() {
      local who="${1:-stm}"
      cat >&2 <<'EOF'
    [stm] Cannot find the `bun` runtime — stm is NOT running.
    EOF
      echo "[stm]   (entrypoint: ${who})" >&2
      cat >&2 <<'EOF'
    [stm] Looked on PATH and in: ~/.bun/bin, /opt/homebrew/bin, /usr/local/bin,
    [stm]   /home/linuxbrew/.linuxbrew/bin, /snap/bin
    [stm] Install bun (https://bun.sh) or, if it is already installed somewhere
    [stm]   else, symlink it into one of those locations.
    [stm] Until then: placeholders are NOT substituted and the paste guard does
    [stm]   NOT scan your prompts. Run `stm doctor` for the full picture.
    EOF
    }
    
  • hooks/sessionstart.shRunsGitHub
    Read the script
    #!/usr/bin/env bash
    # subscribetome SessionStart hook — injects stm usage guidance into every
    # session so the model knows how to use stm-managed keys with no user setup.
    # Thin wrapper; all logic is in src/hooks.ts (sessionStart).
    ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
    . "$ROOT/hooks/resolve-bun.sh"
    if ! stm_resolve_bun; then
      stm_bun_missing "SessionStart hook"
      exit 0
    fi
    exec "$BUN" "$ROOT/src/cli.ts" hook sessionstart
    
  • hooks/userpromptsubmit.shRunsGitHub
    Read the script
    #!/usr/bin/env bash
    # subscribetome UserPromptSubmit hook — blocks a raw key pasted into the chat.
    # Thin wrapper; all logic is in src/hooks.ts (userPromptSubmit).
    ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
    . "$ROOT/hooks/resolve-bun.sh"
    if ! stm_resolve_bun; then
      stm_bun_missing "UserPromptSubmit hook"
      exit 0
    fi
    exec "$BUN" "$ROOT/src/cli.ts" hook userpromptsubmit
    

Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.

@matterhornso
Ships withstm

Your API keys in the OS keychain. Your AI coding agent uses them — without ever seeing them. The model writes {{stm:openai:default}}. The real key is swapped in at the moment the command runs.

Stars on GitHub

Momentum

stars in total
4
Star history of matterhornso/subscribetome on GitHub, a chart by star-history.com

More plugins that ship hooks.

watermarks-remover

watermarks-remover

Agent skill + stdlib Python service to strip multi-vendor AI provenance marks from text and files, for privacy and hygiene on content you own. The skill is a thin client: it drives the machinery over HTTP, so the agent host needs no Python.

2 skills1 hook26k
@guillaumemeyer@guillaumemeyer
Install Plugin
agentic-bug-hunter

agentic-bug-hunter

Runs recon on a target, tests it for real, reportable vulnerabilities, checks each finding against a strict validation gate, and writes a report ready to submit to bug bounty platforms. It also remembers patterns across targets and resumes unfinished sessions.

19 skills+35.8k
@awarexone@awarexone
Install Plugin
agentic-bug-hunter

agentic-bug-hunter

A Claude Code plugin for bug bounty hunters, bundling skills for reconnaissance, vulnerability hunting such as IDOR, SSRF and XSS, black-box audits of deployed AI agents, and CI/CD pipeline security.

19 skills+35.8k
@shuvonsec@shuvonsec
Install Plugin
cc-safety-net

cc-safety-net

A pre-execution guard that blocks destructive Git and file system commands, and common attempts to read sensitive files, before a tool call runs. Works with several AI coding agents, including Claude Code.

2 skills1 hook1.9k
@kenryu42@kenryu42
Install Plugin
claude-code-safety-net

claude-code-safety-net

A pre-execution guard that blocks destructive Git and file system commands, plus common attempts to read sensitive files, before an AI coding agent runs a tool call. Works with Claude Code and several other agent CLIs.

2 skills1 hook1.9k
@kenryu42@kenryu42
Install Plugin
pentest-agents

pentest-agents

A bug bounty agent framework for Claude Code that automates reconnaissance, vulnerability hunting and exploit chaining, with skills for analyzing recon output, running autonomous hunt loops and correlating findings into attack chains.

39 skills+31.1k
@h-mmer@h-mmer
Install Plugin
vestige

vestige

Vestige is a fail-closed runtime firewall for AI agents. The model proposes, a deterministic gate decides, and every action leaves a receipt. When something breaks, causal_walk finds the real cause.

3 agents+1660
@samvallad33@samvallad33
Install Plugin
cti-expert

cti-expert

A cyber threat intelligence and OSINT analysis toolkit that runs structured investigations and produces analyst-style reports with sourced, trust-scored findings. Built for security analysts working OSINT and CTI cases in Claude Code.

1 skill+2624
@7onez@7onez
Install Plugin

Questions about the hooks in stm.

Which coding agents can use the hooks in stm?
The hooks in stm install in Claude Code and Cursor: each runs Claude Code hooks from .claude/settings.json, so copy the hooks there.