Driver.run checks each turn with nisse_core.loop.circles and ends the run as "circling" when the same calls get much the same back, one harness correction is given again and again, or the model apologises, for circle_repeats turns in a row (default 3). Near-identical calls (git add a.py, b.py) and scattered apologies stay flags on the status page. A fact in the transcript says why the run ended. nisse-dev calls in a helper as for a stuck run, then asks the operator; nisse-review counts a failed run and posts none of its drafts. Tuning: tuning.driver / tuning.review circle_repeats (0 off) and circle_similar. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
nisse-review
The Review Agent (Part R of the architecture): it reviews every pull request that is ready, in the repositories its Gitea account can read, and posts its review on the PR as a COMMENT review. It reads and comments; it never changes code, approves, or requests changes.
A thin application over nisse-core, with its own small scheduler:
config: its YAML configuration (nisse-review.example.yaml).state: its state store, and a review item (one per PR).scheduler: the duty (ready PRs), one review at a time, recovery after a crash.clones: each repository as a git clone kept between runs (the latest one), checked out at the PR's head and, when read, its base.reader: those trees, read-only, as the run's executor.review: one review run, and posting it.build,main: putting it together, and the access check at startup.
Bring-up on the development VM: scripts/review-bringup.sh.