Back to Blog

AI / Claude Code / Qwen Code / Automation / Productivity

Building Your AI Coding Behavior Layer: Skills, Hooks, and Auto-Loaded Rules

Stop re-typing rules into your AI agent each session. Make skills and behavior persist automatically in Claude Code and Qwen Code — set once, enforced always.

|11 min read

Introduction

Terminal AI coding agents are stateless by default. Open a fresh session and the agent has forgotten your coding standards, your commit style, your "output diffs, not raw files" rule. So you re-type them — every session, every time — or you skip them and accept the drift.

There is a better layer. Both Claude Code and Qwen Code let you encode two distinct things so they persist:

  • Skills — capabilities you invoke on demand (/review, /test, /commit).
  • Behavior — rules that auto-apply with no invocation (standards, output format, pre-commit gates).

People conflate the two and put them in the wrong place — a standard buried in a skill nobody invokes, or a one-shot generator wired as an always-on rule that bloats every prompt. This post separates them, maps each to the right home, and shows the exact syntax in both tools side by side.

💡 Tool versions move fast. The mechanisms below are stable, but verify exact field names and hook events against your installed version's docs before relying on them in CI.

Skills vs Behavior — The Conflation

One distinction drives every decision in this post:

Skill Behavior
Triggered by You (/name) or agent auto-match Always, or an event
Example "Generate tests for this file" "Never hardcode secrets"
Lives in Skill/command file Context file or hook
Cost when idle Zero (loaded on use) Context: every prompt. Hook: only on event

A skill is a verb you call. Behavior is an adjective on everything the agent does. If you find yourself typing the same instruction at the start of every session, that is behavior — it belongs in the always-on layer, not in your fingers.

The Surface Map

Both tools expose the same four surfaces with different file paths:

Surface Claude Code Qwen Code
Context file CLAUDE.md (@import) QWEN.md (@import)
Skill / command .claude/skills/<name>/SKILL.md .qwen/commands/<name>.md
Hooks .claude/settings.json .qwen/settings.json
Subagents .claude/agents/<name>.md .qwen/agents/<name>.md

Learn the concept once; the only thing that changes between tools is the path and a couple of field names.

Surface 1: Context File — Always-On Rules

The cheapest behavior layer. The context file auto-loads at session start, so its rules apply to every prompt without you doing anything. This is where coding standards, persona, and output discipline live.

Claude Code — CLAUDE.md:

1 # Engineering Standards
2
3 You are a senior production engineer. Prioritize correctness, observability,
4 and rollback safety over speed.
5
6 - Output unified diffs, never raw files.
7 - No hardcoded secrets. Validate all inputs.
8 - Server Components by default; add "use client" only for browser APIs.
9 - Conventional commits. Body explains _why_, not what.
10
11 See @docs/architecture.md for system boundaries.

Qwen Code — QWEN.md: identical content, same @path import syntax. Both tools load the file at startup and resolve imports up to a few hops deep.

The trap: imports load into context at launch — they do not save tokens. Keep the context file lean. Put standards and conventions here; push large procedures into skills (loaded only when invoked) or reference docs (loaded only when relevant).

💡 Anything you would otherwise paste into the first prompt of every session belongs here. That single move eliminates the most common form of repetitive prompting.

Surface 2: Skills / Commands — Invokable Capability

A skill packages a repeatable task behind a slash command. Both tools also let the agent invoke a skill autonomously when its description matches your request.

Claude Code — .claude/skills/review/SKILL.md:

1 ---
2 name: review
3 description: Review the current diff for bugs and convention violations
4 allowed-tools: Read, Bash, Grep
5 ---
6
7 ## Current diff
8
9 !`git diff HEAD`
10
11 Review the diff above. Report findings by severity (blocker / warning / nit),
12 each as one line: file:line problem fix. Flag hardcoded values, missing
13 error paths, and untested logic.

The !`git diff HEAD` line runs the command and injects its output before the model sees the prompt — the skill arrives pre-loaded with context. Use $ARGUMENTS to pass parameters: /review src/api.

Qwen Code — .qwen/commands/review.md:

1 ---
2 description: Review the current diff for bugs and convention violations
3 ---
4
5 Review the staged diff. Report findings by severity (blocker / warning / nit),
6 each as one line: file:line problem fix.
7
8 Target: {{args}}

