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 gate —
lint && testplus 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:
-
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. -
Skill (on demand). A
/testcommand that generates a matching test file for a target. Reliable when you remember to call it. -
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