Skip to content

Four-eyes change

Two sequential, independent approvals, asked once the agent review loop has passed and the pull request is green on CI — the two-person rule that change-management processes ask for. Requesting changes — with a required note — sends the change back for a fix and CI, then both people sign off again; a rejection stops the run.

Template four-eyes
Works on A git repository, cloned into an isolated Docker sandbox
Where a person acts First sign-off — author / team-lead review — a person approves or rejects, waiting up to 24h
Second sign-off — independent reviewer — a person approves or rejects, waiting up to 24h
Waits on systems CI result, up to 4h

Drawn from the template spec at build time. Bookkeeping nodes that only record status are left out; amber nodes are where a person acts.

flowchart TD
  n_validate["Validate"]
  n_implement["Implement"]
  n_review["Review"]
  n_checkApproval{"Check approval?"}
  n_openPR["Open PR"]
  n_checkReviewLimit{"Check review limit?"}
  n_waitForCI[/"Wait for CI<br/><small>waits up to 4h: CI result</small>"/]
  n_lessonReviewFailed["Lesson review failed"]
  n_reviewFix["Review fix"]
  n_checkCI{"Check CI?"}
  n_terminateCITimedOut(["Timed out<br/><small>ci timed out</small>"])
  n_terminateReviewFailed(["Failed<br/><small>review failed</small>"])
  n_firstSignoff>"First sign-off — author / team-lead review<br/><small>person: approval</small>"]
  n_checkCILimit{"Check CI limit?"}
  n_secondSignoff>"Second sign-off — independent reviewer<br/><small>person: approval</small>"]
  n_terminateRejected(["Failed<br/><small>rejected</small>"])
  n_checkSignoffLimit{"Check signoff limit?"}
  n_terminateTimedOut(["Timed out"])
  n_lessonCIFailed["Lesson CI failed"]
  n_fetchLogs["Fetch logs"]
  n_done(["Done"])
  n_signoffFix["Signoff fix"]
  n_terminateCIFailed(["Failed<br/><small>ci failed</small>"])
  n_ciFix["CI fix"]
  n_checkSignoffFixChanged{"Check signoff fix changed?"}
  n_checkCiFixChanged{"Check CI fix changed?"}
  n_repushAfterFix["Repush after fix"]
  n_validate --> n_implement
  n_implement --> n_review
  n_review --> n_checkApproval
  n_checkApproval -->|"yes"| n_openPR
  n_checkApproval -->|"no"| n_checkReviewLimit
  n_openPR --> n_waitForCI
  n_checkReviewLimit -->|"yes"| n_lessonReviewFailed
  n_checkReviewLimit -->|"no"| n_reviewFix
  n_waitForCI -->|"received"| n_checkCI
  n_waitForCI -->|"timed out"| n_terminateCITimedOut
  n_lessonReviewFailed --> n_terminateReviewFailed
  n_reviewFix --> n_review
  n_checkCI -->|"yes"| n_firstSignoff
  n_checkCI -->|"no"| n_checkCILimit
  n_firstSignoff -->|"approved"| n_secondSignoff
  n_firstSignoff -->|"rejected"| n_terminateRejected
  n_firstSignoff --> n_checkSignoffLimit
  n_firstSignoff -->|"timed out"| n_terminateTimedOut
  n_checkCILimit -->|"yes"| n_lessonCIFailed
  n_checkCILimit -->|"no"| n_fetchLogs
  n_secondSignoff -->|"approved"| n_done
  n_secondSignoff -->|"rejected"| n_terminateRejected
  n_secondSignoff --> n_checkSignoffLimit
  n_secondSignoff -->|"timed out"| n_terminateTimedOut
  n_checkSignoffLimit -->|"yes"| n_terminateRejected
  n_checkSignoffLimit -->|"no"| n_signoffFix
  n_lessonCIFailed --> n_terminateCIFailed
  n_fetchLogs --> n_ciFix
  n_signoffFix --> n_checkSignoffFixChanged
  n_ciFix --> n_checkCiFixChanged
  n_checkSignoffFixChanged -->|"yes"| n_firstSignoff
  n_checkSignoffFixChanged -->|"no"| n_repushAfterFix
  n_checkCiFixChanged -->|"yes"| n_checkCILimit
  n_checkCiFixChanged -->|"no"| n_repushAfterFix
  n_repushAfterFix --> n_waitForCI
  class n_firstSignoff,n_secondSignoff gate
  class n_waitForCI wait

Ships as a built-in template and reuses the engineering steps the flagship flow runs. This particular arrangement of them is not separately exercised end to end against a real repository. See product overview §8.

Every built-in template is seeded into the workflow library and can be cloned, edited on the visual canvas, and versioned — see architecture for the node types. The spec lives in packages/shared/src/workflow/templates/fourEyes.ts.

© 2026 Jorge Barnaby

Source-available under FSL-1.1-MIT

Source on GitHub

Built with Astro and Starlight