Study guide: Part 17. Qwen Code Hooks: Workflow Automation

Lesson 2 of 5 in module «Part 17. Qwen Code Hooks: Workflow Automation»
You are viewing the lesson without signing in. Sign in to save progress and take tests.

Topic: Part 17. Qwen Code Hooks: Workflow Automation

Difficulty level: Medium

Estimated study time: 4-6 hours (theory: 1.5 hours, practice: 2.5-4.5 hours)

Prerequisites: Basic understanding of Qwen Code architecture and session management

Knowledge of JSON format and ability to edit configuration files

Python programming skills (scripting level)

Understanding of SDD (Specification-Driven Development) concept from previous course parts

Experience with command line and basic shell commands

Familiarity with QWEN.md, specs/mission.md, specs/tech-stack.md, specs/roadmap.md files

Learning objectives: Configure and connect a minimal set of hooks (PreToolUse, PostToolUse, SessionStart, UserPromptSubmit) in a study project according to course examples

Distinguish situations where a hook is appropriate from cases where a rule should simply be written in QWEN.md or validation.md

Implement a guard hook that blocks dangerous commands with a clear explanation of the stop reason

Organize tool event logging in JSONL format with asynchronous operation mode

Apply security rules when working with hooks: code review, timeouts, secret isolation, trusted directory verification

Overview: Qwen Code hooks are a workflow automation mechanism that allows running scripts at key session moments: at startup, after a user request, before and after tool use, on error, or before completing a response. In the SDD context, hooks do not replace specifications but make the process less dependent on human memory: they remind of rules, record events, block dangerous actions, add short context, and collect traces for retrospectives. Key principle: a hook must be small, understandable, and solve one task. If its purpose cannot be explained in one phrase — it does too much. The course covers three main hook types (command, http, function), six key events, example connection practice, and critically important security rules.

Key concepts: Event: A trigger that activates a hook. Key events: SessionStart (session start), UserPromptSubmit (after user request), PreToolUse (before tool use), PostToolUse (after successful use), PostToolUseFailure (after tool error), Stop (before completing response), PreCompact (before context compression). Each event has its own semantics in the SDD process.

Matcher filter: A component that determines whether a hook should fire for a specific event. Allows precise hook configuration: for example, PreToolUse only for the Bash tool, not for all tools.

Hook executor (command/http/function): The type of script being launched. Command — local command (Python script, shell script), the main option for projects. HTTP — sending to an external address for centralized logging. Function — internal JS session function, rarely needed in regular projects.

Hook input json: Data passed to the hook via stdin: session identifier, current directory, event name, time, for tools — tool name, input data, result or error.

Hook output json: The hook's work result via stdout. Three key variants: empty response (changes nothing), additionalContext (adds a short message to context), action block with reason explanation.

Hook exit code: 0 — successful operation, 2 — blocking error (stops action), other codes — non-blocking error (visible in debug, but process continues).

Asynchronous mode: A mode where the hook does not block the main Qwen Code workflow. Critically important for logging and background checks so the session does not wait for a side task to complete.

Guard hook (pretooluse guard): A hook that blocks dangerous actions before they are executed. Examples of dangerous patterns: rm -rf / or ~, git reset --hard, git clean -fd, running downloaded scripts via sh. Does not replace a sandbox but serves as a final check.

Tool logging (posttooluse/posttoolusefailure): Recording tool usage facts for subsequent retrospectives: crash frequency, changed files, manual checks, candidates for moving to validation.md or QWEN.md.

SDD context injection: Adding a short project reminder via SessionStart and UserPromptSubmit, especially after /clear. The hook checks for key files (QWEN.md, specs/mission.md, etc.) and directs the agent to the source of truth without duplicating their content.

Hook timeout: Maximum hook execution time, preventing session blockage by a hung script.

Hook security rules: Hooks execute with user privileges in their environment. Requirements: hook code review, timeouts, asynchronous mode for background tasks, secret isolation, explicit allowed variable list for HTTP, prohibition of silent file modification, clear messages on blockage, trusted directory verification before autostart.

Practice exercises: Name: Installation and basic hook connection

Problem: Copy hook examples from the course repository to the study project, set execution permissions, and connect settings-hooks.example.json without overwriting existing model, authorization, and MCP server settings.

