#!/usr/bin/env bash # PreToolUse hook: inside a T3 Code thread, subagents go through delegate_task, so T3 can # show them, track them, and wake the parent. Blocks the native Agent and Workflow tools and # shelling out to another agent CLI. Does nothing outside T3 Code. # # The escape is for when Gib asks for a native route by name: start the Agent or Workflow # description with "native:", or prefix the command with T3_NATIVE_OK=1. # # web-fetch stays allowed because it stands in for a WebFetch tool, not a worker. set -euo pipefail [[ -n "${T3CODE_THREAD_ID:-}" ]] || exit 0 input="$(cat)" tool="$(jq -r '.tool_name' <<<"$input")" deny() { jq -n --arg reason "$1" '{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: $reason}}' exit 0 } advice="This is a T3 Code thread, so use the delegate_task tool (load it with ToolSearch: select:mcp__t3-code__delegate_task). This overrides T3's note that native subagents are fine for the same provider. If you are a delegated child, do the work yourself." case "$tool" in Agent | Task | Workflow) [[ "$(jq -r '.tool_input.subagent_type // ""' <<<"$input")" == "web-fetch" ]] && exit 0 [[ "$(jq -r '.tool_input.description // ""' <<<"$input")" == native:* ]] && exit 0 deny "$tool is blocked. $advice Only if Gib asked for a native agent by name: start the description with \"native:\"." ;; Bash) # Only a command position counts, so grep patterns and prose that mention these pass. if jq -r '.tool_input.command // ""' <<<"$input" | grep -qE '(^|[;&|(]|\$\()[[:space:]]*(timeout[[:space:]]+[^[:space:]]+[[:space:]]+)?(claude|clauded|claudedr|klaude|codex|opencode2?)[[:space:]]+([^;&|]*[[:space:]])?(-p|--print|exec|run)([[:space:]]|$)'; then deny "Starting an agent CLI from the shell is blocked. $advice Only if Gib asked for this by name: prefix the command with T3_NATIVE_OK=1." fi ;; esac