n8n-mcp-skills
Expert Claude Code skills for building flawless n8n workflows using the n8n-mcp MCP server.
What octo runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
Claude Code
> /plugin marketplace add nyldn/claude-octopus
Cursor
Cursor also runs Claude Code hooks from .claude/settings.json, so copy these hooks there to use them in Cursor.
What fires, and when
PreToolUse
Bash${CLAUDE_PLUGIN_ROOT}/hooks/provider-routing-validator.shTaskCreate${CLAUDE_PLUGIN_ROOT}/hooks/task-dependency-validator.shBash${CLAUDE_PLUGIN_ROOT}/hooks/codex-exec-guard.sh${CLAUDE_PLUGIN_ROOT}/hooks/codex-exec-guard.sh${CLAUDE_PLUGIN_ROOT}/hooks/codex-exec-guard.shBash${CLAUDE_PLUGIN_ROOT}/hooks/scheduler-security-gate.shEnterPlanMode${CLAUDE_PLUGIN_ROOT}/hooks/plan-mode-interceptor.shBash${CLAUDE_PLUGIN_ROOT}/hooks/careful-check.shEdit|Write${CLAUDE_PLUGIN_ROOT}/hooks/freeze-check.shPostToolUse
Bash|Agent|Write|Edit|Read|WebFetch|Grep${CLAUDE_PLUGIN_ROOT}/hooks/post-tool-dispatch.shBash${CLAUDE_PLUGIN_ROOT}/hooks/quality-gate.shTaskUpdate${CLAUDE_PLUGIN_ROOT}/hooks/task-completion-checkpoint.shBash${CLAUDE_PLUGIN_ROOT}/hooks/telemetry-webhook.shSessionStart
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}/scripts/helpers/ensure-plugin-root.sh${CLAUDE_PLUGIN_ROOT}/hooks/context-reinforcement.sh${CLAUDE_PLUGIN_ROOT}/hooks/auto-router-inject.sh${CLAUDE_PLUGIN_ROOT}/hooks/session-start-memory.sh${CLAUDE_PLUGIN_ROOT}/hooks/statusline-auto-repair.sh${CLAUDE_PLUGIN_ROOT}/hooks/version-advisory.sh${CLAUDE_PLUGIN_ROOT}/hooks/plugin-update-advisory.sh${CLAUDE_PLUGIN_ROOT}/hooks/fable5-inject.sh${CLAUDE_PLUGIN_ROOT}/hooks/discipline-inject.shTeammateIdle
${CLAUDE_PLUGIN_ROOT}/hooks/teammate-idle-dispatch.shTaskCompleted
${CLAUDE_PLUGIN_ROOT}/hooks/task-completed-transition.shConfigChange
${CLAUDE_PLUGIN_ROOT}/hooks/config-change-handler.shSubagentStop
${CLAUDE_PLUGIN_ROOT}/hooks/subagent-result-capture.sh${CLAUDE_PLUGIN_ROOT}/hooks/subagent-stop-gate.shInstructionsLoaded
${CLAUDE_PLUGIN_ROOT}/hooks/instructions-loaded.shPreCompact
${CLAUDE_PLUGIN_ROOT}/hooks/pre-compact.shSessionEnd
${CLAUDE_PLUGIN_ROOT}/hooks/session-end.sh${CLAUDE_PLUGIN_ROOT}/hooks/workflow-verification.shUserPromptSubmit
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/user-prompt-submit.sh${CLAUDE_PLUGIN_ROOT}/hooks/done-criteria.sh${CLAUDE_PLUGIN_ROOT}/hooks/github-work-queue-watch.shStopFailure
${CLAUDE_PLUGIN_ROOT}/hooks/stop-failure-log.shCwdChanged
${CLAUDE_PLUGIN_ROOT}/hooks/cwd-changed.shTaskCreated
${CLAUDE_PLUGIN_ROOT}/hooks/discipline-task-gate.sh${CLAUDE_PLUGIN_ROOT}/hooks/task-dependency-validator.shPostCompact
${CLAUDE_PLUGIN_ROOT}/hooks/post-compact.shElicitation
${CLAUDE_PLUGIN_ROOT}/hooks/elicitation-handler.shElicitationResult
${CLAUDE_PLUGIN_ROOT}/hooks/elicitation-handler.sh resultPermissionDenied
${CLAUDE_PLUGIN_ROOT}/hooks/permission-denied-log.shWhere it lives
#!/usr/bin/env bash
# Native Windows has no supported Octopus runtime.
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*|CYGWIN*) exit 0 ;;
esac
# auto-router-inject.sh - Compact SessionStart routing contract.
#
# Inject one small, explicit contract early in the session so hook-provided
# routing instructions are honored.
set -euo pipefail
_octo_hook_exit() { local c=$?; if [[ $c -ne 0 ]]; then echo "[hook:$(basename "$0")] exit $c" >&2 2>/dev/null || true; fi; return 0; }
trap _octo_hook_exit EXIT
# Provider subprocesses are already inside an Octopus dispatch. Do not inject
# a second routing contract that can trigger recursive orchestration.
[[ "${OCTOPUS_PROVIDER_CHILD:-false}" == "true" ]] && exit 0
escape_for_json() {
local s="$1"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//$'\n'/\\n}"
s="${s//$'\r'/\\r}"
s="${s//$'\t'/\\t}"
printf '%s' "$s"
}
emit_session_context() {
local context="$1"
local escaped
escaped=$(escape_for_json "$context")
if [[ -n "${CURSOR_PLUGIN_ROOT:-}" ]]; then
printf '{"additional_context":"%s"}\n' "$escaped"
elif [[ -n "${CLAUDE_PLUGIN_ROOT:-}" && -z "${COPILOT_CLI:-}" ]]; then
printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"%s"}}\n' "$escaped"
else
printf '{"additionalContext":"%s"}\n' "$escaped"
fi
}
normalize_router_mode() {
local raw
raw=$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]' | tr '_' '-')
case "$raw" in
off|disabled|disable|none|0) echo "off" ;;
suggest|suggestion|advisory|hint|hints|false|no) echo "suggest" ;;
invoke|auto|auto-invoke|autoinvoke|mandatory|true|yes|on|1) echo "invoke" ;;
*) return 1 ;;
esac
}
json_pref_value() {
local file="$1"
local key="$2"
[[ -f "$file" ]] || return 1
command -v python3 &>/dev/null || return 1
python3 -c "
import json, sys
try:
with open(sys.argv[1]) as f:
data = json.load(f)
value = data.get(sys.argv[2], None)
if value is not None:
print(str(value))
except Exception:
pass
" "$file" "$key" 2>/dev/null
}
# Explicit-only is the safe default. Preferences and environment overrides can
# still opt into suggest/invoke behavior.
AUTO_ROUTER_MODE="off"
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
SETTINGS_FILE="${PLUGIN_ROOT}/settings.json"
[[ -f "$SETTINGS_FILE" ]] || SETTINGS_FILE="${PLUGIN_ROOT}/.claude-plugin/settings.json"
if [[ -f "$SETTINGS_FILE" ]]; then
_setting_router=$(json_pref_value "$SETTINGS_FILE" "OCTOPUS_AUTO_ROUTER_MODE" || true)
_setting_legacy=$(json_pref_value "$SETTINGS_FILE" "OCTOPUS_AUTO_INVOKE" || true)
if [[ -n "$_setting_router" ]] && _mode=$(normalize_router_mode "$_setting_router"); then
AUTO_ROUTER_MODE="$_mode"
elif [[ -n "$_setting_legacy" ]] && _mode=$(normalize_router_mode "$_setting_legacy"); then
AUTO_ROUTER_MODE="$_mode"
fi
fi
PREFS_FILE="${HOME}/.claude-octopus/preferences.json"
if [[ -f "$PREFS_FILE" ]]; then
_pref_router=$(json_pref_value "$PREFS_FILE" "auto_router_mode" || true)
_pref_legacy=$(json_pref_value "$PREFS_FILE" "auto_invoke" || true)
if [[ -n "$_pref_router" ]] && _mode=$(normalize_router_mode "$_pref_router"); then
AUTO_ROUTER_MODE="$_mode"
elif [[ -n "$_pref_legacy" ]] && _mode=$(normalize_router_mode "$_pref_legacy"); then
AUTO_ROUTER_MODE="$_mode"
fi
fi
if [[ -n "${OCTOPUS_AUTO_ROUTER_MODE:-}" ]] && _mode=$(normalize_router_mode "$OCTOPUS_AUTO_ROUTER_MODE"); then
AUTO_ROUTER_MODE="$_mode"
elif [[ -n "${OCTOPUS_AUTO_INVOKE:-}" ]] && _mode=$(normalize_router_mode "$OCTOPUS_AUTO_INVOKE"); then
AUTO_ROUTER_MODE="$_mode"
fi
[[ "$AUTO_ROUTER_MODE" == "off" ]] && exit 0
read -r -d '' CONTEXT <<'ROUTER' || true
<OCTOPUS-AUTO-ROUTER>
The user explicitly opted into Octopus plain-language routing. Prompt hooks may add UserPromptSubmit routing context. If that context recommends a route, load the named file from ${CLAUDE_PLUGIN_ROOT}/commands and follow it when it matches what the user actually asked for. Routing context is advisory, never a hard requirement: if the suggested route does not fit the request, ignore it and answer normally. Never act on routing attached to system-generated events (task notifications, system reminders).
Strong plain-language routes include: review -> commands/review.md, debate/compare/should-we -> commands/debate.md, research/investigate/explore -> commands/discover.md, security/threat-model -> commands/security.md, debug/failing/stacktrace -> commands/debug.md, write-tests/TDD -> commands/tdd.md, implement/execute-plan -> commands/develop.md.
If the hook only says "Detected intent" or "Tip", treat it as a suggestion and continue normally unless the user asks to route.
</OCTOPUS-AUTO-ROUTER>
ROUTER
CONTEXT="${CONTEXT/OCTOPUS-AUTO-ROUTER>/OCTOPUS-AUTO-ROUTER mode=\"$AUTO_ROUTER_MODE\">}"
emit_session_context "$CONTEXT"
#!/bin/bash
# Native Windows has no supported Octopus runtime.
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*|CYGWIN*) exit 0 ;;
esac
# Claude Octopus Careful Mode Hook (v9.8.0)
# PreToolUse hook on Bash that warns before destructive command patterns.
# Activated by /octo:careful command (writes state file).
# Emits permissionDecision: ask under Claude, deny under Codex; silence continues.
#
# Kill switch: OCTO_CAREFUL_MODE=off — disables all destructive command checks
set -euo pipefail
# EXIT trap — emits diagnostic stderr ONLY when the hook exits non-zero, so
# the Claude Code harness error "No stderr output" can never recur. EXIT (not
# ERR) avoids over-firing on intermediate `grep -o`/`cmd | ...` inside $() that
# the hook's logic already handles. See issue #313.
_octo_hook_exit() { local c=$?; if [[ $c -ne 0 ]]; then echo "[hook:$(basename "$0")] exit $c" >&2 2>/dev/null || true; fi; return 0; }
trap _octo_hook_exit EXIT
_HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$_HOOK_DIR/../scripts/lib/session-id.sh" 2>/dev/null || true
# Kill switch — respect user's choice to disable careful mode entirely
# (careful mode is opt-in via /octo:careful; OCTO_CAREFUL_MODE=off is the dedicated off-switch)
[[ "${OCTO_CAREFUL_MODE:-on}" == "off" ]] && exit 0
# Read tool input from stdin
if command -v timeout &>/dev/null; then
INPUT=$(timeout 3 cat 2>/dev/null || true)
else
INPUT=$(cat 2>/dev/null || true)
fi
[[ -z "$INPUT" ]] && INPUT='{}'
# Check if careful mode is active
if declare -f octo_session_state_file >/dev/null 2>&1; then
STATE_FILE=$(octo_session_state_file "careful" "txt" "$INPUT")
else
STATE_FILE="/tmp/octopus-careful-${CLAUDE_CODE_SESSION_ID:-${CLAUDE_SESSION_ID:-$$}}.txt"
fi
if [[ ! -f "$STATE_FILE" ]]; then
: # pass-through — current hook schema treats silence as continue
exit 0
fi
_octo_invalid_input() {
printf '%s\n' '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Careful mode could not validate the tool input. Check that Python 3 is installed and the hook input is valid JSON before retrying."}}'
exit 0
}
# _octo_careful_decision: Emit a host-compatible decision without executing the supplied command.
_octo_careful_decision() {
python3 "$_HOOK_DIR/safety-contract.py" careful-decision "$1" 2>/dev/null || _octo_invalid_input
}
# Codex calls exec_command Bash in PreToolUse, just as Claude does.
# Parse JSON structurally so whitespace and escaped quotes retain their meaning.
TOOL_NAME=$(printf '%s' "$INPUT" | python3 "$_HOOK_DIR/safety-contract.py" field tool_name 2>/dev/null) || _octo_invalid_input
[[ "$TOOL_NAME" == "Bash" ]] || exit 0
COMMAND=$(printf '%s' "$INPUT" | python3 "$_HOOK_DIR/safety-contract.py" field command 2>/dev/null) || _octo_invalid_input
CHECK_TEXT="$COMMAND"
[[ -n "$CHECK_TEXT" ]] || exit 0
# ── Destructive pattern checks ────────────────────────────────────────
# 1. rm -rf: check every executable statement and target, including -fr.
# Safe-only targets: node_modules dist .next __pycache__ build coverage .turbo.
# A safe target never exempts another target or a later shell statement.
RM_RISK=$(printf '%s' "$INPUT" | python3 "$_HOOK_DIR/safety-contract.py" careful-rm 2>/dev/null) || _octo_invalid_input
case "$RM_RISK" in
safe|unsafe) ;;
*) _octo_invalid_input ;;
esac
if [[ "$RM_RISK" == "unsafe" ]]; then
_octo_careful_decision 'Careful mode requires review: recursive deletion or unclassified executable input.'
exit 0
fi
# 2. SQL destructive operations. A SQL-looking string alone is not execution: source
# searches and output commands routinely contain examples such as `DROP TABLE` and
# `TRUNCATE users`. Gate only when the statement is either a direct shell command or
# appears alongside a known SQL client. This keeps read-only grep/rg/printf commands
# quiet while retaining coverage for client flags, stdin pipes, and heredocs.
_octo_drop_pat='DROP\s+(TABLE|DATABASE)(\s+IF\s+EXISTS)?(\s+["'\''`]?[[:alnum:]_.$-]+["'\''`]?)?'
_octo_truncate_pat='TRUNCATE\s+["'\''`]?[[:alnum:]_.$-]+["'\''`]?(\s+["'\''`]?[[:alnum:]_.$-]+["'\''`]?)?'
_octo_sql_pat="${_octo_drop_pat}|${_octo_truncate_pat}"
_octo_sql_client_pat='(^|[;&|][[:space:]]*)((sudo|command|env)[[:space:]]+)?([[:alpha:]_][[:alnum:]_]*=[^[:space:]]+[[:space:]]+)*(psql|mysql|mariadb|sqlite3|sqlcmd|cockroach\s+sql)([[:space:]]|$)'
_octo_direct_sql_pat="^[[:space:]]*(${_octo_sql_pat})"
# ERE alternation alone cannot distinguish `TRUNCATE TABLE foo` from the
# incomplete `TRUNCATE TABLE`: the optional TABLE branch can backtrack and
# consume TABLE as the identifier. Inspect candidate tokens so TABLE requires a
# third token, while `TRUNCATE users` and quoted identifiers remain protected.
_octo_has_destructive_sql() {
local drop_matches truncate_matches
drop_matches=$(echo "$CHECK_TEXT" | grep -oiE "$_octo_drop_pat" || true)
if [[ -n "$drop_matches" ]] && printf '%s\n' "$drop_matches" | awk '
{
if (NF < 3) next
if (tolower($3) == "if") {
if (NF < 5 || tolower($4) != "exists") next
target = $5
} else {
target = $3
}
quote = substr(target, 1, 1)
apostrophe = sprintf("%c", 39)
if ((quote == "\"" || quote == "`" || quote == apostrophe) &&
substr(target, length(target), 1) != quote) next
found = 1
exit
}
END { exit(found ? 0 : 1) }
'; then
return 0
fi
truncate_matches=$(echo "$CHECK_TEXT" | grep -oiE "$_octo_truncate_pat" || true)
[[ -n "$truncate_matches" ]] || return 1
printf '%s\n' "$truncate_matches" | awk '
{
raw = $2
token = tolower(raw)
gsub(/^["`]/, "", token)
gsub(/["`;]$/, "", token)
apostrophe = sprintf("%c", 39)
first = substr(raw, 1, 1)
quoted = (f#!/bin/bash
# Native Windows has no supported Octopus runtime.
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*|CYGWIN*) exit 0 ;;
esac
# Provider CLI guard — blocks unsafe direct non-interactive provider dispatch.
# PreToolUse hook on Bash. Returns block decision with correction message.
# WHY: `codex "prompt"` launches interactive TUI which fails in non-TTY (Claude Code Bash tool).
# `codex exec "prompt"` is the correct non-interactive mode.
# Direct Qwen dispatch can enter OAuth device authorization and open a browser.
# Direct Gemini dispatch uses a retired individual client. Both bypass Octopus
# provider admission and authentication checks.
set -euo pipefail
# EXIT trap — emits diagnostic stderr ONLY when the hook exits non-zero, so
# the Claude Code harness error "No stderr output" can never recur. EXIT (not
# ERR) avoids over-firing on intermediate `grep -o`/`cmd | ...` inside $() that
# the hook's logic already handles. See issue #313.
_octo_hook_exit() { local c=$?; if [[ $c -ne 0 ]]; then echo "[hook:$(basename "$0")] exit $c" >&2 2>/dev/null || true; fi; return 0; }
trap _octo_hook_exit EXIT
# Note: this gate guards correctness, not user permission policy, so it runs
# regardless of bypassPermissions.
INPUT=$(cat 2>/dev/null || true)
[[ -z "$INPUT" ]] && exit 0
# Extract command
if command -v jq &>/dev/null; then
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""' 2>/dev/null || echo "")
else
COMMAND=$(echo "$INPUT" | grep -o '"command":"[^"]*"' | head -1 | cut -d'"' -f4)
fi
[[ -z "$COMMAND" ]] && exit 0
# Find the closing parenthesis for a $(...) command substitution. Parentheses
# inside quotes/backticks do not close the substitution; nested substitutions
# and grouping parentheses increase its depth. Bash 3.2 compatible.
_octo_command_sub_end() {
local source="$1" start="$2" state="plain" escaped="false" depth=1
local i char next
for ((i = start; i < ${#source}; i++)); do
char="${source:i:1}"
next="${source:i+1:1}"
if [[ "$escaped" == "true" ]]; then
escaped="false"
continue
fi
case "$state" in
single)
[[ "$char" == "'" ]] && state="plain"
;;
double)
case "$char" in
'"') state="plain" ;;
"\\") escaped="true" ;;
'$')
if [[ "$next" == '(' ]]; then
depth=$((depth + 1))
i=$((i + 1))
fi
;;
esac
;;
backtick)
case "$char" in
'`') state="plain" ;;
"\\") escaped="true" ;;
esac
;;
plain)
case "$char" in
"'") state="single" ;;
'"') state="double" ;;
'`') state="backtick" ;;
"\\") escaped="true" ;;
'(') depth=$((depth + 1)) ;;
')')
depth=$((depth - 1))
if [[ $depth -eq 0 ]]; then
printf '%s\n' "$i"
return 0
fi
;;
esac
;;
esac
done
return 1
}
_octo_backtick_end() {
local source="$1" start="$2" escaped="false" i char
for ((i = start; i < ${#source}; i++)); do
char="${source:i:1}"
if [[ "$escaped" == "true" ]]; then
escaped="false"
elif [[ "$char" == "\\" ]]; then
escaped="true"
elif [[ "$char" == '`' ]]; then
printf '%s\n' "$i"
return 0
fi
done
return 1
}
# Print the delimiter, tab-stripping flag, and quoting flag for the first
# heredoc operator that appears in executable shell syntax on a line. Operators
# inside quotes and comments are data, not syntax.
_octo_heredoc_spec() {
local line="$1" state="plain" escaped="false"
local i char next previous j strip_tabs="false" quote delimiter="" quoted="false"
for ((i = 0; i < ${#line}; i++)); do
char="${line:i:1}"
next="${line:i+1:1}"
previous="${line:i-1:1}"
if [[ "$escaped" == "true" ]]; then
escaped="false"
continue
fi
case "$state" in
single)
[[ "$char" == "'" ]] && state="plain"
;;
double)
case "$char" in
'"') state="plain" ;;
"\\") escaped="true" ;;
esac
;;
plain)
case "$char" in
"'") state="single" ;;
'"') state="double" ;;
"\\") escaped="true" ;;
'#')
if [[ $i -eq 0 || "$previous" == ' ' || "$previous" == $'\t' ]]; then
return 1
fi
;;
'<')
[[ "$next" == '<' ]] || continue
j=$((i + 2))
if [[ "${line:j:1}" == '-' ]]; then
strip_tabs="true"
j=$((j + 1))
fi
while [[ "${line:j:1}" == ' ' || "${line:j:1}" == $'\t' ]]; do
j=$((j + 1))
done
quote="${line:j:1}"
if [[ "$quote" == "'" || "$quote" == '"' ]]; then
quoted="true"
j=$((j + 1))
while [[ $j -lt ${#line} && "${line:j:1}" != "$quote" ]]; do
delimiter="${delimiter}${line:j:1}"
#!/usr/bin/env bash
# Native Windows has no supported Octopus runtime.
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*|CYGWIN*) exit 0 ;;
esac
# Claude Octopus ConfigChange Hook Handler
# Triggered when Claude Code configuration changes (v2.1.49+)
# Detects Octopus setting changes and writes reload signal for orchestrate.sh
# v8.29.0: Expanded from fast-mode-only to full Octopus settings hot-reload
set -euo pipefail
# EXIT trap — emits diagnostic stderr ONLY when the hook exits non-zero, so
# the Claude Code harness error "No stderr output" can never recur. EXIT (not
# ERR) avoids over-firing on intermediate `grep -o`/`cmd | ...` inside $() that
# the hook's logic already handles. See issue #313.
_octo_hook_exit() { local c=$?; if [[ $c -ne 0 ]]; then echo "[hook:$(basename "$0")] exit $c" >&2 2>/dev/null || true; fi; return 0; }
trap _octo_hook_exit EXIT
CONFIG_CHANGE_DATA=""
if [[ ! -t 0 ]]; then
CONFIG_CHANGE_DATA="$(cat)"
fi
SESSION_ID="${CLAUDE_SESSION_ID:-}"
WORKFLOW_PHASE="${OCTOPUS_WORKFLOW_PHASE:-unknown}"
SIGNAL_DIR="${HOME}/.claude-octopus"
# Log the change for debugging
if [[ "${VERBOSE:-false}" == "true" ]]; then
echo "[ConfigChange] Session: $SESSION_ID, Phase: $WORKFLOW_PHASE" >&2
if [[ -n "$CONFIG_CHANGE_DATA" ]]; then
echo "[ConfigChange] Data: $CONFIG_CHANGE_DATA" >&2
fi
fi
if [[ -n "$CONFIG_CHANGE_DATA" ]]; then
# Detect fast mode toggle
if echo "$CONFIG_CHANGE_DATA" | grep -q '"fast"' 2>/dev/null; then
if [[ "${VERBOSE:-false}" == "true" ]]; then
echo "[ConfigChange] Fast mode setting changed" >&2
fi
fi
# Detect Octopus-specific setting changes
NEEDS_RELOAD=false
for setting in OCTOPUS_ROUTING_MODE OCTOPUS_AUTONOMY OCTOPUS_OPUS_MODE \
OCTOPUS_MAX_COST_USD OCTOPUS_MAX_PARALLEL_AGENTS \
OCTOPUS_QUALITY_GATE_THRESHOLD OCTOPUS_WORKTREE_ISOLATION \
OCTOPUS_WEBHOOK_URL OCTOPUS_AGY_SANDBOX OCTOPUS_CODEX_SANDBOX \
OCTOPUS_MEMORY_INJECTION OCTOPUS_PERSONA_PACKS OCTOPUS_COST_WARNINGS \
OCTOPUS_TOOL_POLICIES; do
if echo "$CONFIG_CHANGE_DATA" | grep -q "\"$setting\"" 2>/dev/null; then
NEEDS_RELOAD=true
if [[ "${VERBOSE:-false}" == "true" ]]; then
echo "[ConfigChange] Octopus setting changed: $setting" >&2
fi
fi
done
# Write reload signal for orchestrate.sh to pick up on next invocation
if [[ "$NEEDS_RELOAD" == "true" ]]; then
mkdir -p "$SIGNAL_DIR"
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$SIGNAL_DIR/.config-reload-signal" 2>/dev/null || true
if [[ "${VERBOSE:-false}" == "true" ]]; then
echo "[ConfigChange] Wrote reload signal for orchestrate.sh" >&2
fi
fi
fi
: # pass-through — current hook schema treats silence as continue
exit 0
#!/bin/bash
# Native Windows has no supported Octopus runtime.
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*|CYGWIN*) exit 0 ;;
esac
# Context Reinforcement Hook — SessionStart
# Re-injects Iron Laws after context compaction so enforcement rules survive
# conversation compression. Inspired by obra/superpowers v4.3.1 SessionStart pattern.
#
# Hook type: SessionStart
# Returns: {"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"<CONTEXT-REINFORCEMENT>...</CONTEXT-REINFORCEMENT>"}
set -euo pipefail
# EXIT trap — emits diagnostic stderr ONLY when the hook exits non-zero, so
# the Claude Code harness error "No stderr output" can never recur. EXIT (not
# ERR) avoids over-firing on intermediate `grep -o`/`cmd | ...` inside $() that
# the hook's logic already handles. See issue #313.
_octo_hook_exit() { local c=$?; if [[ $c -ne 0 ]]; then echo "[hook:$(basename "$0")] exit $c" >&2 2>/dev/null || true; fi; return 0; }
trap _octo_hook_exit EXIT
# Read JSON payload from stdin (required by hook protocol)
if command -v timeout &>/dev/null; then
INPUT=$(timeout 3 cat 2>/dev/null || true)
else
INPUT=$(cat 2>/dev/null || true)
fi
[[ -z "$INPUT" ]] && INPUT='{}'
ACTIVATION_LIB="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}/scripts/lib/hook-activation.sh"
[[ -r "$ACTIVATION_LIB" ]] || exit 0
# shellcheck source=../scripts/lib/hook-activation.sh
source "$ACTIVATION_LIB" 2>/dev/null || exit 0
octo_hook_profile_allows "context-reinforcement" || exit 0
octo_hook_workflow_active "$INPUT" || exit 0
# Build compact enforcement context only for the active, matching workflow.
# Native disable-model-invocation frontmatter is the hard activation gate; this
# reminder only helps an explicitly started workflow survive compaction.
read -r -d '' CONTEXT <<'RULES' || true
<CONTEXT-REINFORCEMENT source="🐙 Octopus">
Hard gates: no-stubs (verify before claiming done), test-first (failing test before code), debug-protocol (root cause before fix), orchestrate-only (use orchestrate.sh for research), factory-pipeline (no skipping steps).
All Octopus commands and skills are explicit-only. Continue only the active workflow recorded for this Claude session.
</CONTEXT-REINFORCEMENT>
RULES
# Escape the context for JSON output
ESCAPED_CONTEXT=$(echo "$CONTEXT" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null | sed 's/^"//;s/"$//')
# Return the hook response
cat <<EOF
{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"${ESCAPED_CONTEXT}"}}
EOF
#!/usr/bin/env bash
# Native Windows has no supported Octopus runtime.
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*|CYGWIN*) exit 0 ;;
esac
# cwd-changed.sh — Re-detect project context when working directory changes
# Hook event: CwdChanged (CC v2.1.83+)
# Outputs additionalContext with project type detection for the new directory.
set -euo pipefail
# EXIT trap — emits diagnostic stderr ONLY when the hook exits non-zero, so
# the Claude Code harness error "No stderr output" can never recur. EXIT (not
# ERR) avoids over-firing on intermediate `grep -o`/`cmd | ...` inside $() that
# the hook's logic already handles. See issue #313.
_octo_hook_exit() { local c=$?; if [[ $c -ne 0 ]]; then echo "[hook:$(basename "$0")] exit $c" >&2 2>/dev/null || true; fi; return 0; }
trap _octo_hook_exit EXIT
# Read hook input from stdin (JSON with new_cwd field)
INPUT=$(cat 2>/dev/null) || INPUT=""
[[ -z "$INPUT" ]] && exit 0
# Extract new CWD — try jq first, fall back to regex
if command -v jq &>/dev/null; then
NEW_CWD=$(echo "$INPUT" | jq -r '.new_cwd // empty' 2>/dev/null) || NEW_CWD=""
else
# Fallback: extract with grep
NEW_CWD=$(echo "$INPUT" | grep -o '"new_cwd"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"new_cwd"[[:space:]]*:[[:space:]]*"//' | sed 's/"$//' 2>/dev/null) || NEW_CWD=""
fi
[[ -z "$NEW_CWD" || ! -d "$NEW_CWD" ]] && exit 0
# Detect project characteristics
context_hints=""
# Check if it's a git repo
if [[ -d "$NEW_CWD/.git" ]]; then
context_hints="git-repo"
fi
# Detect language/framework
if [[ -f "$NEW_CWD/package.json" ]]; then
context_hints="${context_hints:+$context_hints, }node/js"
if grep -q '"next"' "$NEW_CWD/package.json" 2>/dev/null; then
context_hints="$context_hints, nextjs"
fi
if grep -q '"react"' "$NEW_CWD/package.json" 2>/dev/null; then
context_hints="$context_hints, react"
fi
elif [[ -f "$NEW_CWD/pyproject.toml" || -f "$NEW_CWD/setup.py" || -f "$NEW_CWD/requirements.txt" ]]; then
context_hints="${context_hints:+$context_hints, }python"
elif [[ -f "$NEW_CWD/go.mod" ]]; then
context_hints="${context_hints:+$context_hints, }go"
elif [[ -f "$NEW_CWD/Cargo.toml" ]]; then
context_hints="${context_hints:+$context_hints, }rust"
fi
# Detect if it has Claude config
if [[ -d "$NEW_CWD/.claude" ]]; then
context_hints="${context_hints:+$context_hints, }claude-configured"
fi
# Output context hint if we detected anything useful
if [[ -n "$context_hints" ]]; then
echo "[octopus] Directory changed to: $NEW_CWD (detected: $context_hints)"
fi
exit 0
All 51 scripts are listed above. The source is inlined for 6 of them, starting with whatever hooks.json actually runs. See all of them in the repo.
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.
Every AI model has blind spots. Claude Octopus supports twelve external provider integrations — Codex, Antigravity CLI, Copilot, Qwen, Ollama, Perplexity, OpenRouter, OrcaRouter, OpenCode, Cursor CLI, Grok, and Kimi Code — alongside the built-in Claude Code
Expert Claude Code skills for building flawless n8n workflows using the n8n-mcp MCP server.
A research assistant plugin for Claude Code that supports literature review, paper writing, citation verification, Zotero and Obsidian integration, and code review and debugging for academic and software work.
Orchestrates multiple Claude Code agents across terminals and machines, giving them persistent memory and agent-to-agent messaging so you no longer have to relay messages between them by hand.
An autonomous pipeline that turns a text description into a playable Godot game, generating design docs, game assets such as backgrounds, characters, props, cards and effects, and running visual checks and playtests.
A personal AI assistant with voice, screen and meeting support that learns your patterns and can update its own code. It runs across several Macs and can talk with other people's assistants.
Helps hardware teams turn product requirements into a reviewable, buildable PCB design plan. Covers embedded architecture, MCU or SoC selection, power tree, interfaces, sensors, connectivity, and BOM risk.
MCP server for reusable prompt templates, multi-step workflow chains, and quality gates. Compose agentic workflows with an operator syntax; export as native skills to Claude Code, Cursor, OpenCode, and Gemini CLI.
A Claude Code plugin for crypto trading with skills to run multi-agent market analysis, track a portfolio and open trades, close trades with post-mortem review, and monitor stop-loss and take-profit levels on a schedule.