CI Monitor Lifecycle in no-mistakes: Idle Timeout, Re-arming, and Termination

The CI monitor in no-mistakes watches pull requests with a configurable idle timeout that automatically re-arms whenever the base branch advances, terminating only when the PR merges, closes, or the timeout finally expires.

The no-mistakes repository implements a sophisticated CI monitor that manages the lifecycle of automated runs against open pull requests. Understanding how this component handles idle timeouts and re-arming logic is essential for configuring reliable CI pipelines that don't prematurely abort during long-running reviews or rebase operations.

Initialization and Timeout Configuration

The CI monitor lifecycle begins with configuration parsing in internal/config/config.go. The system reads the ci_timeout value from the merged configuration via Config.CITimeout. If this value is absent, the monitor falls back to config.DefaultCITimeout, which is hardcoded to 7 days.

The parseCITimeout function in internal/config/config.go (lines 78-95) implements the idle timeout semantics. It recognizes several keywords and non-positive durations as CITimeoutUnlimited:

  • Negative values
  • The strings "unlimited", "none", "off", or "never"
  • Any non-positive duration

When any of these are specified, the monitor enters an infinite waiting mode and never self-terminates due to idle time. Positive durations are interpreted as idle timeouts measured from a specific anchor point.

The Polling Loop and Base Branch Detection

Once initialized, the monitor enters its polling phase in CIStep.Execute within internal/pipeline/steps/ci.go (lines 70-78). This function implements the main monitoring loop that repeatedly queries the CI provider for the pull request's check status.

The monitor uses a baseBranchTip resolver to track the upstream default branch. During each iteration, it compares the current base branch SHA against previous values to detect advancement. The idle timeout is always measured from a timeoutAnchor variable rather than a fixed start time, which enables the re-arming behavior.

Re-arming Mechanics: Resetting the Timer on Base Branch Changes

The re-arming logic represents a critical aspect of the CI monitor lifecycle. When baseBranchTip reports a new SHA indicating the base branch has moved, the monitor executes the re-arming sequence at lines 94-99 of internal/pipeline/steps/ci.go.

Specifically, the code resets timeoutAnchor to the current time (now()). This operation shifts the measurement reference point without modifying the timeout duration itself. Consequently, a pull request that is actively rebased against an advancing default branch retains its monitoring session indefinitely, preventing premature timeout during legitimate development workflows.

The timeout duration itself remains constant; only the anchor point moves forward in time.

Auto-Fix Attempts and Termination Conditions

During each poll cycle, the monitor may attempt to automatically resolve failing checks. The CIStep struct tracks these attempts through the ciFixAttempts field, with the total allowed attempts governed by Config.AutoFix.CI as defined in config.go.

The CI monitor terminates when any of the following conditions occur:

  1. PR Merged: The run is marked as merged and monitoring stops immediately via CIStep.ReconcileApprovalGate
  2. PR Closed: The run is marked as closed and the monitor exits
  3. Idle Timeout Elapsed: The system executes no-mistakes axi abort --run <id> to abort the run

These termination checks are implemented in CIStep.ReconcileApprovalGate and the timeout validation logic within CIStep.Execute.

Configuration Examples

Configure the CI timeout globally in ~/.no-mistakes/config.yaml:


# ~/.no-mistakes/config.yaml

ci_timeout: "48h"   # monitor for up to 48 hours of inactivity

Repository-level overrides can be specified in .no-mistakes.yaml for per-project timeouts.

Start a monitored run manually:


# Start a run that will monitor CI for PR #42

no-mistakes axi run --pr 42

During operation, the monitor indicates re-arming events in the output:

base branch advanced, re-arming CI timeout

Summary

  • The CI monitor defaults to a 7-day idle timeout configurable via ci_timeout in internal/config/config.go.
  • Special keywords including "unlimited", "none", "off", and "never" disable the idle timeout entirely via CITimeoutUnlimited.
  • The monitor re-arms by resetting timeoutAnchor to the current time whenever baseBranchTip detects a new base branch SHA at lines 94-99 of internal/pipeline/steps/ci.go.
  • Auto-fix attempts are limited by Config.AutoFix.CI and tracked in the ciFixAttempts field.
  • Termination occurs only upon PR merge, PR closure, or idle timeout expiration, handled in CIStep.Execute and ReconcileApprovalGate.

Frequently Asked Questions

What happens when the CI timeout is set to "unlimited"?

When the ci_timeout configuration contains "unlimited", "none", "off", "never", or any negative duration, the parseCITimeout function in internal/config/config.go returns CITimeoutUnlimited. In this mode, the CI monitor never self-terminates due to idle time and will continue polling indefinitely until the pull request merges or closes.

How does rebasing affect the CI monitor timer?

Rebasing triggers the re-arming mechanism in internal/pipeline/steps/ci.go. When the baseBranchTip resolver detects that the default branch has advanced to a new SHA, the code resets the timeoutAnchor variable to the current time at lines 94-99. This effectively extends the monitoring window by moving the idle timeout measurement reference point forward, ensuring actively maintained pull requests do not expire.

Where is the idle timeout duration defined in the source code?

The default idle timeout is defined as DefaultCITimeout (7 days) in internal/config/config.go. The active timeout for a specific run is retrieved from Config.CITimeout, with parsing logic handled by the parseCITimeout function in the same file. The effective timeout is applied in CIStep.Execute within internal/pipeline/steps/ci.go.

What triggers the CI monitor to stop watching a pull request?

According to the implementation in internal/pipeline/steps/ci.go, the monitor terminates when three specific conditions occur: the pull request merges (marking the run as merged), the pull request closes (marking the run as closed), or the idle timeout expires relative to the last timeoutAnchor (triggering an abort command). These checks execute within CIStep.Execute and ReconcileApprovalGate.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →