Skip to content

English | Русский

Hooks ​

TAUSIK uses Claude Code hooks for automatic quality control. Hooks intercept agent actions before and after execution — they are gates, not instructions. 23 Python hooks + 1 shell pre-commit ship with TAUSIK — 24 gates in total (v1.4 introduced secret_scan.py, posttool_usage.py, tool_output_truncation_nudge.py, and task_cost_budget_check.py; 1.8 added scope_write_gate.py and bash_write_gate.py; 1.9 added read_ledger_gate.py, off by default).

What Are Hooks ​

Hooks are scripts that run automatically with every agent action. They decide whether an action can be performed (PreToolUse), what to do afterward (PostToolUse), or what to record on session/agent boundaries (SessionStart, Stop, UserPromptSubmit). Shared helpers live in scripts/hooks/_common.py (not a hook itself); the regex set in scripts/hooks/memory_markers.py is a library imported by memory_posttool_audit.py and the brain-scrubbing pipeline.

PreToolUse — Gates That Run Before an Action ​

HookWhenWhat It Does
task_gate.pyBefore every write tool — Write/Edit/MultiEdit/NotebookEdit and the MCP editors listed in hooks/write_tools.py (serena, windows-mcp; PR #5)Blocks file changes if no active task (SENAR Rule 9.1)
scope_write_gate.pyBefore every write tool — Write/Edit/MultiEdit/NotebookEdit and the MCP editors listed in hooks/write_tools.py (serena, windows-mcp; PR #5)Scope ACL (SENAR Rule 2, Walko pattern): blocks a write outside the union of the active tasks' declared scope_paths. This is the verdict source bash_write_gate reuses for shell writes. Conservative adoption: any active task without scope_paths → allow (legacy, undeclared = unrestricted); target outside the project root → allow; pre-v30 DB or any DB error → REFUSE unless TAUSIK_HOOK_FAIL_OPEN=1 (the default flipped in 1.9).
memory_pretool_block.pyBefore every write tool — Write/Edit/MultiEdit/NotebookEdit and the MCP editors listed in hooks/write_tools.py (serena, windows-mcp; PR #5) and every shell tool (Bash, PowerShell, mcp__windows-mcp__PowerShell)Layer 2 of memory-route enforcement: blocks a write into any foreign memory sink from scripts/memory_sinks.py (~/.claude/**/memory/, .cursor/rules/, .github/copilot-instructions.md, .aider*, …) and redirects to memory add. The shell tools are on the matcher because a heredoc — or a Set-Content — writes what the Write path refuses. Bypass: confirm: cross-project in the prompt, or gates.memory_route.allow in config.
secret_scan.py (v1.4)Before every write tool — Write/Edit/MultiEdit/NotebookEdit and the MCP editors listed in hooks/write_tools.py (serena, windows-mcp; PR #5) and every shell tool (Bash, PowerShell, mcp__windows-mcp__PowerShell)Scans tool_input for likely secrets (AWS/GitHub/Slack/Stripe/OpenAI/Anthropic tokens, JWT, private-key blocks, generic password/api_key literals). Warns by default; set TAUSIK_SECRET_SCAN_STRICT=1 to block. (SENAR Rule 10.12). The shell tools are on the matcher: a heredoc or a Set-Content -Value 'AKIA…' carries the same secret.
bash_firewall.pyBefore Bash and PowerShellBlocks dangerous commands (rm -rf /, Remove-Item -Recurse C:\, DROP TABLE, Format-Volume, force push, etc.). The dialect is chosen by tool_name: the POSIX lexer cannot read PowerShell, where \ is an ordinary path character rather than an escape.
bash_write_gate.pyBefore Bash and PowerShellApplies the same QG-0 (Rule 1) and scope-ACL (Rule 2) verdict to a shell write that the Write tool gets — by importing scope_write_gate's decisions, not copying them. Parses redirections, tee/dd/sed -i/cp/mv, and Set-Content/Add-Content/Out-File/New-Item/Tee-Object.
git_push_gate.pyBefore Bash and PowerShellBlocks unless .tausik/.push_ticket.json is fresh, single-use, and bound to HEAD SHA. /ship and /commit run tausik push-ok && git push after your "y" — push-ok writes the 60-second ticket; the hook consumes it on the next push. The narrowing if clause is gone: it was a second copy of a decision the hook makes itself, and it named only one shell.

PostToolUse — Reactions After an Action ​

HookWhenWhat It Does
auto_format.pyAfter every write tool (MultiEdit was off this hook before PR #5)Auto-formats with ruff/prettier/gofmt + logs "Modified: X" to task
memory_posttool_audit.pyAfter every write tool into auto-memoryAudits cross-project leakage (uses memory_markers.py regex library) and warns
task_done_verify.pyAfter mcp__tausik-project__tausik_task_done, or a tausik task done run in the shellAudits AC evidence via 5 rule-based checks (Ralph-mode-lite).
task_call_counter.pyAfter any tool callIncrements per-task call_actual counter; warns at 1.5×budget
posttool_usage.py (v1.4)After any tool callRecords token-usage events to usage_events for per-task cost rollup
activity_event.pyAfter any tool callRecords activity timestamps for gap-based active-time session metric (SENAR Rule 9.2)
tool_output_truncation_nudge.py (v1.4)After Read/Grep/Glob and every shell tool (Bash, PowerShell, mcp__windows-mcp__PowerShell)Coaches the agent to narrow scope when tool output exceeds the configured line threshold (warn-only)
rag_grep_context.py (1.10)After GrepSearches the RAG index for the identifiers of the Grep pattern and adds the top 3 chunks (path:lines) as context. Read-only; nothing when the index is absent or has no hit.
task_cost_budget_check.py (v1.4)After any tool callCompares the active task's cost_actual / tokens_actual against budget; emits WARN at 1.5× and BLOCKER at 2× (throttled)

SessionStart ​

HookWhenWhat It Does
session_start.pyOn session startAuto-injects status + Memory Block + rebuilds skill profiles — no manual /start needed

UserPromptSubmit ​

HookWhenWhat It Does
user_prompt_submit.pyOn user promptDetects coding-intent (EN+RU) → nudges if no active task; scores the answer just read and, over answer_budget_words or without a verdict first, adds one line with the numbers. The code-discovery nudge toward search_code was removed in 1.10 (decision #390: 0 search_code calls with it in a paired replay). Ignores slash-command bodies and hook-generated text

Stop ​

HookWhenWhat It Does
keyword_detector.pyOn agent stopCatches "I'll implement"/"сейчас напишу" drift phrases → blocks stop
session_cleanup_check.pyOn agent stopWarns about open exploration / review tasks / session timeout

SessionEnd ​

HookWhenWhat It Does
session_metrics.pyOn session endRecords session metrics (active vs wall, throughput) to DB

The session on every host (1.10) ​

The TAUSIK session is the host session: the host opens and closes it, not an agent's ritual. Measured on the host binary, not its documentation, session #266.

HostOpenCloseProvided byMeasured
claudehookhookSessionStart / SessionEnd from the shared hook declarationClaude Code hook protocol
qwenhookhookSessionStart / SessionEnd from the shared hook declarationbootstrap profile
codexhookhookSessionStart / SessionEnd from the shared hook declarationcodex 0.153.4: the hook event list carries SessionStart and SessionEnd
opencodepluginpluginsession.created / session.deleted in the tausik-qg0.js pluginopencode 1.1.42: plugin events in the binary
kilocliclitausik session start / session end by handthe profile has no session events
cursorcliclitausik session start / session end by handthe profile carries no hooks

Where it says cli, what closing by a hook does is lost: recording the transcript's metrics and the generated handoff at exit. session end by hand does both.

Git pre-commit ​

HookWhenWhat It Does
pre-commit (shell)Before git commitRuns python -m mypy against scripts/ (uses pyproject.toml config). On exit ≠ 0 — blocks the commit. Optionally runs an incremental codebase-rag reindex (warn-only, capped at 5s); never blocks the commit because of RAG.

This is not "scoped quality gates" — those run via tausik verify (heavy stack: pytest/tsc/cargo/phpstan/…) and are decoupled from git commit since the v1.4 Verify-First Contract.

Install (one-time) ​

bash
# Option A: copy the file
cp scripts/hooks/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit

# Option B (recommended): point git at the in-repo hooks dir so updates are picked up automatically
git config core.hooksPath scripts/hooks

Windows caveat. pre-commit is a Bash script with timeout(1) and POSIX [ -f … ]. Plain cmd.exe will fail to execute it. Use Git Bash, WSL, or a terminal that ships Bash + timeout on PATH. If your team runs Windows-only, replace the script with a pre-commit.cmd wrapper that calls python -m mypy directly and accepts the same exit contract.

Disable / bypass ​

  • One-off: git commit --no-verify (skips core.hooksPath entirely).
  • Temporarily: git config --unset core.hooksPath.
  • For CI without mypy: keep core.hooksPath unset on CI runners; the heavy verification runs via tausik verify regardless.

How It Works ​

You: "add a button to the homepage"

Agent wants to edit index.html
  → task_gate.py checks: is there an active task? No → BLOCKED
  → Agent creates a task via /plan, starts
  → task_gate.py checks again: task exists → ALLOWED

Agent edits index.html
  → auto_format.py: formats with prettier
  → auto_format.py: logs "Modified: index.html" to the task
  → task_call_counter.py: bumps call_actual; warns at 1.5×budget
  → activity_event.py: stamps activity timestamp (active-time)

Agent: tausik task done my-button --ac-verified
  → task_done_verify.py: 5-check AC audit

Exit Codes ​

CodeMeaningBehavior
0SuccessAction allowed
1WarningAction allowed; warning logged
2BlockAction cancelled; agent receives the reason

What bash_firewall Blocks ​

  • rm -rf / and rm -rf . — filesystem deletion
  • DROP TABLE, DROP DATABASE, TRUNCATE TABLE — data deletion
  • git reset --hard — loss of local changes
  • git push --force — overwriting remote history
  • git clean -fd — deleting untracked files
  • dd if=/dev/zero, mkfs. — disk formatting
  • Fork bombs

Disabling Hooks ​

For testing or debugging: set TAUSIK_SKIP_HOOKS=1.

In .claude/settings.json hooks are generated automatically during bootstrap. To disable a specific hook, remove it from the hooks section. To re-generate the file, run python .tausik-lib/bootstrap/bootstrap.py --refresh.

What's Next ​