Reading: Part 17. Qwen Code Hooks: Workflow Automation

Lesson 1 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.

Part 17. Qwen Code Hooks: Workflow Automation

Qwen Code hooks are scripts that run at predefined moments in a session: at startup, after a user request, before using a tool, after using a tool, on tool error, or before completing a response.

In SDD, hooks are not meant to replace specifications. They are meant to make the process less dependent on human memory: remind the agent about rules, record important events, stop dangerous commands, add short context, or collect traces for subsequent verification.

Basic schema:

flowchart TD
  A["Qwen Code Event"] --> B["Matcher Filter"]
  B --> C["Hook<br/>command or http"]
  C --> D{"Can continue?"}
  D -- "yes" --> E["Qwen Code continues working"]
  D -- "no" --> F["Qwen Code shows reason for stopping"]
  C --> G["Additional Context"]
  G --> E

When hooks are appropriate

A hook is appropriate if an action should happen regularly and consistently:

  • record the fact of tool usage;
  • add a short SDD reminder after /clear;
  • check a potentially dangerous command before execution;
  • save a tool error for retrospective analysis;
  • send an event to an internal log;
  • add a link to the current specification to the context;
  • run a lightweight background check after a file change.

A hook is not needed if a rule is sufficient to write in QWEN.md. For example, "read specifications first" is better left as a behavior rule. But "every Bash execution with a dangerous command must be stopped" is already suitable for a hook.

Events most commonly needed

For the learning process, it is enough to understand a few events.

EventWhen it triggersTypical meaning in SDD
SessionStartat startup or session resumptionadd a short project reminder
UserPromptSubmitafter a user requestcheck the request and add relevant context
PreToolUsebefore using a toolstop a dangerous action
PostToolUseafter successful tool userecord the fact, run a lightweight background check
PostToolUseFailureafter a tool errorsave the error for analysis
Stopbefore the agent completes its responserecord session summary or remind about verification

| PreCompact | before context compression | save important conclusions before details are lost |

Do not connect everything at once. Start with one or two events, otherwise the process will become opaque.

Hook types

Qwen Code supports several executor types.

command runs a local command. This is the main option for project hooks: a Python script, shell script, or small utility.

http sends an event to an HTTP address. This is convenient for centralized logging or an internal audit system, but requires careful setup of secrets and allowed addresses.

function is intended for internal JavaScript functions at the session level. For a typical project, command or http is almost always sufficient.

What a hook receives

A command hook receives JSON via standard input. It contains common fields: session identifier, current directory, event name, event time. For tool events, the tool name, tool input, result or error are added.

A hook can return JSON via standard output. Most often it does one of three things:

  • changes nothing and simply exits;
  • adds additionalContext so that Qwen Code sees a short message in the next step;
  • prohibits an action before tool use and explains the reason.

The exit code is also important. 0 means the hook worked successfully. 2 is used for a blocking error. Other codes are considered non-blocking errors: the main Qwen Code flow continues, and details are visible in debugging.

Minimum file set

Examples have been moved from the lesson into separate files:

Configuration in the learning project:

mkdir -p .qwen/hooks
cp sdd-qwen-code-ru/examples/hooks/pre_tool_guard.py .qwen/hooks/pre_tool_guard.py

