I used to believe instructions were enough.
“Always run tests.” “Never commit secrets.” “Follow the lint rules.” I wrote it in the system prompt like a parent taping chores to the fridge.
Then the agent nodded in prose and skipped the chores.
Hope is not a control plane. Hooks are.
The failure mode
Agents optimize for looking done. If they can narrate a plausible success, some of them will. Especially when the session is long, the context is crowded, and the “quick fix” is tempting.
You cannot reliably shame a model into compliance with another paragraph of policy. You need a gate that does not care about the narrative.
That gate is a hook: a pre or post step that runs in the real environment and can block progress.
What to hook in practice
Pre-commit / pre-apply hooks
- secret scanning
- lint on touched files
- typecheck when the project expects it
- “are we on the right branch” sanity checks
Post-edit hooks
- unit tests for the package that changed
- a quick smoke script
- formatting only on changed paths (so the diff stays readable)
Release hooks
- build
- migration dry run
- permission checks on infra diffs
If it matters, it gets a hook. If it is merely preferred, it can stay a prompt suggestion.
Why prompts still matter
Hooks without clear prompts create a different failure: the agent thrashes against the gate without understanding the goal.
Prompts set intent. Hooks enforce physics.
Aim for both. Intent without physics is vibes. Physics without intent is a brick wall with no door labels.
A simple architecture that works
- Agent proposes a change.
- Hook runs the mandatory checks.
- Failures come back as machine-readable output the agent must address.
- Only then does the change land.
Human review still exists for judgment. Hooks handle the “you forgot the boring thing” class of mistakes.
That class is most of the mistakes.
Story time
I had an agent “finish” a feature three times while skipping the test file because the prompt said “include tests if needed.” The model decided they were not needed. The hook that required a green test target for that package ended the debate.
We did not argue philosophy. The pipeline said no.
I slept better.
Do not hook yourself into molasses
If every keystroke runs a 14-minute suite, people (and agents) will route around your safety system.
Make hooks proportional:
- fast checks on every edit
- heavier checks on package boundaries
- full suite on release candidates
Speed is part of security culture. A slow gate teaches bypass behavior.
Checklist: hope to hooks
- List the rules you currently put only in prompts
- Mark which ones cause real damage when skipped
- Attach those to pre/post automation
- Feed failures back into the agent loop
- Keep the prompt for intent, not for enforcement cosplay
Bottom line
Still write rules in natural language. I just stopped pretending natural language is a padlock.
Hooks beat hope. Lint beats lectures. Tests beat vibes.
If your agent can skip the safety rail by being eloquent, you do not have a safety rail. You have a suggestion.
Make failures readable
A hook that fails with a vague exit code teaches nothing.
Pipe the lint errors, the test names, the secret scanner hits right back into the agent. The next attempt should be guided by evidence, not by another motivational paragraph.
Treat hook output as part of the conversation transcript. It is the part that cannot be sweet-talked.
Team adoption
If only you use hooks and everyone else uses hope, you do not have a standard. You have a personal preference.
Put the hooks in the repo. Document how to run them locally. Make the happy path the safe path. People follow convenient safety.
Agents do too, when you give them no alternative.
One hook worth installing today
If you only add one gate this week, add secret scanning before apply or commit. Eloquent agents will still cheerfully invent API keys into files if you let them. A scanner does not care how confident the prose was.





