Loops, tampering and bloat
In any mode, three detectors run on every tool result. When one fires on new evidence, the agent gets one line that says what was detected and names the choices. The agent, not the hook, explains it to you and asks. Orstrum prefers a missed detection to a false one.
Loop
Either heuristic fires:
- Failing edits. Edits to one file, each followed by a failing test, build or run ("edit, fail, edit, fail, edit, fail"). Fires at
loop.failing_edits, default 3. A pass resets the streak. - Recurring error. The same normalized error from failing tool results,
loop.repeated_errorstimes (default 3) with at least one edit in between.
Orstrum: loop (3 failing edits on format.js). Stop editing and ask the user now:
roll back to the last working checkpoint, or hand off and restart? On Free the choices are "undo edits since tests last passed, or start fresh". When nothing has passed yet (an impossible spec, say) the line says so and offers rethinking the approach instead of a rollback. The nudge is sent once per loop.
The hard block
If the agent edits the looping file again after a nudge without you saying anything in between,
the next edit to that file is blocked and the agent is told to stop and ask. Your next
message releases it. This exists for headless and autonomous runs, where nobody is there to
answer the nudge; interactively, models tend to obey the nudge and the block never fires.
Turn it off with loop.block_ignored: false.
Piped checks don't count
npm test | tail exits with tail's status, so it says nothing about the tests.
A check feeding a pipe is neither a pass nor a fail: it neither resets a loop nor marks a
checkpoint working, and a handoff that claims "tests pass" on the strength of it gets tagged.
Test tampering
A failing check, then edits to test files only, then the same kind of check passes: the agent made the test pass by changing the test, not the code. The pass is still checkpointed but not marked working, so a rollback never restores it as known-good, and the agent gets:
Orstrum: format.test.js was changed, not the code, and now passes.
Stop and ask the user whether changing the test was intended before going on.
It stays quiet when source files were edited in the same span (ordinary work: fix the code, fix
the test). Test files are recognized by path: test/, __tests__/, spec/, *.test.*, *.spec.*, *_test.go, test_*.py, *Test.java and the like. Turn it off with tampering.enabled: false.
Bloat
Compaction about to run is the hard signal. Context at or over bloat.context_tokens
(default 400k) or cumulative tool output over bloat.tool_output_kb (default 1 MB) is the soft one.
The agent is told to finish the current step and offer a handoff and a fresh session.
Subagents
Events from subagents are logged and counted in the session's cost, but excluded from loop detection and checkpoint decisions. A subagent that loops is the main agent's problem to notice.