Same idea, two syntactic differences: Qwen uses {{args}} for parameter injection where Claude uses $ARGUMENTS. (Qwen's older TOML command format is deprecated but still loads — migrate to Markdown.)

Skills are the right home for generators and one-shot quality passes: doc generation, test generation, scaffolding, commit messages, security reviews. They cost nothing when you are not using them.

Surface 3: Hooks — Deterministic Enforcement

Here is the surface most people skip, and it is the one that matters most. A rule in your context file is advisory — the agent usually follows it, but "usually" is not a guarantee. A hook is deterministic: it runs a real command on a real event, and the agent cannot talk its way around it.

Both tools configure hooks in settings.json with the same shape — an event name, a matcher, and a command to run. The event vocabulary is shared: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SessionEnd, and more.

Auto-lint every edited file — .claude/settings.json:

1 {
2 "hooks": {
3 "PostToolUse": [
4 {
5 "matcher": "Edit|Write",
6 "hooks": [{ "type": "command", "command": "yarn lint --fix $CLAUDE_FILE_PATHS" }]
7 }
8 ]
9 }
10 }

Every time the agent edits or writes a file, the linter runs. No reminder, no drift. The .qwen/settings.json structure is identical (matcher + hooks array of {type, command}).

Block direct commits, route through review — PreToolUse:

1 {
2 "hooks": {
3 "PreToolUse": [
4 {
5 "matcher": "Bash",
6 "hooks": [{ "type": "command", "command": "./scripts/block-git-commit.sh" }]
7 }
8 ]
9 }
10 }

The script inspects the command and exits non-zero (blocking) if it sees git commit or git push — forcing changes through human-reviewed patch application. A PreToolUse hook exiting with a blocking status stops the tool call before it runs.

Other high-value hook wiring:

  • SessionStart — inject a rules digest or a lazy-loaded doc index, so the agent starts every session already anchored.
  • UserPromptSubmit — append a standing reminder to each prompt, or rewrite commands through a token-saving proxy (the technique behind cutting AI coding agent token burn).
  • Pre-commit gatelint && test plus secret scanning before anything reaches history.

The principle: if a rule must hold, do not write it as prose. Wire it as a hook. Prose persuades; hooks enforce.

Surface 4: Subagents — Delegated, Isolated Work

A subagent is a separate context with its own instructions, tool allowlist, and model. Use one to delegate work that would either pollute your main context or benefit from a fresh, unbiased perspective.

Claude Code — .claude/agents/auditor.md:

1 ---
2 name: auditor
3 description: Independent production-readiness auditor. Use to review a plan or diff without bias.
4 tools: Read, Grep, Glob
5 model: opus
6 ---
7
8 You are an independent reliability and security auditor. Assess against
9 12-Factor, OWASP Top 10, and SRE fundamentals. Report gaps and concrete
10 recommendations. Do not modify files.

Qwen Code — .qwen/agents/auditor.md: same Markdown-plus-frontmatter format; field names align closely (name, description, model, tools, plus an approvalMode option). Invoke either by naming the agent in your prompt, or let the main agent delegate based on the description.

Two patterns earn their keep:

  • Fresh-context auditor — a second agent reviewing a plan without the confirmation bias of the session that wrote it.
  • Cheap-model delegation — route simple, high-volume work (searches, file reads, read-all summaries) to a small fast model, reserving the expensive model for reasoning.

💡 Model selection is itself a behavior. Pinning model: haiku (or your tool's small model) on a search-and-summarize subagent cuts cost on exactly the tasks that do not need a frontier model.

Use-Case Matrix: Where Each Job Lives

Doc generation and test generation are the obvious wins — and the least interesting. The leverage is in the enforce and delegate rows that most setups never build.

Use case Surface
Generate functional / technical docs Skill
Generate unit + integration tests Skill
Scaffold component / route / endpoint Skill
Plan / audit / tasks one-shots Skill
Commit message from diff Skill
Code review / security review Skill
Coding standards, persona, output format Context file
Tech-stack + compliance constraints Context file
Auto lint/format/test on edit Hook (PostToolUse)
Block commit/push, validate first Hook (PreToolUse)
Session-start rule/index load Hook (SessionStart)
Pre-commit lint + test + secret scan Hook (pre-commit)
Fresh-context audit Subagent
Cheap-model search / summarize Subagent

Organize by where the behavior lives, not by what the AI produces. The same task can legitimately sit on two surfaces: doc generation as a skill (on demand) or as a Stop/post-task hook (automatic after each change). Choose based on whether you want it available or guaranteed.

Worked Example: One Rule, Three Surfaces

Take a single rule — "new code ships with tests." It can live on three surfaces, each with a different strength:

  1. Context file (advisory). Add to CLAUDE.md / QWEN.md: "Every behavior change includes tests in the same diff." Cheap, always present, but the agent can still forget under pressure.

  2. Skill (on demand). A /test command that generates a matching test file for a target. Reliable when you remember to call it.

  3. Hook (guaranteed). A pre-commit hook that runs coverage and rejects the commit if new files lack tests. Cannot be skipped.

Mature setups use all three: the context file states the intent, the skill makes compliance easy, the hook makes non-compliance impossible. Advisory at the top, enforced at the bottom.

What to Put Where

A four-line decision rule:

  • Always-on, applies to everything → context file.
  • Invokable on demand → skill / command.
  • Must hold, no exceptions → hook.
  • Isolated or needs a fresh perspective → subagent.

When a rule matters enough that "the agent usually does this" is not good enough, it graduates from the context file to a hook. That graduation is the whole game.

Conclusion

Your behavior layer is portable. The four concepts — context file, skill, hook, subagent — are identical across Claude Code and Qwen Code; only the paths and a couple of field names differ. Configure them once per tool and the payoff compounds: no more re-typing standards, no more silent drift, and the rules that actually matter enforced by commands rather than hope.

This is the enforcement half of a larger practice. The production-ready AI coding workflow covers the planning, audit, and review discipline that this behavior layer then locks into place automatically. Both sit inside a broader stance on how a senior engineer works with these tools: AI as agile assistance, not autopilot.

Skills make the right thing easy. Hooks make the wrong thing impossible. Build both, and your agent stops being a stateless code generator and starts behaving like a disciplined member of the team — every session, without being reminded. If you're wiring this into a real team's stack and want a second opinion, get in touch.

Written by Erik Yuntantyo·Software Engineer·About me