Why We Built Sentinel Enforcement into Agent Development Tools
The Problem Was Not a Lack of Rules
By the time the Sentinel pattern emerged inside Agent Development Tools, the system already had rules, skills, hooks, and enforcement intent.
The missing layer was not policy. It was memory.
A lot of hook-based governance systems assume that each lifecycle event can make a correct decision in isolation. In practice that breaks down quickly in agentic environments.
A PreToolUse hook often needs to know something that happened earlier in the session:
- was the right skill already activated?
- did the last test run fail?
- did the user explicitly ask for a certain discipline?
- did another agent just touch this file?
- did this subagent actually run, or was that only mentioned in the prompt?
Without some durable session evidence, every enforcement attempt starts guessing.
Sentinel was not introduced to make ADT stricter for its own sake. It was introduced because lifecycle hooks are stateless, while agent governance often depends on something that happened one or two events earlier.
Why LLM-Only Enforcement Was Not Enough
One of the clearest examples in the repo history is the move away from an LLM-based skill gate.
A PreToolUse prompt hook using Haiku tried to determine whether a required write-* skill had been activated before someone edited ADT rules, hooks, or skills.
That sounded elegant.
In practice it was brittle.
The commit that replaced it says the quiet part out loud: the model hook had no reliable visibility into the session's actual activation state. It could read the current event, but it could not deterministically know whether the skill tool had fired earlier in the same session.
That is the key conception point for Sentinel. The system needed an enforcement primitive that was:
- cheap
- deterministic
- session-scoped
- visible to ordinary shell hooks
- and independent of whether an LLM could reconstruct context correctly
What Sentinel Actually Is
In ADT, Sentinel is a small file-based state layer written into /tmp/ and read back by later hooks.
The canonical pattern is:
/tmp/.adt-{type}-{session_id}[-{discriminator}]That sounds simple because it is simple. That is part of why it works.
| Sentinel type | Example shape | Written by | Read by | Purpose |
|---|---|---|---|---|
| Skill active | .adt-skill-active-write-hooks-{session_id} | skill-activation-sentinel.sh | require-skill-for-adt.sh | Block ADT edits unless the right skill was actually activated |
| Debug required | .adt-debug-required-{session_id} | detect-test-failure.sh | require-debug-skill.sh | Stop blind editing after a failing test or typecheck run |
| Prompt intent | .adt-intent-{session_id}-{skill} | prompt-intent-sentinel.sh | intent-skill-check.sh | Compare what the user asked for with what actually got activated |
| Agent run | .adt-agent-{session_id}-{type} | agent-run-sentinel.sh | intent-skill-check.sh | Accept completed agent execution as evidence |
| File lock | .adt-filelock-{file_hash} | file-lock-write.sh | file-lock-check.sh | Warn about parallel edits to the same file |
This is not a database. It is not a workflow engine. It is a deliberately tiny state-bridge between otherwise stateless hook invocations.
Why a File-Based Technique Made Sense
I think the design makes sense for five practical reasons.
It records the smallest useful fact
Each sentinel stores a binary or near-binary fact: this skill was activated, this test run failed, this file was recently touched, this intent was declared. That keeps the mechanism simple enough to trust.
It works across lifecycle boundaries
PostToolUse hooks can write state that PreToolUse, TaskCompleted, or Stop hooks can read later. That is exactly the gap ordinary hook systems struggle with.
It stays cheap in the hot path
Checking whether a file exists in /tmp/ is fast. ADT's own enforcement docs explicitly say heavy enforcement should sit at natural boundaries, while hot-path checks stay cheap.
It isolates sessions cleanly
Most sentinels include session_id, which means parallel sessions and subagents do not interfere with one another by accident. That matters a lot in orchestrated agent workflows.
It remains inspectable
When enforcement behaves unexpectedly, the mechanism is debuggable with ordinary shell tools. You can inspect the sentinel, check whether it exists, see when it was written, and reason about why the next hook made the decision it did.
The Need Behind It
The deeper need was not just technical convenience. It was enforcement reliability.
ADT is trying to turn rules like these into real behaviour:
- use the right skill before editing governance files
- do root-cause work before blindly patching after a failed test run
- distinguish between a user mentioning a skill and an agent actually activating it
- keep parallel work visible without freezing the whole system
Those are all examples of a broader pattern:
a later decision depends on verified evidence from an earlier event
That is the category Sentinel serves.
The Evolution of the Technique
The git history shows a fairly clear progression.
| Stage | What changed | Why it mattered |
|---|---|---|
63f01f4 | ADT added a 4-layer skill activation reliability system | This established that skill activation was not just guidance. It was a reliability problem that needed multiple enforcement layers. |
2183c88 | ADT added real-time test-failure enforcement using a debug-required sentinel | This was the first strong expression of the pattern: a later edit gate depended on earlier test evidence. |
bc911ae | The Haiku skill gate was replaced with deterministic skill sentinels | This appears to be the clearest conception moment for Sentinel as a named enforcement technique. The system moved from inference to evidence. |
4ed5029 | Sentinel usage expanded across prompt intent, stale-read tracking, file locks, and agent-run evidence | Sentinel stopped being a single fix and became a general enforcement architecture for cross-event state. |
331b173 | Skill sentinels expanded beyond write-* skills and intent-vs-activation checks were added | The technique matured from simple gating to governance auditing. It could now compare what was requested with what actually happened. |
287ce53 | Several legacy hooks and sentinels were retired or reduced | This was the correction phase: keep sentinel where the signal is strong, remove it where latency and false positives outweigh value. |
That last stage matters as much as the first ones. A lot of systems know how to add enforcement. Fewer know how to narrow it back down after observing real operational cost.
The Intent Was Never Maximal Blocking
One of the strongest ideas in docs/enforcement-system.md is that hard blocks should be reserved for unambiguous violations with near-zero false positives.
That principle explains why some Sentinel use cases stayed and others did not.
The good fits are easy to see:
- if
write-hookswas not activated, blocking edits to ADT hooks is reasonable - if a test failure sentinel exists, forcing explicit debugging discipline is reasonable
- if another session touched the same file, surfacing an advisory is reasonable
But other uses created more drag than value. The stale-read system is the clearest example. It was added to detect edits made against outdated reads, then later removed when the repo concluded that Claude 4.6 self-corrected well enough and the enforcement added false positives and hot-path latency.
That tells you something important about the real intent. Sentinel was not meant to become ideology. It was meant to become calibrated infrastructure.
What Sentinel Is Really For
My current read is that Sentinel exists to do four things well:
- turn session history into cheap, testable evidence
- let deterministic shell hooks enforce rules that would otherwise require memory
- support multi-agent workflows without requiring a central service
- keep enforcement inspectable enough that it can be audited and tuned back when necessary
That is a narrower claim than saying Sentinel is the future of agent governance. I do not think it is.
I think it is a very good answer to a more specific question:
how do you give stateless lifecycle hooks just enough memory to enforce the right thing one step later?
For that problem, Sentinel is a strong technique.
My Current View
I think the most interesting part of the ADT Sentinel story is not that it introduced more enforcement. It is that it made enforcement more evidence-based.
The shift was basically this:
- from model inference about what probably happened
- to deterministic proof that something did happen
That is a big difference in an agentic system.
Once agents are doing many steps across multiple hooks, fuzzy enforcement becomes expensive. A hook that guesses wrong either blocks legitimate work or lets weak discipline slip through.
Sentinel reduces that ambiguity by carrying small pieces of verified state forward. Then the later hook makes a narrower, more defensible decision.
That is why I think the technique matters.
Not because writing tiny files in /tmp/ is clever, but because it is a practical way to give governance systems memory without making them heavy.
Related Reading
- Why We Had to Build a Constitution for AI Coders explains the broader governance problem that Sentinel sits inside.
- Why Agent-Native Teams Need Better Tests, Not More Tests covers the evidence problem from the verification side.
- Agent-Native Shift-Left CI for High-Velocity Solo Engineering shows how local gates and enforcement evolved around high-velocity agent workflows.
- AI Collapsed Implementation Cost. It Did Not Collapse Judgment places the same pattern inside the larger move from implementation scarcity to judgment scarcity.
Conclusion
Sentinel enforcement in Agent Development Tools did not emerge because hooks were fashionable or because stricter governance sounded impressive.
It emerged because stateless hooks kept running into decisions that required memory.
The technique gave ADT a lightweight memory layer. That made some gates deterministic, made some advisories evidence-based, and made the broader enforcement system easier to reason about.
Just as importantly, the repo history shows that the technique was later pruned where it was no longer earning its keep.
I think that is the real lesson.
Good agent governance is not just about adding more rules. It is about finding the smallest amount of durable state that lets the next decision become trustworthy.