Solution: 1. Create directory: mkdir -p .qwen/hooks

  1. Copy three hooks: cp sdd-qwen-code-ru/examples/hooks/pre_tool_guard.py .qwen/hooks/; cp sdd-qwen-code-ru/examples/hooks/log_tool_result.py .qwen/hooks/; cp sdd-qwen-code-ru/examples/hooks/inject_sdd_context.py .qwen/hooks/
  2. Set execution permissions: chmod +x .qwen/hooks/*.py
  3. Copy example settings separately: cp sdd-qwen-code-ru/examples/hooks/settings-workflow.example.json .qwen/settings-hooks.example.json
  4. Manually merge settings-hooks.example.json contents with existing .qwen/settings.json, preserving model, auth, mcp sections
  5. Verify JSON validity: python -m json.tool .qwen/settings.json

Complexity: beginner

Name: Guard hook configuration for Bash

Problem: Connect pre_tool_guard.py only to the PreToolUse event for the Bash tool. Test on a safe test command containing a dangerous pattern (for example, git reset --hard in a test repository). Ensure the hook explains the blockage reason, not just prohibits.

Solution: 1. In .qwen/settings.json add to the hooks section an entry with matcher: {"event": "PreToolUse", "tool": "Bash"}, executor: {"type": "command", "command": ".qwen/hooks/pre_tool_guard.py"}

  1. Create a test git repository: mkdir /tmp/test-guard && cd /tmp/test-guard && git init && echo 'test' > file.txt && git add . && git commit -m 'init'
  2. In Qwen Code try to execute via Bash: git reset --hard HEAD~
  3. Verify that the hook returned code 2, Qwen Code showed the stop reason with explanation of the specific dangerous pattern
  4. Try a safe alternative: git log --oneline -5 and verify it passes
  5. Verify that other tools (Read, Edit) are not affected by the hook

Complexity: intermediate

Name: Logging with asynchronous mode

Problem: Connect log_tool_result.py to PostToolUse and PostToolUseFailure events. Configure asynchronous mode so logging does not slow down the session. Perform several tool operations and analyze the resulting log.

Solution: 1. Add two hooks in settings.json with the same executor but different events: PostToolUse and PostToolUseFailure, command: .qwen/hooks/log_tool_result.py

  1. Set "async": true for both hooks
  2. Launch Qwen Code, execute /clear, ask the agent to read roadmap and suggest the next feature
  3. Check log creation: ls -la .qwen/hooks/logs/tool-events.jsonl
  4. Analyze entries: jq . .qwen/hooks/logs/tool-events.jsonl | head -20
  5. Ensure entries are compact: contain event_type, tool_name, timestamp, success/failure, but not full environment dumps or secrets
  6. Verify that on tool error (for example, reading non-existent file) the entry differs from a successful one

Complexity: intermediate

Name: Context injection after /clear

Problem: Connect inject_sdd_context.py to SessionStart and UserPromptSubmit. Verify that after the /clear command the agent receives a short reminder about key project files, but not full specification texts.

Solution: 1. Add hooks in settings.json for SessionStart and UserPromptSubmit with command .qwen/hooks/inject_sdd_context.py

  1. Ensure the project has at least QWEN.md and specs/mission.md
  2. Launch session, execute /clear
  3. In the next request ask: "What specifications are in the project?"
  4. Verify that the agent mentions file existence but does not quote their content fully
  5. Check hook logs or additionalContext output in Qwen Code debug mode
  6. Ensure that when specs/roadmap.md is absent the hook handles the situation correctly, does not crash and does not add unnecessary information

Complexity: intermediate

Name: Hook analysis and refactoring after practice

Problem: After completing exercises 1-4, answer four questions in writing: which hook actually helped the process; which one was noisy; what is better moved to QWEN.md; what is better left as a manual step in validation.md. Based on answers, adjust the configuration.

Solution: 1. Keep notes during exercises: record moments when a hook fired usefully and when it created interference

  1. Example of useful firing: pre_tool_guard prevented git reset --hard — keep
  2. Example of noise: inject_sdd_context fires on every UserPromptSubmit and duplicates information from QWEN.md — consider moving the rule "read QWEN.md first" to QWEN.md itself, leaving the hook only for SessionStart
  3. Example for QWEN.md: "After /clear pay attention to specs/roadmap.md" — this is a behavior rule not requiring automation
  4. Example for validation.md: "Run npm test before commit" — heavy check unsuitable for a hook
  5. Adjust settings.json, remove or modify hooks based on analysis, document the decision in the commit comment

Complexity: advanced

Case studies: Name: Protecting production databases from accidental deletion

Scenario: A team of five developers uses Qwen Code for working with a microservice architecture on Node.js. The project contains Docker containers with production-like data for local testing. A developer accidentally asked the agent to execute docker volume prune during debugging, which would have led to deleted volumes with test data, recovery of which took 2-3 hours.

Challenge: Rules in QWEN.md did not prevent dangerous commands in the moment: a developer in flow state might not notice the warning. Manual verification of each Bash command by the agent was unreliable. An automatic but explainable obstacle to destructive operations was needed without slowing normal work.

Solution: The team implemented a guard hook pre_tool_guard.py, extending its patterns: added docker volume prune, docker system prune -a, rm in directories with .env files, any commands with DROP DATABASE. The hook is configured only for PreToolUse + Bash. When blocking, the hook returns JSON with explanation: "The docker volume prune command will delete all unused Docker volumes, including volumes with project X test data. For safe cleanup use docker volume rm with a specific volume name or confirm via validation.md step 'Manual Docker resources cleanup'." The developer sees the reason and can choose a safe path.

Result: Over three months the hook blocked 12 potentially destructive commands. In 10 cases developers chose a safe alternative. In 2 cases they consciously went through validation.md. Test data recovery time dropped from 2-3 hours to zero. The hook became part of the onboarding checklist for new developers.

Lessons learned: Blockage without explanation provokes circumvention attempts; specific reason directs to a safe solution

A hook must be narrowly specialized: Docker command protection does not interfere with normal git and file work

Hook integration with validation.md creates a link between automatic and manual verification without breaking the process

Related concepts: Guard hook (PreToolUse guard)

Hook exit code

Hook output JSON with reason explanation

Connection of hooks with validation.md

Name: Hook excess and return to simplicity

Scenario: A team of three enthusiasts implemented hooks in all available events: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure, Stop, PreCompact. Each hook performed 3-4 tasks: logging, verification, context addition, formatting. Qwen Code sessions began taking 2.5 times longer, the agent started ignoring part of the context due to overload, developers stopped understanding where a particular system reaction came from.

Challenge: Classic automation trap: hooks stopped being transparent tools and became hidden logic. The team could not explain session behavior in one phrase. Debugging required tracing 7 hooks, many of which conflicted: one added context, another modified it, a third logged an already modified version.

Solution: The team conducted an audit by the "one phrase — one hook" principle. For each hook they asked: "What does it do in one phrase?" Hooks failing the check were split or removed. Final configuration: SessionStart + inject_sdd_context (remind about project after /clear), PreToolUse + pre_tool_guard only for Bash (stop dangerous), PostToolUseFailure + log_tool_result async (save error for retrospective). Everything else was moved to QWEN.md or validation.md.

Result: Session time returned to original. Transparency was restored: any developer could explain behavior in 30 seconds. The error log became clean and useful for weekly retrospectives. The "no more than three hooks per project" rule entered team guidelines.

Lessons learned: A hook must solve one task and be explainable in one phrase; otherwise it becomes technical debt

Start with one-two hooks, not connect everything at once — otherwise the process is opaque

Logging, verification, formatting, and security should not mix in one script

Related concepts: "One phrase — one hook" rule

Asynchronous mode

What not to automate

Connection of hooks with QWEN.md and validation.md

Study tips: Start practice strictly with one hook — preferably PreToolUse guard, as its benefit is visible and risks are clear. Add others only after thoughtful analysis of the first.

Keep a "hook diary" during practice: record each firing, reaction time, whether there was benefit or noise. This will facilitate the final refactoring exercise.

Use jq or python -m json.tool for reading the tool-events.jsonl log — JSONL format is specifically chosen for line-by-line processing, do not try to read it as a regular JSON array.

Create a test "sandbox" for verifying the guard hook: a separate git repository, Docker volumes with unneeded data, temporary files. Never test rm -rf / blockage on a real system.

Compare hook behavior in synchronous and asynchronous mode: run log_tool_result.py first without async, measure delay between tools, then enable async and compare. This visualizes the critical difference.

For visual learning type draw the course scheme on paper (event → matcher → hook → decision → continue/stop/context) and mark which paths your configured hooks take.

For auditory type: speak aloud the purpose of each hook in one phrase before adding it to settings.json. If the phrase becomes long or with conjunctions "and", split the hook.

Regularly re-read the "What not to automate" section — it is a self-check checklist before each new hook.

Practice manual settings.json merging: this skill will be useful for course updates and when working with third-party repositories where hooks may be a hidden threat.

Discuss with colleagues or in the study group: which commands in your stack are considered "dangerous"? The list differs for Python (pip install unknown package), Node.js (npm audit fix --force), Go (go get with module substitution), DevOps (kubectl delete, terraform destroy).

Additional resources: Course examples repository (sdd-qwen-code-ru/examples/hooks/): Source files pre_tool_guard.py, log_tool_result.py, inject_sdd_context.py, settings-workflow.example.json and README.md — basis of all practical exercises

Official qwen code documentation on hooks: Extended description of events, executor types, JSON formats (check version relevance)

Jq — json command processor: https://jqlang.github.io/jq/ — tool for analyzing JSONL logs in terminal

Python json.tool: Built-in module for JSON validation and formatting: python -m json.tool file.json

Article "the twelve-factor app" (config section): Principles of configuration and secrets storage, applicable to HTTP hook setup and environment variables

Owasp cheat sheet: injection prevention: Recommendations for preventing injections, relevant for hook input processing and secure command construction

Previous course parts (qwen.md, specs/, validation.md): SDD context necessary for proper separation of hooks and specifications

Summary: Qwen Code hooks are a powerful but discipline-requiring tool for SDD process automation. Their purpose is to reduce dependence on human memory, not replace specifications. Key principles: start with 1-2 hooks, each hook solves one task and is explainable in one phrase, guard hooks explain blockage reason, logging works asynchronously, checks are separated by weight (light — automatically, heavy — via validation.md). Hook security is critical: they execute with user privileges, require review, timeouts, secret isolation, and caution with third-party repositories. After mastering hooks the student is ready to study hook security and SQLite memory in subsequent course parts.

My notes
0 / 10000

Notes are saved in this browser. They will not appear on another device.

Course menu

Course

Specification-Driven Development with Qwen Code CLI
Progress 0 / 135