Nightshift
Verification gates
The single most important idea in Nightshift: a role's work is never accepted because the agent said it finished. A real command has to agree.
Last updated: July 25, 2026
Quick answer
A gate is a shell command attached to a role that must pass before its work counts as done. For code that is usually the project's test or lint command. For an article it might be a word count and a check for leftover placeholder text. If a gate fails, the failure and its output are fed back to the agent for a bounded repair attempt, and the work does not land until a command agrees.
- Gates are ordinary shell commands with no special environment
- A role with no gate is accepted on the agent's word alone
- A gate that always passes is worse than none, because it looks like proof
- Failed gates feed their real output back into a bounded repair
- Gates run inside the role's isolated checkout when isolation is on
On this page
Why gates exist
The most common complaint about autonomous agent platforms is that they mark work complete when it is not. An agent reports success, the task moves to done, and nobody notices until a customer does. Gates are the answer: the work is only accepted if something independent of the agent confirms it.
The agent is told about its gates
The gate commands are included in the role's prompt, along with an instruction not to weaken, skip or disable a check to make it pass. In practice the agent runs them itself and fixes problems before finishing, which is cheaper than a repair round.
Gates for code
gates:- run: npm test- run: npm run lint- run: npx tsc --noEmit
Prefer the project's real commands. They are stronger evidence than anything generic, and they are already the standard the rest of your work is held to.
Gates for content and non-code work
A non-code role still needs a gate. The shape differs: instead of a test suite, prove that output exists, has substance, and is not full of placeholders.
# The file exists and is not empty- run: test -s .nightshift/content/post.md# It has real substance- run: test $(wc -w < .nightshift/content/post.md) -ge 400# Nothing was left half-written- run: '! grep -rniE "lorem ipsum|TBD|TODO" .nightshift/content'# Research was appended today, not just repeated- run: grep -rq "$(date +%Y-%m-%d)" .nightshift/research# A draft landed where the human will look for it- run: test -n "$(ls -A .nightshift/outbox)"
Gate options
A gate can be a bare string, or a mapping when you need more control.
gates:# Terse form- "npm test"# A gate that must FAIL for the work to be accepted, for example# "there must be no TODOs left"- run: "grep -rn TODO src/"expect_exit: 1# Exit zero is not enough; the output has to prove it- run: "curl -s localhost:3000/health"expect_stdout: "ok"# A slow gate with its own budget- run: "npm run e2e"timeout: 15m
- expect_exit sets the required exit code. Defaults to 0.
- expect_stdout requires that text to appear in the output.
- timeout bounds the gate. It inherits the role's timeout when unset.
- Gates run in order and stop at the first failure, so a later gate never wastes time after an earlier one fails.
- A timeout is always a failure: a gate that cannot finish proves nothing.
The repair loop
- 1
Gates run after the agent finishes
They execute in the role's working directory, which is its isolated checkout when isolation is on.
- 2
A failure is turned into feedback
The failing command, the reason it failed and the tail of its output are handed back to the agent in the same session.
- 3
The agent gets a bounded number of attempts
max_repair_attempts caps this, so a permanently broken gate cannot loop all night.
- 4
Gates re-run after each repair
If they pass, the cycle succeeds. If the attempts are exhausted, the cycle fails and the work does not land.
The tail is what matters
Compiler and test output puts the real failure at the end, so when the output is too long to include in full, Nightshift keeps the tail rather than the beginning.
Gates that do not work
# Always passes. Proves nothing, but looks like proof.trueecho donegit statusgit diff --stat # exits 0 whether or not anything changed# Better: prove something actually happenedtest -n "$(git status --porcelain)"
A vacuous gate is worse than no gate
With no gate you at least know the work is unverified. With a gate that cannot fail, you believe it was checked. Validation warns about roles with no gates; nothing can warn you about a gate that always passes except reading it.
Frequently asked questions
Does a role need a gate?
Not technically, but validation warns when a role that changes things has none, because its work is then accepted on the agent's word alone. Read-only roles are exempt since they produce nothing to verify beyond their report.
Can the agent cheat a gate by deleting the test?
It is explicitly instructed not to weaken, skip or disable a check to make it pass, and the policy layer reinforces that. In practice we have seen agents fix the real problem rather than delete the check. Gates are still a safety net, not a guarantee, which is why work lands on a branch you can review.
Where do gates run?
In the role's working directory. With isolation enabled that is the role's own git worktree, so a gate verifies the isolated copy rather than your main checkout.
Was this page helpful?
Related articles
Nightshift
The fleet file reference
Complete reference for nightshift.yaml: roles, cadences, modes, sandbox levels, limits and the policy layer.
Nightshift
Isolation, merging and secret scanning
How Nightshift runs roles in parallel using git worktrees, merges verified work through a queue, and refuses to commit secrets.
Nightshift
Troubleshooting Nightshift
Diagnose skipped roles, failing gates, exhausted turns, missing connectors and unmerged work in Nightshift.