cp sdd-qwen-code-ru/examples/hooks/log_tool_result.py .qwen/hooks/log_tool_result.py
cp sdd-qwen-code-ru/examples/hooks/inject_sdd_context.py .qwen/hooks/inject_sdd_context.py
chmod +x .qwen/hooks/*.py

Copy the settings example separately and merge it with the existing .qwen/settings.json manually:

cp sdd-qwen-code-ru/examples/hooks/settings-workflow.example.json .qwen/settings-hooks.example.json

Do not overwrite working settings for the model, authentication, and MCP servers.

Protective hook before a tool

PreToolUse is suitable for actions that must be checked before execution. The most obvious example is shell commands.

The file examples/hooks/pre_tool_guard.py checks Bash input against several dangerous patterns: deleting root or home directory, git reset --hard, git clean -fd, running a downloaded script via shell. This is not a full sandbox. It is the last check before an obviously risky action.

Important: a protective hook must explain the reason for stopping. If the agent sees only "command forbidden," it will start guessing workarounds. If it sees a specific reason, it can suggest a safe alternative.

Tool logging

PostToolUse and PostToolUseFailure are suitable for event logging. In SDD, such a log is useful not by itself, but as a source for retrospective analysis:

  • which commands often failed;
  • which files the agent changed before an error;
  • which checks were run manually;
  • which actions should be moved to validation.md;
  • which rules should be recorded in QWEN.md.

The file examples/hooks/log_tool_result.py writes compact records to .qwen/hooks/logs/tool-events.jsonl. This is a local technical log. Do not store secrets there, large model responses, or full environment dumps.

For logging, asynchronous mode is usually enabled so that the main workflow does not wait for the log write.

Adding SDD context

SessionStart and UserPromptSubmit are suitable for short context additions. This is especially useful after /clear: the chat history is cleared, but the project process should remain visible.

The file examples/hooks/inject_sdd_context.py does not read the entire project. It checks for the presence of QWEN.md, specs/mission.md, specs/tech-stack.md, and specs/roadmap.md, then adds a short reminder. Such a hook should not turn into a hidden specification. It only directs the agent to the files where the source of truth lives.

Hooks and checks

There is a temptation to run npm test after every file change. Usually this is a bad idea: the agent will become slow, and errors will arrive at inappropriate moments. It is better to separate checks:

  • lightweight checks can be run automatically and asynchronously;
  • heavy checks are run by an explicit step from validation.md;
  • blocking hooks are used only for dangerous actions;
  • results of automatic checks should go into a report or log, not get lost in noise.

If a hook runs a check, it should answer one question. For example: "did the fast type check fail after a TypeScript file change?" Do not turn one hook into a full branch merge process.

Security rules

Hooks run in your environment with your privileges. Therefore, treat them like ordinary automation code.

Minimum rules:

  • store project hooks in the repository and review them as code;
  • set timeout so that a stuck hook does not block the session;
  • use asynchronous mode for logs and background checks;
  • do not pass secrets via command line;
  • for HTTP hooks, set a list of allowed environment variables;
  • do not send sources and prompts to external services without explicit team decision;
  • do not write hooks that silently change project files;
  • add a clear message when blocking an action.

Project hooks should be enabled only in a trusted directory. If you opened someone else's repository, first read .qwen/settings.json and .qwen/hooks/, and only then allow automatic execution.

What not to automate

Bad ideas:

  • automatically fix code after every tool error;
  • block any commands not in a precompiled list;
  • add large specification fragments to the context on every request;
  • record full model responses in a permanent log;
  • mix memory, checking, formatting, and security in one script;
  • use hooks as a hidden replacement for requirements.md, plan.md, and validation.md.

A hook should be small and understandable. If you cannot explain its purpose in one phrase, it is most likely doing too much.

Practical exercise

  1. Copy the hook examples into your learning project.
  2. Connect pre_tool_guard.py only to PreToolUse for Bash.
  3. Connect log_tool_result.py to PostToolUse and PostToolUseFailure.
  4. Connect inject_sdd_context.py to SessionStart and UserPromptSubmit.
  5. Launch Qwen Code in the project and execute /clear.
  6. Ask the agent to read the roadmap and suggest the next feature without changing files.
  7. Verify that the log appeared in .qwen/hooks/logs/tool-events.jsonl.
  8. Try a dangerous command in a safe test form and make sure the protective hook explains the block.

After the exercise, answer in writing:

  • which hook actually helped the process;
  • which hook turned out to be noisy;
  • what is better to move to QWEN.md;
  • what is better to leave as a manual step in validation.md.

Connection to following parts

In the next part, hooks are considered from a security perspective: they can protect the process, but they themselves require review. After that, in the part about SQLite memory, the same mechanism is used for collecting events, background summarization, and adding short memory to new sessions.

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