Hooks
What subrosa runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
> /plugin marketplace add ij5a/subrosa > /plugin install subrosa@subrosa
Ships with subrosa. Installing the plugin gets these hooks.
What fires, and when
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/run.sh session-start
SessionEnd
"${CLAUDE_PLUGIN_ROOT}"/hooks/run.sh session-end
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/run.sh user-prompt-submit
PreCompact
"${CLAUDE_PLUGIN_ROOT}"/hooks/run.sh pre-compact
Stop
"${CLAUDE_PLUGIN_ROOT}"/hooks/run.sh stop
Where it lives
- hooks/run.shRunsGitHub
Read the script
#!/bin/sh # Find the subrosa binary and run the given hook event. If no binary exists yet, # bootstrap the release pinned in hooks/binary-version for this platform — # sha256-verified against hooks/sha256sums.txt committed in this repo — into the # data dir. Everything is best-effort and quiet: a failed download must never # break a Claude Code session. EVENT="$1" [ -n "$EVENT" ] || exit 0 DATA="${SUBROSA_DIR:-$HOME/.claude/subrosa}" # Parameter expansion, not $(dirname): the hot path must not fork. hooks.json # always invokes us by absolute path, so stripping the last component works. SELF="${0%/*}" [ "$SELF" != "$0" ] || SELF="." # Sets BIN directly (no $(...) capture subshell — this runs on every prompt). find_bin() { if command -v subrosa >/dev/null 2>&1; then BIN=subrosa return 0 fi for c in "$HOME/.cargo/bin/subrosa" "$DATA/bin/subrosa" "$SELF/../bin/subrosa"; do if [ -x "$c" ]; then BIN="$c" return 0 fi done BIN="" } bootstrap() { # Owner-only for everything the bootstrap creates (data dir, temp download). umask 077 [ -s "$SELF/binary-version" ] && [ -s "$SELF/sha256sums.txt" ] || return 1 VERSION="$(cat "$SELF/binary-version")" case "$(uname -s)-$(uname -m)" in Darwin-arm64) TARGET=aarch64-apple-darwin ;; Darwin-x86_64) TARGET=x86_64-apple-darwin ;; Linux-x86_64) TARGET=x86_64-unknown-linux-musl ;; Linux-aarch64|Linux-arm64) TARGET=aarch64-unknown-linux-musl ;; *) return 1 ;; esac ARCHIVE="subrosa-$VERSION-$TARGET.tar.gz" WANT="$(awk -v f="$ARCHIVE" '$2 == f {print $1}' "$SELF/sha256sums.txt")" [ -n "$WANT" ] || return 1 TMP="$(mktemp -d)" || return 1 if ! curl -fsSL --proto '=https' --proto-redir '=https' --max-time 120 -o "$TMP/$ARCHIVE" \ "https://github.com/ij5a/subrosa/releases/download/$VERSION/$ARCHIVE"; then rm -rf "$TMP" return 1 fi if command -v sha256sum >/dev/null 2>&1; then GOT="$(sha256sum "$TMP/$ARCHIVE" | awk '{print $1}')" else GOT="$(shasum -a 256 "$TMP/$ARCHIVE" | awk '{print $1}')" fi if [ "$GOT" != "$WANT" ]; then rm -rf "$TMP" return 1 fi mkdir -p "$DATA/bin" && chmod 700 "$DATA" "$DATA/bin" 2>/dev/null tar -xzf "$TMP/$ARCHIVE" -C "$DATA/bin" subrosa && chmod 755 "$DATA/bin/subrosa" STATUS=$? rm -rf "$TMP" return $STATUS } find_bin if [ -z "$BIN" ]; then mkdir -p "$DATA" 2>/dev/null if bootstrap >>"$DATA/hook.log" 2>&1; then echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) bootstrap: installed $(cat "$SELF/binary-version") to $DATA/bin" >>"$DATA/hook.log" fi find_bin [ -n "$BIN" ] || exit 0 fi # No exec, and stderr dropped: an older PATH binary that doesn't know this # event yet must degrade to a silent no-op, never a failed hook. "$BIN" hook "$EVENT" 2>/dev/null exit 0
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.
Persistent, private memory for Claude Code — every session archived locally, searchable. Sub rosa.

