AI helps me move faster, but only after I stopped relying on prompts alone.
The key realization: skills, hooks, and markdown files are all “agent control surfaces,” but they are not equivalent. They operate at different layers and with different enforcement strength.
One Mental Model: Instruction Layers
Think of AI delivery as layered controls:
- Policy layer: markdown docs (
AGENTS.md,docs/ai/*.md) define intent and constraints. - Workflow layer: skills define reusable procedures (for example, how to run NX generators correctly).
- Enforcement layer: hooks and CI decide what is allowed to pass.
If you only have the first two layers, the AI can still drift. The third layer is what makes rules real.
Are Skills, Hooks, and Markdown “The Same”?
They are the same in one sense: all three steer agent behavior. But they differ in responsibility.
| Mechanism | Primary role | When it runs | Hard or soft control |
|---|---|---|---|
Markdown rules (AGENTS.md, docs/ai/*.md) | Define standards and architecture constraints | Before/while generation | Mostly soft |
Skills (SKILL.md + references/scripts) | Encode repeatable implementation workflows | During generation and edits | Soft-to-medium |
| Agent completion hooks | Auto-run checks and auto-fix before handoff | When agent marks task complete | Medium |
Git hooks (pre-commit, pre-push) | Fast local validation and feedback | On commit/push | Medium (can be bypassed) |
| CI required checks | Merge gate and final policy enforcement | On PR/merge | Hard |
This distinction matters. Git hooks can be skipped with --no-verify, so hooks alone are not a reliable control plane. CI required status checks are the actual enforcement boundary.
Architecture Diagram
flowchart LR
A["Task request"] --> B["AI reads AGENTS.md + rule docs"]
B --> C["AI executes skill workflow"]
C --> D["Agent completion hook runs lint/test/typecheck"]
D --> E["Agent auto-fixes failures and re-runs checks"]
E --> F["Local hooks run fast checks"]
F --> G["CI runs required checks"]
G --> H["Merge only if all gates pass"]
1) Put Architecture Rules in Markdown (Policy Layer)
Start by writing short, testable rules in markdown.
Recommended files:
AGENTS.mdfor global agent behaviordocs/ai/architecture-rules.mddocs/ai/coding-standards.mddocs/ai/testing-policy.mddocs/ai/pr-checklist.md
Write constraints so they can be mechanically verified. Good examples:
- “No
anyin app code except in approved adapter boundaries.” - “All
type:featurelibs must include unit tests for one happy path and one failure path.” - “Cross-scope imports are disallowed unless explicitly listed.”
2) Encode NX Knowledge as a Skill (Workflow Layer)
Instead of manually running generation steps every time, create an NX skill that the AI must follow.
The skill should include:
- approved generators and when to use each,
- required flags (
--directory,--tags,--standalone, etc.), - naming and tagging conventions,
- post-generation checks (
lint,test, exports, boundaries).
Example layout:
skills/
nx-workflow/
SKILL.md
references/
generator-examples.md
tagging-rules.md
Minimal SKILL.md shape:
# NX Workflow Skill
When creating Angular libraries:
1. Use `nx g @nx/angular:library` with required tags.
2. Enforce workspace naming and directory conventions.
3. Validate module boundaries before creating imports.
4. Run `nx lint <project>` and `nx test <project>`.
5. If checks fail, fix code before proposing final output.
3) Keep Hooks Fast and Focused (Enforcement Layer, Local)
Use hooks for quick feedback, not full verification.
pre-commit should usually run:
- format on staged files,
- lightweight lint/type checks,
- narrow unit tests when cheap.
pre-push should usually run:
nx affected -t lint,test,typecheckfor broader confidence.
Hooks improve developer speed, but they are not security boundaries.
3.5) Add Agent Completion Hooks (Auto-Verify + Auto-Fix)
There is another useful hook layer: hooks that run when the AI agent thinks it is done.
In practice, this means the agent can:
- run
lint,test, and optionaltypecheckautomatically before presenting results, - inspect failures and apply fixes on its own,
- rerun checks until green (or until a retry limit is reached),
- return a summary of what it changed and which checks passed.
This removes a lot of “please run tests and fix errors” back-and-forth. The user gets a cleaner first handoff, and the AI behaves more like an engineer closing a task instead of just generating code.
4) Make CI the Non-Negotiable Gate (Enforcement Layer, Remote)
CI is where your rules become enforceable policy:
- protected branches require passing status checks,
- lint, test, and typecheck must pass before merge,
- AI-generated code and human code follow identical gates.
If a rule cannot fail CI, it is a suggestion, not a standard.
Delivery Pipeline Diagram
sequenceDiagram
participant Dev as Developer
participant AI as AI Agent
participant Rules as Rules and Skills
participant AgentHook as Agent Completion Hook
participant Hooks as Git Hooks
participant CI as CI Required Checks
Dev->>AI: Implement feature request
AI->>Rules: Load markdown rules + skill workflow
AI->>AgentHook: Mark task done and trigger checks
AgentHook->>AgentHook: Run lint/test/typecheck
AgentHook-->>AI: Return failures
AI->>AI: Apply fixes and rerun until green
AgentHook-->>AI: Checks pass
AI->>Dev: Propose code changes with passing checks
Dev->>Hooks: Commit and push
Hooks-->>Dev: Fast local pass/fail signal
Dev->>CI: Open or update PR
CI-->>Dev: Enforce lint/test/typecheck gates
CI-->>Dev: Merge only on green checks
Practical File Layout
AGENTS.md
docs/
ai/
architecture-rules.md
coding-standards.md
testing-policy.md
pr-checklist.md
skills/
nx-workflow/
SKILL.md
references/
generator-examples.md
tagging-rules.md
agent-hooks/
on-task-complete.sh
.husky/
pre-commit
pre-push
.github/workflows/
ci.yml
Bottom Line
Prompting matters, but system design matters more.
The strongest setup is:
- write clear markdown policy,
- encode repeatable workflows as skills,
- enforce compliance with hooks,
- require CI checks for merge.
That is how AI becomes predictable in a real engineering environment.