Hooks
What crowdstrike-falcon-foundry runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
> /plugin marketplace add CrowdStrike/foundry-skills > /plugin install crowdstrike-falcon-foundry@foundry-marketplace
Ships with crowdstrike-falcon-foundry. 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/foundry-session-start.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/foundry-skill-router.sh
PreToolUse
${CLAUDE_PLUGIN_ROOT}/hooks/foundry-skill-router.sh- Matches
Bash${CLAUDE_PLUGIN_ROOT}/hooks/foundry-cli-guard.sh - Matches
Skill${CLAUDE_PLUGIN_ROOT}/hooks/superpowers-foundry-bridge.sh
Where it lives
- hooks/foundry-cli-guard.shRunsGitHub
Read the script
#!/usr/bin/env bash # # foundry-cli-guard.sh # # PreToolUse hook that enforces --no-prompt on all Foundry CLI commands, # blocks manual directory/file creation that should use the CLI, and # reminds Claude to confirm resource names with the user before creating. # # Prevents common failures: # 1. Running Foundry CLI commands without --no-prompt (causes Error: EOF) # 2. Running foundry apps deploy without --change-type (causes 500 error) # 3. Running ui extensions create without --sockets (interactive picker hangs) # 4. Using mkdir/touch to create app structure (causes invalid manifests) # 5. Creating resources without user confirmation of the name # # Receives JSON on stdin with hook_event_name and tool-specific fields. # Outputs JSON with additionalContext (advisory nudge, not blocking). # # Environment variables: # FOUNDRY_SKIP_NAME_CONFIRM=1 Bypass name confirmation (for automated tests) # # Note: foundry-skill-router.sh also fires on `api-integrations create` for # OpenAPI spec adaptation. Both hooks produce independent advisories. set -euo pipefail INPUT=$(cat) HOOK_EVENT=$(echo "$INPUT" | jq -r '.hook_event_name // empty') if [ "$HOOK_EVENT" != "PreToolUse" ]; then exit 0 fi TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty') # Only validate Bash commands if [ "$TOOL_NAME" != "Bash" ]; then exit 0 fi COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty') # Check for Foundry CLI commands that need --no-prompt # Nearly all Foundry CLI commands support --no-prompt: # apps create/validate/release/delete, functions create, collections create, # workflows create, api-integrations create, # ui pages create, ui extensions create, rtr-scripts create, profile create/delete # functions exec (incl. exec list / exec status), functions logs, functions test if echo "$COMMAND" | grep -qE 'foundry\s+apps\b.*\b(create|validate|release|delete)\b|foundry\s+(functions|collections|workflows|api-integrations|rtr-scripts)\b.*\bcreate\b|foundry\s+functions\s+(exec|logs|test)\b|foundry\s+profile\b.*\b(create|delete)\b|foundry\s+ui\s+(pages|extensions)\b.*\bcreate\b'; then # Check if --no-prompt is missing if ! echo "$COMMAND" | grep -qF -- '--no-prompt'; then jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: "The command is missing --no-prompt. Foundry CLI commands (create/validate/release, functions exec/logs/test) run non-interactively in Claude Code and will hang with Error: EOF without it. Add --no-prompt before retrying. Example: foundry apps create --name \"app-name\" --no-prompt" } }' exit 0 fi fi # Check for foundry apps deploy without --change-type # Omitting --change-type causes a 500 error (server-side panic) because the # Foundry API requires a change_type field in deploy requests. if echo "$COMMAND" | grep -qE 'foundry\s+apps\s+deploy\b'; then if ! echo "$COMMAND" | grep -qF -- '--change-type'; then jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: "The command is missing --change-type. Foundry apps deploy requires --change-type and --change-log to avoid a 500 error. Add both flags before retrying. Example: foundry apps deploy --change-type Patch --change-log \"description of changes\" --no-prompt" } }' exit 0 fi if ! echo "$COMMAND" | grep -qF -- '--change-log'; then jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: "The command is missing --change-log. Foundry apps deploy requires --change-type and --change-log. Add both flags before retrying. Example: foundry apps deploy --change-type Patch --change-log \"description of changes\" --no-prompt" } }' exit 0 fi fi # Check for foundry ui extensions create without --sockets # Omitting --sockets launches an interactive picker that hangs with Error: EOF. if echo "$COMMAND" | grep -qE 'foundry\s+ui\s+extensions\b.*\bcreate\b'; then if ! echo "$COMMAND" | grep -qF -- '--sockets'; then jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: "The command is missing --sockets. Without it, the CLI launches an interactive socket picker that will hang with Error: EOF. Run `foundry ui extensions list-sockets` to see available sockets. Example: foundry ui extensions create --name \"my-ext\" --from-template React --sockets \"activity.detections.details\" --no-prompt" } }' exit 0 fi # Validate --sockets value against known valid socket IDs SOCKET_VAL=$(echo "$COMMAND" | grep -oE -- '--sockets\s+"?[^"[:space:]]+"?' | sed 's/--sockets[[:space:]]*//' | tr -d '"') if [ -n "$SOCKET_VAL" ]; then VALID_SOCKETS="activity.detections.details identity.detections.details automated-leads.leads.details hosts.host.panel xdr.cases.panel ngsiem.workbench.details workflows.executions.execution.details" IS_VALID=false for vs in $VALID_SOCKETS; do if [ "$SOCKET_VAL" = "$vs" ]; then IS_VALID=true break fi done if [ "$IS_VALID" = "false" ]; then jq -n --arg val "$SOCKET_VAL" '{ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: ("Invalid socket ID: \"" + $val + "\". Run `foundry ui extensions list-sockets` for available sockets. Known IDs: activity.detections.details, identity.detections.details, automated-leads.leads.details, hosts.host.panel, xdr.cases.panel, ngsiem.workbench.details, workflows.executions.execution.details.") } }' exit 0 fi fi fi # Check for foundry workflows actions/triggers view without --no-prompt # The CLI currently ignores --no-prompt for these commands (FOUNDRY-3049) and # always launches an interactive Select() prompt. Adding --no-prompt is still # correct (for when the bug is fixed), but the real workaround is # the workflow skill's bundled action_search.py, which queries the API directly. if echo "$COMM - hooks/foundry-session-start.shRunsGitHub
Read the script
#!/usr/bin/env bash # # foundry-session-start.sh — SessionStart hook # # 1. Check Foundry CLI version and warn if below minimum required # 2. Set FOUNDRY_UI_HEADLESS_MODE=true for CLIs below 2.0.1 (older versions # need this env var to suppress the TUI; 2.0.1+ auto-detects headless) # set -euo pipefail # --- Version check --- MINIMUM_VERSION="2.1.0" NEEDS_UPGRADE=0 if CLI_OUTPUT=$(foundry version 2>/dev/null); then CLI_VERSION=$(echo "$CLI_OUTPUT" | awk '{print $2}') # Compare semver: split into major.minor.patch IFS='.' read -r CUR_MAJ CUR_MIN CUR_PAT <<< "$CLI_VERSION" IFS='.' read -r MIN_MAJ MIN_MIN MIN_PAT <<< "$MINIMUM_VERSION" if [ "${CUR_MAJ:-0}" -lt "${MIN_MAJ:-0}" ]; then NEEDS_UPGRADE=1 elif [ "${CUR_MAJ:-0}" -eq "${MIN_MAJ:-0}" ]; then if [ "${CUR_MIN:-0}" -lt "${MIN_MIN:-0}" ]; then NEEDS_UPGRADE=1 elif [ "${CUR_MIN:-0}" -eq "${MIN_MIN:-0}" ] && [ "${CUR_PAT:-0}" -lt "${MIN_PAT:-0}" ]; then NEEDS_UPGRADE=1 fi fi if [ "$NEEDS_UPGRADE" -eq 1 ]; then cat >&2 << UPGRADE_EOF IMPORTANT: Foundry CLI $CLI_VERSION is below the minimum required $MINIMUM_VERSION. Before proceeding with any Foundry work, you MUST inform the user and offer to upgrade: - macOS/Linux: brew upgrade crowdstrike/foundry-cli/foundry - Windows: Download https://assets.foundry.crowdstrike.com/cli/latest/foundry_Windows_x86_64.zip Feature unavailable below $MINIMUM_VERSION: function execution and debugging (foundry functions exec, test, logs), non-interactive output for actions view and triggers view with multiple matches, and automatic headless mode detection. Use AskUserQuestion to ask whether to upgrade now. If the user declines, Foundry commands may fail or behave unexpectedly. UPGRADE_EOF fi fi # --- Env vars for older CLIs --- # CLIs below 2.0.1 need FOUNDRY_UI_HEADLESS_MODE=true to suppress the TUI. # 2.0.1+ auto-detects headless environments, so this is only needed as a fallback. if [ "$NEEDS_UPGRADE" -eq 1 ]; then if [ -n "${CLAUDE_ENV_FILE:-}" ]; then echo 'export FOUNDRY_UI_HEADLESS_MODE=true' >> "$CLAUDE_ENV_FILE" else cat >&2 << ENV_EOF IMPORTANT: Foundry CLI $CLI_VERSION requires FOUNDRY_UI_HEADLESS_MODE=true to suppress the TUI in non-interactive environments. You MUST run this export before ANY foundry CLI command (deploy, release, validate, etc.), or those commands will fail with "could not open a new TTY": export FOUNDRY_UI_HEADLESS_MODE=true Run this silently at the start of any Bash tool call that uses the foundry CLI. Do not ask the user — just prepend it. ENV_EOF fi fi exit 0 - hooks/foundry-skill-router.shRunsGitHub
Read the script
#!/usr/bin/env bash # # foundry-skill-router.sh # # Two-hook system for Foundry skill routing: # 1. UserPromptSubmit: Detects specific Foundry keywords → writes marker file + injects context # 2. PreToolUse (all tools): Reads marker → injects advisory reminder to use # the Foundry development workflow skill (non-blocking) # # The marker file bridges the two hooks since they run at different times. # Cleaned up once the Skill tool is invoked. # # Receives JSON on stdin with hook_event_name and event-specific fields. # Outputs JSON with additionalContext or permissionDecision. set -euo pipefail INPUT=$(cat) HOOK_EVENT=$(echo "$INPUT" | jq -r '.hook_event_name // empty') MARKER="/tmp/.foundry-skill-router-active" case "$HOOK_EVENT" in UserPromptSubmit) USER_PROMPT=$(echo "$INPUT" | jq -r '.prompt // .user_prompt // empty') PROMPT_LOWER=$(echo "$USER_PROMPT" | tr '[:upper:]' '[:lower:]') FOUNDRY_MATCH=false # Require an action verb + Foundry noun to detect real development intent. # "create a foundry app" triggers; "if we were in a foundry app" does not. VERBS="create|build|deploy|release|scaffold|add|update|fix|debug|configure" NOUNS="foundry app|foundry function|foundry collection|foundry workflow|foundry ui|foundry page|foundry api|falcon foundry|falcon app|crowdstrike app|foundry extension" if echo "$PROMPT_LOWER" | grep -qE "\b(${VERBS})\b.*(${NOUNS})"; then FOUNDRY_MATCH=true elif echo "$PROMPT_LOWER" | grep -qE "(${NOUNS}).*\b(${VERBS})\b"; then # Also catch "foundry app ... deploy" word order FOUNDRY_MATCH=true fi # Explicit CLI commands always trigger for cmd in "foundry apps create" "foundry apps deploy" "foundry apps release" \ "foundry apps run" "foundry login"; do if echo "$PROMPT_LOWER" | grep -qF "$cmd"; then FOUNDRY_MATCH=true break fi done # Explicit skill requests always trigger if echo "$PROMPT_LOWER" | grep -qE "(use|invoke|run) foundry (skill|plugin)"; then FOUNDRY_MATCH=true fi if [ "$FOUNDRY_MATCH" = true ]; then # Write marker so PreToolUse hook knows to inject advisory context echo "$$" > "$MARKER" # Standalone Fusion workflow? Advise the sibling plugin instead of # steering into app scaffolding. Without this the classifier is never # consulted at runtime and the agent tends to quietly author the workflow # itself, never telling the user a better-suited plugin exists. REDIRECT_SCRIPT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/skills/development-workflow/scripts/detect_fusion_redirect.py" if [ -f "$REDIRECT_SCRIPT" ]; then VERDICT=$(printf '%s' "$USER_PROMPT" | python3 "$REDIRECT_SCRIPT" 2>/dev/null || true) if echo "$VERDICT" | grep -q '"redirect": true'; then # If the sibling plugin is already installed, say "use it" rather than # "install it". Best-effort: the file may be absent, in which case we # fall back to the install wording. Mirrors the check in # fusion-skills' fusion-foundry-bridge.sh. FUSION_HINT="Advise the crowdstrike-falcon-fusion plugin — /plugin install crowdstrike-falcon-fusion, or https://claude.com/plugins/crowdstrike-falcon-fusion." if [ -f "$HOME/.claude/plugins/installed_plugins.json" ] && grep -q "crowdstrike-falcon-fusion" "$HOME/.claude/plugins/installed_plugins.json" 2>/dev/null; then FUSION_HINT="The crowdstrike-falcon-fusion plugin is already installed — hand off to its workflows skill." fi jq -n --arg hint "$FUSION_HINT" '{ hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext: ("STANDALONE FUSION WORKFLOW DETECTED: this request looks like a trigger plus actions that already exist in the CID — no UI, function, collection, or API integration to build. It does NOT need a Foundry app. " + $hint + " Do NOT scaffold a Foundry app. Naming the plugin is required output — declining to scaffold is only half the redirect, and hand-writing the workflow YAML yourself defeats the purpose since that plugin discovers real action IDs, validates against the platform schema, and imports to the CID. This detection is advisory: if the request genuinely needs an app capability built, proceed with crowdstrike-falcon-foundry:development-workflow instead.") } }' exit 0 fi fi jq -n '{ hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext: "FOUNDRY PLUGIN DETECTED: This prompt involves Falcon Foundry development. Do NOT enter plan mode. IMMEDIATELY invoke crowdstrike-falcon-foundry:development-workflow using the Skill tool. That skill handles requirements gathering, clarifying questions, CLI scaffolding, and sub-skill delegation." } }' exit 0 fi ;; PreToolUse) TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty') # Auto-adapt OpenAPI spec before allowing api-integrations create if [ "$TOOL_NAME" = "Bash" ]; then TOOL_INPUT=$(echo "$INPUT" | jq -r '.tool_input.command // empty') if echo "$TOOL_INPUT" | grep -q 'foundry api-integrations create'; then # Extract the spec file path from --spec flag SPEC_FILE=$(echo "$TOOL_INPUT" | grep -oE '\-\-spec\s+[^ ]+' | awk '{print $2}') if [ -n "$SPEC_FILE" ] && [ -f "$SPEC_FILE" ]; then # Find the adapt script relative to the plugin root PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)" ADAPT_SCRIPT="$PLUGIN_ROOT/skills/api-integrations/scripts/adapt_spec_for_foundry.py" # Run the adapt script automatically to fix known issues if [ -f "$ADAPT_SCRIPT" ]; then if ! ADAPT_OUTPUT=$(python3 "$ADAPT_SCRIPT" "$SPEC_FILE" 2>&1); then jq -n --arg output "$ADAPT_OUTPUT" --arg r - hooks/superpowers-foundry-bridge.shRunsGitHub
Read the script
#!/usr/bin/env bash # # superpowers-foundry-bridge.sh # # PreToolUse hook on the Skill tool. Blocks superpowers:brainstorming and # redirects to development-workflow which owns the Foundry dev flow. # Advisory context is injected for other superpowers planning skills. # # Receives JSON on stdin with tool_input.skill (the skill being invoked). # Outputs JSON with decision or additionalContext. set -euo pipefail INPUT=$(cat) SKILL_NAME=$(echo "$INPUT" | jq -r '.tool_input.skill // empty') # Redirect brainstorming to the Foundry development workflow skill. # Uses additionalContext for a clean UX (no error messages). # ~75% reliable — when it misses, the model still has Foundry skills in its # available skills list. deny is 100% reliable but shows ugly duplicate errors. case "$SKILL_NAME" in superpowers:brainstorming|brainstorming) jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: "STOP. Do NOT proceed with brainstorming. The Foundry plugin is installed and crowdstrike-falcon-foundry:development-workflow MUST be used instead. It handles requirements gathering, CLI scaffolding, and manifest coordination for Foundry apps. Cancel this brainstorming skill invocation and invoke crowdstrike-falcon-foundry:development-workflow immediately." } }' exit 0 ;; esac # Advisory context for other superpowers planning skills case "$SKILL_NAME" in superpowers:writing-plans|writing-plans|\ superpowers:executing-plans|executing-plans|\ superpowers:subagent-driven-development|subagent-driven-development) CONTEXT=$(cat <<'FOUNDRY_CONTEXT' FOUNDRY PLUGIN INSTALLED: If this task involves Falcon Foundry, invoke crowdstrike-falcon-foundry:development-workflow BEFORE this skill. That skill owns Foundry app creation — it uses CLI commands (foundry apps create, foundry api-integrations create, etc.) that generate manifest.yml and wire up capability IDs correctly. Hand-writing manifest.yml or workflow YAML without the CLI causes deploy failures. FOUNDRY_CONTEXT ) jq -n \ --arg ctx "$CONTEXT" \ '{ hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: $ctx } }' exit 0 ;; esac
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.
AI coding assistant skills for building CrowdStrike Falcon Foundry apps. Build Foundry apps from a natural language prompt — API integrations, workflows, UI pages, functions, and collections — all scaffolded with the Foundry CLI and deployed to the Falcon
Repo: CrowdStrike/foundry-skills

