Your issues become pull requests overnight.

Give thirdshift a GitHub issue URL. It runs the coding agents you already use to implement the issue, review the change and deliver a pull request ready for review, or merge it when asked. You are the day shift: talk the idea through, write the spec and cut it into tickets. Agents work the third shift, unattended. Start a Ticket run whenever you like, or let your operating system start passes on a schedule. thirdshift is free and open source.

How thirdshift works: an engineer's guide from issue to pull request, through Worktrees, agent review and Delivery. Architecture draws what runs where and who does each step. Documentation covers installation, commands and configuration. Videos explain it in a few minutes.

Built on Matt Pocock's skills: aihero.dev/skills · mattpocock/skills. Read every prompt and skill thirdshift sends.

Install

curl -fsSL https://thirdshift.app/install.sh | sh
Show the full commandcurl -LsSf https://github.com/JacobStephens2/thirdshift/releases/latest/download/thirdshift-installer.sh | sh

Then run thirdshift setup to choose your defaults. Keep the binary current with thirdshift update.

Two shifts

You plan by day. Agents work at night.

Day shift

Humans, with Matt Pocock's skills, used interactively

  1. /grill-with-docs
  2. /to-spec
  3. /to-tickets

The human half of the workflow: shaping work into issues the factory can take on, by grilling the idea with /grill-with-docs, writing the spec with /to-spec and cutting it into tickets with /to-tickets, and reviewing the pull requests it delivers, except those a Ticket run Self-merges when you ask.

Third shift

Agents, with headless copies of the same skills

  1. /thirdshift-implement
  2. /thirdshift-code-review
  3. /thirdshift-pr

thirdshift takes an Issue URL: one issue starts a Ticket run; an issue with sub-issues starts a Spec run. Its Factory skills implement the issue, review the change and write the pull request.

How bug issues are handled

Issues labelled bug first use /thirdshift-diagnosing-bugs to reproduce the reported failure and write a failing regression test before fixing it. A Continuation whose Issue branch is ahead of the Base branch reproduces at their merge base, and a fix already on the branch still goes on to review and the pull request. If it cannot reproduce the bug, the Ticket run leaves triage notes and needs-info on the issue, ending successfully without a new pull request. Flaky-test Tickets use the recorded CI failure as evidence and go straight to implementation. Security fixes and Base fixes keep their own flow.

Skills and Processes in detail

thirdshift skill runs one skill. thirdshift process is experimental: it runs skill, command or catalogue Steps from ~/.thirdshift/processes, including Steps that run together in throwaway worktrees the file names. The catalogue Step run-published-issue starts a Ticket run or a Spec run on the issue the session Step before it published. Its optional process = "<name>" setting selects the child Ticket Process, defaulting to ticket-run; it must exist and declare an Issue-branch worktree. An issue with Tickets still starts a Spec run. An optional Step can fail without stopping the process. Pass issue to give the process an issue, so each session Step works from that issue. A file can name one Issue-branch worktree and a delivery Step: the run holds the Claim, and Delivery leaves a ready-for-review pull request and then removes the Claim. A self-merge Step directly after it merges when merge or the User config asks, and a file can only tighten limits. With no issue, and neither an Issue-branch nor a Spec-branch worktree, it is a Pass: it skips, exiting 0 with no Run notification, while the repository is at its Command limit, and it does not take an Architect run's Ready-issue or Architect-idea gates. With an issue, it is not a Pass. Status, the Console and the Activity log list it as Process <name>, and a failed one is in Needs you. It sends a Run notification under the same email rules as a Ticket run, except a skipped Process sends none. Custom processes.

A Step may name its own Harness, Model and Effort. Each omitted setting inherits the Command's resolved value, including --harness and User config choices. process check prints each choice, its origin and whether the Harness starts. thirdshift process list lists Processes and marks Built-in processes; process show <name> prints a Process file exactly, ready to save under a new Custom process name. The compiled-in ticket-run file runs implement → security-review → delivery → self-merge. Ticket runs execute it by default, including those started by Spec, Architect and Security runs, inheriting the Command's Harness, Model and Effort, Child asks and Limits. The Security review and Self-merge still run only when asked. Inspect it with process show ticket-run, or use process check ticket-run with an issue <issue> argument.

Spec runs execute the compiled-in spec-run file: land-tickets → spec-review → security-review → delivery → self-merge, on a spec-branch worktree. Every starter uses it: an Issue URL, Pickup, Architect and Security runs, and run-published-issue. Dispatch, the Claim, Child asks and Limits stay in front of the file. The run keeps its sessions, progress lines and Spec run name, and records the compiled file's hash. Inspect it with thirdshift process show spec-run or validate it with thirdshift process check spec-run issue <spec>; its name is reserved against Custom processes.

Security runs execute the compiled-in security-run file: security-audit → reproduce-findings → fix-findings → close-findings. The Command limit, the lock of its kind and Ready-issue, failed-fix and unchanged-Base skip gates stay before the file. An earlier reproduced finding awaiting an allowed fix makes the first two Steps skip. The run fixes at most one finding and closes only that finding after its fix merges and its proof passes. Sessions, progress, logs, Run notifications and the Security run name stay the same, with the compiled file's hash recorded. Inspect it with thirdshift process show security-run or validate it with thirdshift process check security-run; its name is reserved against Custom processes. A copy under a new name follows the Command limit without a lock of a kind and can fix several findings.

Pickup has no Built-in process file. It selects and reserves a Ready issue, then dispatches ticket-run or spec-run.

A Custom process can instead declare a spec-branch worktree and use land-tickets to gather Tickets in dependency order into a draft Spec PR and its checklist, up to spec.parallel at once. Its process setting selects every child Ticket's Process. A file can declare one Issue-branch or one Spec-branch worktree, never both; the former refuses Specs, the latter requires one, and both require an issue and make the Claim before the worktree. The draft Spec PR keeps its Claim while it waits.

Follow land-tickets with spec-review → security-review → delivery → self-merge on the Spec-branch worktree to deliver the Spec PR. The Spec review reviews the whole Spec with its usual report contract. Delivery restores the Tickets checklist, runs the Repair loop and leaves the PR ready for review, removing its Claim. Security review and Self-merge run only when asked; a refused or incomplete Security review holds the merge.

The implement catalogue Step runs the Ticket run's implementation session on an Issue-branch worktree, starting fresh or continuing existing work. On an ordinary bug issue it diagnoses first; Flaky-test Tickets use recorded evidence directly; if the bug is not reproduced, the Process ends successfully with triage notes and needs-info, skips later Steps and cleans up its Claim and worktree.

The security-review catalogue Step reviews the Issue branch after editing and before delivery, when the command or User config asks. It keeps the Ticket run's Harness fallback, and a refused or incomplete review holds a following Self-merge.

The architecture-review catalogue Step reviews the Base branch in its own throwaway worktree. Follow it with run-published-issue to build a Strong Architect plan. An Architect idea, or thirdshift process <name> --plan-only, ends the Process successfully and skips later Steps, with the reason recorded.

security-audit → reproduce-findings audits the Base branch, records findings privately and reproduces each at its audited commit. Each Step takes its own Harness, Model and Effort and keeps completed reproductions. Both skip when a recorded finding awaits an allowed fix; Security runs keep their existing skip gates.

Every session Step gets one Resume when background work was killed as its turn ended. If the Resume leaves work running too, the Process names it and carries on; a later failure names that killed work first. A Resume does not spend a Repair.

The compiled-in architect-run file runs architecture-review → run-published-issue. Architect runs execute it after the Command limit, the lock of their kind and the open-plan, waiting-idea and Ready-or-settling-issue gates. The review Step ends successfully on an idea or with --plan-only; otherwise the next Step runs the plan. Read it with thirdshift process show architect-run or validate it with thirdshift process check architect-run. A copy under a new Custom process name follows the Command limit without a lock of a kind. Architect runs keep their name, progress, logs and Run notification.

Command records and Session traces keep each run's Process name, whether it is Built-in or Custom, and the SHA-256 hash of its file. Architect runs record the compiled architect-run file. Child Ticket runs record their selected Process independently of their parent, defaulting to ticket-run. Runs awaiting a Built-in file keep their run-type name without a hash; the displayed run names stay the same.

A Custom process can use fix-findings → close-findings to fix reproduced Security findings and close only merged fixes whose proof-of-concept passes against the merged Base branch. The Steps keep private records and the Security run’s fixing and closing permissions. fix-findings can select a child Ticket Process with process; it defaults to ticket-run. Failed fixes and failed rechecks stay with the Day shift. Their sessions and the Ticket runs they start stay off any configured OTLP endpoint, as a Security run's do. The Built-in Security run still fixes at most one finding per invocation.

Read every prompt and skill the agents get →

How a Ticket run works

One issue in, one pull request out.

A Ticket run takes one issue through four steps and delivers a pull request that is ready for review, or merged when you ask for a Self-merge. Steps 2 and 3 are one agent session in the Harness you choose. Under each step are lines thirdshift printed on stderr during a real Ticket run, overnight on 12 October 2026. A scheduled Pickup run took issue #663 at 00:21, and its Ticket run Self-merged pull request #665 at 01:22. That pull request refreshed the floor plan further down this page. Click a step to see what it does. Every prompt and skill it sends is on the Prompts and skills page.

From issue #663 to merged pull request #665 in four steps Issue #663 passes through Step 1 · Prepare, Step 2 · Implement, Step 3 · Review and Step 4 · Finish. A bracket over steps 2 and 3 marks them as one agent session. Pull request #665 comes out merged into main. ONE AGENT SESSION ISSUE #663 the issue C STEP 1 · PREPARE M STEP 2 · IMPLEMENT Y STEP 3 · REVIEW K STEP 4 · FINISH PR #665 · MERGED merged into main

Step 1 · Prepare

Pre-flight checks the Origin match, the open issue, the Base branch and the selected Harness, plus Git’s commit identity. thirdshift picks the Issue branch, fresh or a Continuation, claims the issue with in-progress, and creates a worktree next to your clone. Here a scheduled Pickup run took the issue.

  1. thirdshift: 00:21:01 Pickup run starting, 2026-10-12 -0400
  2. thirdshift: 00:21:05 taking Ready issue #663 "update https://thirdshift.app/ based on the latest which is part of thirdshift", as thirdshift https://github.com/JacobStephens2/thirdshift/issues/663 would
  3. thirdshift: 00:21:05 checking the Model and Effort against codex debug models
  4. thirdshift: 00:21:06 logging this command to /home/jacob/.thirdshift/logs/JacobStephens2/thirdshift/commands/pickup/663-20261012T002101-0400.log
  5. thirdshift: 00:21:06 sessions run on codex · gpt-6.1-sol · high
  6. thirdshift: 00:21:08 updating main in the Launch directory from origin/main
  7. thirdshift: 00:21:08 labelling #663 in-progress, in place of ready-for-agent
  8. thirdshift: 00:21:10 creating worktree /home/jacob/repos/thirdshift-issue-663 on issue-663 from origin/main

Step 2 · Implement

A headless session in the selected Harness, with the Factory skills loaded, implements the issue in the worktree, test-first where it can, and commits. The recorded Ticket run used Codex.

  1. thirdshift: 00:21:10 logging the session to /home/jacob/.thirdshift/logs/JacobStephens2/thirdshift/commands/pickup/663-20261012T002101-0400-implement.jsonl
  2. thirdshift: 00:21:11 implement: session started
  3. thirdshift: 00:21:19 implement: $ pwd && git status --short && git branch --show-current && cat /tmp/thirdshift-skills-OIZYKN/thirdshi…
  4. thirdshift: 00:21:25 implement: $ cat AGENTS.md GLOSSARY.md docs/agents/issue-tracker.md docs/agents/domain.md docs/agents/triage-label…
  5. thirdshift: 00:21:25 implement: $ gh issue view 663 --repo JacobStephens2/thirdshift --json title,body,comments,labels && git log -5 -…
  6. thirdshift: 00:21:30 implement: web search
  7. thirdshift: 00:21:30 implement: $ cat CODING_STANDARDS.md && rg --files | rg '("'^site/|web|index.html|landing|pages|astro|package.jso…
  8. thirdshift: 00:21:35 implement: $ cat site/index.html site/main.js
  9. 7 lines cut: more reading
  10. thirdshift: 00:23:41 implement: $ cat > /tmp/issue-663-pr.md <<'EOF'
  11. thirdshift: 00:24:13 implement: $ "cat > /tmp/verify-site-663.cjs <<'JS'
  12. thirdshift: 00:24:15 implement: $ cargo check --all-targets && cargo test --test share_card --test site_deploy
  13. thirdshift: 00:24:25 implement: $ node /tmp/verify-site-663.cjs
  14. thirdshift: 00:24:26 implement: $ git diff --check && git diff -- site/index.html site/styles.css
  15. thirdshift: 00:24:39 implement: $ python3 - <<'PY'
  16. thirdshift: 00:24:48 implement: $ rg -n '\\.unit|\\.floor|hopper' site/styles.css && sed -n '115,160p' site/styles.css
  17. thirdshift: 00:25:13 implement: $ python3 - <<'PY'
  18. thirdshift: 00:25:26 implement: commit

Step 3 · Review

The same session reviews its work against the Base branch, fixes the Standards findings and Spec findings it agrees with, and lists the rest as Unaddressed findings in the pull request body. Behavior findings need a test or command that exercises them before the agent decides. It fixes reproduced failures and keeps the test. Then it opens the pull request, ready for review.

  1. thirdshift: 00:26:05 implement: $ git status --short && gh pr list --repo JacobStephens2/thirdshift --head issue-663 --state open --js…
  2. thirdshift: 00:26:26 implement: $ cargo fmt --check && cargo clippy --all-targets -- -D warnings
  3. thirdshift: 00:26:27 implement: $ git check-ignore .thirdshift-review-ZgRuM9/standards.md; rg -n 'thirdshift-review' /home/jacob/repos…
  4. thirdshift: 00:27:10 implement: $ ls -l /tmp/issue-663-standards-initial.md /tmp/issue-663-spec-initial.md 2>/dev/null && cat /tmp/iss…
  5. thirdshift: 00:27:13 implement: $ cat /tmp/issue-663-standards-initial.md
  6. thirdshift: 00:27:29 implement: $ python3 - <<'PY'
  7. thirdshift: 00:27:30 implement: commit
  8. thirdshift: 00:27:41 implement: $ cat /tmp/issue-663-spec-initial.md
  9. thirdshift: 00:27:53 implement: $ cargo test > /tmp/issue-663-cargo-test.log 2>&1
  10. thirdshift: 00:27:54 implement: $ "mkdir -p .thirdshift-review-ZgRuM9 && cp /tmp/issue-663-standards-initial.md .thirdshift-review-ZgR…
  11. thirdshift: 00:28:10 implement: $ tail -n 12 /tmp/issue-663-cargo-test.log && git status --short && git log main..HEAD --oneline
  12. thirdshift: 00:28:30 implement: $ "cat > /tmp/issue-663-pr.md <<'EOF'
  13. thirdshift: 00:28:51 implement: push
  14. thirdshift: 00:28:52 implement: $ tail -n 14 /tmp/issue-663-cargo-test.log
  15. 20 lines cut: mostly waiting on the full test suite
  16. thirdshift: 00:46:48 implement: $ python3 - <<'PY'
  17. thirdshift: 00:46:59 implement: $ gh pr view issue-663 --repo JacobStephens2/thirdshift --json number,url,state,isDraft,baseRefName,he…
  18. thirdshift: 00:47:13 implement: session ended after 26m 2s: 7416316 input tokens (7285760 cached), 20664 output tokens

Step 4 · Finish

An optional Security review checks the change first. Then thirdshift pushes, checks the pull request, merges the Base branch in and watches CI. A merge conflict or failing CI starts a Repair, at most 5. For generated-file conflicts, the Repair resolves the sources and regenerates the output. A Resume can happen in any session and isn't a Repair. The Ticket run ends once the pull request is open, ready, mergeable and passing CI. A Ticket run that Self-merges, requested with thirdshift merge <Issue URL> or the User config, then merges it. Here the Security review found nothing, main moved during CI and was merged in again, and no Repair was needed.

  1. thirdshift: 00:47:13 Security review private report: /home/jacob/.thirdshift/logs/JacobStephens2/thirdshift/security-reviews/663-20261012T002101-0400-0eoBGA/pre-existing.json
  2. thirdshift: 00:47:13 logging the session to /home/jacob/.thirdshift/logs/JacobStephens2/thirdshift/commands/pickup/663-20261012T002101-0400-security-review.jsonl
  3. thirdshift: 00:47:14 security-review: session started
  4. thirdshift: 00:47:14 security-review: Model: gpt-6.1-sol (requested)
  5. thirdshift: 00:47:23 security-review: $ git status --short --branch
  6. thirdshift: 00:47:23 security-review: $ cat .agents/skills/thirdshift-security-audit/SKILL.md
  7. 28 lines cut: the review reading and checking the change
  8. thirdshift: 00:49:54 security-review: session ended after 2m 41s: 981609 input tokens (882304 cached), 5030 output tokens
  9. thirdshift: 00:49:54 pushing issue-663
  10. thirdshift: 00:49:56 writing "Built with codex 0.160.0 · gpt-6.1-sol · high" in the pull request's body
  11. thirdshift: 00:49:57 checking the PR
  12. thirdshift: 00:50:01 merging origin/main into issue-663
  13. thirdshift: 00:50:03 pushing issue-663
  14. thirdshift: 00:50:05 waiting up to 60s for CI on c16e780
  15. thirdshift: 00:50:07 CI on c16e780: 6 of 8 checks still running
  16. 5 lines cut: CI still running
  17. thirdshift: 01:00:40 CI passed on c16e780
  18. thirdshift: 01:00:41 origin/main moved while CI ran; merging it again
  19. thirdshift: 01:00:42 merging origin/main into issue-663
  20. thirdshift: 01:00:43 pushing issue-663
  21. thirdshift: 01:00:45 waiting up to 60s for CI on 545e42f
  22. thirdshift: 01:00:57 CI on 545e42f: 6 of 6 checks still running
  23. 9 lines cut: CI still running
  24. thirdshift: 01:22:47 CI passed on 545e42f
  25. thirdshift: 01:22:48 checking the PR is open, ready and mergeable
  26. thirdshift: 01:22:49 merging the PR into main
  27. thirdshift: 01:22:49 checking the PR is open, ready and mergeable
  28. thirdshift: 01:22:53 deleting issue-663 on origin
  29. thirdshift: 01:22:54 cleaning up the worktree and local branch issue-663
  30. thirdshift: 01:22:55 removing in-progress from issue #663
  31. thirdshift: 01:22:56 PR https://github.com/JacobStephens2/thirdshift/pull/665 is merged

The lines are copied, timestamps and all, from the Pickup run's Command log, which keeps everything thirdshift printed. Each cut for length says how many lines it left out; there are 139 lines on stderr in all.

Results

What you get back

Ready for review

An open pull request from the Issue branch to the Base branch. It is mergeable, its CI passes, and it has been reviewed against your repository's documented coding standards and against the issue. Otherwise thirdshift doesn't call it ready.

Unaddressed findings

Every Standards finding and Spec finding the agent chose not to fix is listed as an Unaddressed finding in the pull request body, with the code, plan decision, ADR or focused run that refutes it. A decision left to the Day shift links a needs-triage issue.

Failed ticket runs keep their work

A Failed ticket run still pushes its work, so nothing is lost (if the push fails, it keeps the worktree instead), and its pull request goes back to draft. Repeat the same command to continue it.

Workflows

Six workflows

Choose the work you need. Open a workflow for details and links to the manual.

Ticket runOne Issue URL becomes one reviewed pull request.

A Ticket run takes one Issue URL and delivers one pull request, ready for review. A Ticket run that Self-merges merges its own reviewed, green pull request when you ask.

Spec runDependent Tickets come together in one Spec PR.

A Spec run works through Tickets in dependency order, up to three at once by default. They merge into a Spec branch, then one Spec PR gets reviewed against the whole Spec.

Architect runFind architecture improvements and build a Strong plan.

An Architect run looks for architecture improvements and builds its top Strong plan. Without a Strong recommendation, it leaves an Architect idea for the Day shift. Use --plan-only to publish a plan and stop.

Pickup runTake a Ready issue and put the factory to work.

A Pickup run takes the lowest-numbered Ready issue by default, the highest-numbered with pickup.order = "highest-first" or highest-first, after it has settled and while the repository is below its Failure limit: fewer open issues labelled agent-failed than pickup.failure_limit, 3 by default. A pull request waiting for review never holds it back. It immediately re-runs failed Base branch push CI once: green on re-run files a Flaky-test Ticket, and red again files an ordinary bug Ticket after 30 minutes. That CI-red Ticket leaves job names and log lines out of its title, body and later comments, and waits until you write the task and apply ready-for-agent. New failing commits are added to an open CI-red Ticket; one in needs-info does not block a new report. Failed work stays with the Day shift until you hand it back by applying ready-for-agent again.

Security runAudit privately; fix reproduced findings when allowed.

A Security run audits the Base branch and records findings privately. It is report-only by default. With security-fix, it can fix a reproduced finding through a Ticket run or Spec run. By default, it closes a finding its fix merged once its proof-of-concept test passes against the merged Base branch; no-security-close or close = false under [security] leaves it open. An optional Security review checks each Ticket run's change, including Tickets and the Spec PR, and holds Self-merge if introduced findings remain unaddressed or the review is incomplete. Its Harness is checked before work; an unavailable review Harness falls back to the default Harness, with one fallback also allowed for a Harness error before its first turn.

Scoring runGrade merged pull requests and compare your Scores.

A Scoring run, started with thirdshift score, samples merged factory pull requests across configured GitHub owners, leaving out Security fixes. Each gets a blind packet with its issue and repository at merge time, its diff, pull request and CI conclusions. thirdshift scores --json lists the private samples by week. An independent Model grades each packet on Correct, Scoped, Tested, Honest and Standards, with a pass or fail and a reason for each. Completed Scores are kept; the next Scoring run finishes pending packets after a Claude or Codex quota window reaches 85%, a Claude rejection, or a Claude warning with no readable utilization. It also proposes Bug origins for closed bugs, excluding Security fixes, using a sandboxed session and history ending at the fix. The first proposal run covers all closed bugs; later runs cover their window. Use thirdshift bug-origins [issue] --json to read them; --confirm, --correct <pull request> or --none settles one. Confirmed origins count against their retained Ticket run in show --json and create proposed code-review Eval tasks with pinned PR diffs and draft catch criteria. Rejected and unsettled origins count for nothing. Eval tasks stay out of Experiments until approved.

Scoring samples, Bug-origin proposals and settlements, and Run metrics share retained pull-request attribution. Matching ignores ASCII letter case and trailing slashes. Latest means chronological RFC 3339 time, including UTC offsets, then greatest lexical record path and Command name for ties; invalid times sort before valid ones. Saved local record-path/name pairs select that exact Command under the matching pull request. Missing or mismatched local identities count for nothing; only absent or cross-host attribution selects the latest local Command, so Continuations never multiply a count.

The first run marks 20 past pull requests for you, spread across Harnesses and Models; later runs mark two a week. thirdshift scores <pull request> --mine records your five Scores before revealing the model's; add --json to return the saved result as JSON. Ordinary text and JSON views also keep model Scores hidden until yours are saved. Each criterion shows its own calibration: at least 18 agreements among the last 20 pull requests you both scored.

The Console's Scores page lists samples by week and each criterion's calibration, and saves all five of your Scores before revealing the model's. Its Bug origins page shows proposals and settled decisions with Confirm, Correct and Reject actions. Both use the same operations as their CLI commands.

Schedules and passes

Start passes with thirdshift architect base main, thirdshift pickup base main or thirdshift secure base main. A Custom process started with no issue, and neither an Issue-branch nor a Spec-branch worktree, follows the same Command limit, running beside other Passes up to it, and does not wait on a Ready issue or an Architect idea. A file that declares either branch worktree is refused when no issue is given, before any session. Your operating system schedules them. [pass] command_limit, 1 by default, is how many Commands on one repository on the machine skip a Pass there; raise it to let Passes overlap: Pickup runs, one Architect run and one Security run side by side, never two Architect runs or two Security runs. A Ticket run you start on an Issue URL counts toward it, but is never refused. thirdshift status, thirdshift cronjobs and the Console show when each repository's Pickup, Architect and Security Pass last fired, including repeated skips. Architect runs every few minutes and Security runs on a schedule, with fixing allowed. Both yield to work the Day shift shaped, and pause when a decision needs you.

Console

See the Console with sample Commands in the Focus light Theme. Open either screenshot for the full-size view. The Console header shows the running thirdshift version. Every Console tab title names its host; the Inbox also shows its Needs you count. Ready for review rows show the pull request's latest CI: green, red, pending, no checks or unknown. A separate Merge conflict pill appears beside CI when GitHub reports a conflict; the row stays Ready for review even with green CI. status shows the same indicators, and show --json includes locally cached GitHub facts and observation times without a network request.

Console Inbox: a failed Command in Needs you, two pull requests Ready for review, and the selected Command's details.
The Inbox groups Commands by what needs you. Select a row to inspect its cause, CLI commands and logs alongside the list.
Console Waterfall: a Command's stages and Session tool calls drawn on one time axis, with the slowest calls listed above.
Waterfall expands a Command into stages, Sessions and individual calls, so you can see where the time went.

The Console opens on this machine's Inbox: Commands grouped by what needs you, with their stages and logs. Overview shows Needs you, Ready for review, Landing and Working together, each with its heading and count. Folders beside the one-line rows filter to a single section, including Done and Resolved; a clicked row's Command details open alongside. It reads ready rows' pull requests and Needs you rows' issues and pull requests from GitHub in the background once a minute; changed answers update open pages automatically. thirdshift status uses the same kept answer. Failed reads keep the last facts; after five minutes, both show when GitHub last answered and why the latest read failed. With fewer than 500 GraphQL points or REST requests left, both wait for the quota to reset, leaving the rest to the factory. An ended Needs you row leaves when GitHub shows its issue closed or its pull request merged; a Triage row also leaves when needs-triage is removed. A Finding leaves with “findings triaged” once all its private records are triaged on GitHub. A draft advisory without severity, or an open security-finding issue labelled needs-triage, still waits; a finding closed by its merged fix does not. Live Silent and Slow rows wait until their Commands end. A signed-in account can Stop or Requeue a live Command, just as from the CLI. Dismiss is always visible on the row in Needs you or Ready for review, beside Copy where available; d dismisses the selected row and selects the next. An inline Dismissal shows a temporary notice with Undo; Command details also keeps Dismiss and Undo. Command details shows each CLI form: thirdshift dismiss <command> or thirdshift dismiss <command> --undo. A dismissed row returns for a new kind of problem or when it ends ready for review; each kind counts once for the whole row.

The Console and status show the serving OS account's Commands by default. thirdshift console other-accounts readable, or a comma-separated list of names, includes readable local accounts with an account tag, including in Needs you and its tab count. Other-account Commands are read-only: Stop, Requeue, Dismiss and Undo apply only to the serving account's own Commands. The machine owner grants read access with filesystem permissions or ACLs. Account visibility.

On a desktop, Inbox issue numbers stay visible when long repository or Process subjects shrink. Hover a subject for its full text.

Command details opens with the Inbox subject linked to the issue and its full title, wrapping long titles above Stop and Dismiss. An unknown title says “(title unavailable)”; a Command without an issue shows its Inbox subject alone. The recorded issue title is also in thirdshift show <command> --json.

An ended, unsuccessful Command shows its full failure reason immediately below that heading, before the controls, with URLs as links. When its own cause is absent, it uses the first cause from failed dispatched work. Successful or live Commands, and those with no cause, show no reason. The cause also stays in the facts list.

Command details shows the last five lines of recent Command output above Full Command log, updating as output arrives. The small preview helps assess a Slow run without leaving its details.

A Security fix’s Command details links each advisory it addresses, with its title and severity, even if the fix fails or is interrupted. The parent Security run marks which advisories it dispatched a fix for. Older Command records show no advisory line.

Above its groups, the Inbox counts the runs active on this machine. Below the notification control, every Console reader page shows whether host limits allow another session, refreshing every ten seconds while visible. The indicator links to the Resources page, also available with thirdshift resources, for host memory, CPU load and the User config limits that can delay new sessions. It says when limits are off or measurements are unavailable; capacity is not reserved.

Experiments

Experiments compare a Candidate with a Baseline on private Eval suites. thirdshift experiment <candidate> shows its Trials’ worst-case session-minutes, with an estimate where this machine has history, and asks on a terminal unless given --yes, then builds both Arms and runs interleaved Trials with two workers, a fixed Bar and resume after interruption or a Paused Command outcome at a quota stop (85% for Claude and Codex, a Claude rejection, or a Claude warning with no readable utilization). Trials and Graders run in bwrap sandboxes. Code Graders score mechanical checks offline from report packets and the prepared repository, then fresh model Graders score written criteria from blind packets with provider-only access. Graders cannot read raw Trial logs, Arm mappings or the Experiment’s other files. Results show the Verdict, wrong findings, borderline marks, paired intervals, each Arm's minutes, tokens by Model, reported cost and Void causes. Trials and Graders join the Command's Trace. Void Trials retry fresh up to twice; an exhausted task drops out of both Arms. More than a tenth of judged tasks dropped in suites that are not advisory makes the overall Verdict inconclusive.

Experiments, including release Experiments, report approved Eval tasks missing Trial inputs before building either Arm. Before each Trial's session, the host prepares its repository's pinned Rust toolchain and listed components, sharing preparation across Trials with the same pin. An installation failure makes the Trial void with session_unavailable. Spec review Trials keep the production prompt and grade only the reports; their sandbox blocks gh calls and provides no PR service.

The Bar fixes separate pass and fail levels, 70% and 95% by default. Each metric shows both intervals from the same draws: fail below zero at the fail level; otherwise pass when the interval at the pass level sits above the margin, marked worse, within the margin if it lies wholly below zero. Today's suites fall short of an 80% A/A pass rate at the 70% default: code-review needs about 20 Eval tasks, Spec review about 80. --pass-level and --fail-level set them before the first Trial. Saved Experiments keep their original Bar and Verdict.

An A/A Experiment uses one commit and matching Harness, Model and Effort flags in both Arms to measure ordinary Trial variation. Select its suites explicitly with --suite; both Arms run through to a Verdict. After completion, thirdshift experiments <id> --record-difficulty records each Eval task's Difficulty from both Arms' non-void Trials. thirdshift evals lists the readings and whether each is discriminating: between 0.15 and 0.95 inclusive, over at least 6 Trials. Fewer Trials or no reading means unmeasured.

The Bar fixes each suite's discriminating Eval tasks from recorded Difficulty before the first Trial. Only those tasks are judged; other approved tasks run and are graded as measurement. experiments <id> and --json show measurement Trials per task and counts of judged, measurement-only, void-dropped and judged tasks measured on another setup. Measurement changes no interval, required recheck or prediction. An empty judged list is inconclusive. A changed list or changed Difficulty for a retained task refuses resume after the first Trial, including readings that stay inside the band. Saved Experiments keep their original method.

The Console's Experiments pages group saved Experiments into Running, Needs you and Done. Each Experiment says what it tests and updates live with its Trial grid, Verdict intervals, Arm comparison and Bar, each folded to one line until opened. Open a Trial's Peek for its Scores, reasons and Session evidence; copy recheck commands to run in the CLI. Session links share thirdshift experiments <id> --session <session-id>'s confined evidence reader, keeping healthy evidence readable even when unrelated Trial metadata or usage spans are corrupt. Approve proposed Eval tasks there or with thirdshift evals approve <suite> <task> --json. Approval starts no work and affects future Experiments; unapproved proposals never run.

A suite with fewer than 20 discriminating Eval tasks is an Advisory suite: its Verdict and intervals are shown, but cannot pass or block a release. --min-discriminating-tasks sets the minimum for one Experiment; the Bar fixes it before the first Trial and refuses a changed minimum on resume. Only suites that are not advisory decide the overall Verdict, Void dropout guard and required rechecks. When every suite is advisory, the Verdict is inconclusive. CLI text, JSON and the Console mark Advisory suites and show judged and measurement counts. The release summary lists each Advisory suite and its Verdict and asks whether to release when all suites are advisory. Saved Experiments without the minimum keep their original Bar and Verdict.

Each Trial and each Grader has its own memory cap. A Trial its cap kills is void; repeated cap kills are reported for its Arm. The User config sets the caps, with defaults of 1 GiB for throttling, 2 GiB for killing and 1 GiB of swap.

The Verdict waits for your rechecks of borderline and decisive Scores. thirdshift experiments <id> --json lists those waiting and which flip changes the provisional Verdict, with its resulting Verdict. thirdshift recheck <id> <trial> pass --reason '…' records your decision beside the Grader's Score and keeps its history. To review a batch, use thirdshift recheck <id> --pending, then record one decision and reason with thirdshift recheck <id> --batch <fingerprint> pass|fail --reason '…'. A changed pending list refuses the batch.

Each Trial removes its Harness caches when its session ends. After grading and all rechecks finish, the Experiment removes every attempt's repository copy. Paused Experiments keep repositories for resume; Session evidence, reports, packets and Scores remain readable.

scripts/release.sh runs on Linux. It refuses other hosts before Git or GitHub work. On macOS, use an Ubuntu 24.04 Linux VM such as Lima; on Windows, use WSL2.

thirdshift experiment --release <commit> compares touched suites with the last release tag. The release script skips Experiments by default. Add --with-experiment to scripts/release.sh on each invocation to run one: it waits for rechecks before pushing and asks whether to release on a fail or inconclusive Verdict. Reruns with the flag reuse the Experiment, including before opening a pushed branch’s PR. It selects the newest main commit whose latest push CI passed, tags that content plus the version bump, waits for publication, then merges the bump PR. After a failed unpublished release, rerunning re-cuts from newer green main content or automatically reruns failed jobs; published releases are never moved. If the publication check cannot be completed, the script refuses and moves nothing. Recovery retains the prior release boundary for the summary and Experiment. Main can move during the release; a failed merge leaves the release standing and the PR for the Day shift. No touched suite or a last release with no Trial flag carries on with a note. Release checks.

Run metrics

Completed Ticket runs keep their Run metrics in their Command records: outcome, Repairs, CI rounds, Unaddressed findings counted separately as Standards, Spec and Security, stage times against Usual ranges, and minutes by stage and in total. The Unaddressed findings counts come from Delivery's final PR body and include the Security review. Each Session stage keeps the review's Standards and Spec finding counts from its summary, with missing counts left missing. thirdshift show <Issue URL> --json includes each Ticket run's metrics, including Ticket runs and Base fixes. The Console's Command details show these same metrics and mark unavailable signals as Missing.

thirdshift metrics <command> [--json] shows one Ticket run and its children; thirdshift metrics [--json] shows weekly trends by repository, Harness, Harness version, Model, Effort and kind of session, with week and repository filters. Session traces supply tokens by observed Model with the cache split, reported cost, tool errors, permission denials, killed work and repeated tool calls. Completed Ticket runs sum these by session kind; past Ticket runs get them from converted traces when metrics are read. Missing values stay missing. Every signal stays separate.

Confirmed Bug origins count against the Ticket run that introduced each bug when metrics are read, even if confirmed after it ended. Metrics match this machine's Ticket runs against the Scoring data for both hosts, and weekly Ticket run trends count them in the Ticket run's start week. Rejected and unsettled origins count for nothing. Command details in show --json and the Console include these read-time counts and the available metrics of past Ticket runs, without rewriting their records.

Run metrics and Experiments share Session usage accounting: partial totals refine only reported fields, preserving known input, cache counts and cost. Input includes cache reads and writes; missing measurements stay missing. Reported Session cost wins, otherwise each Model's reported cost replaces its call costs. Saved completion metrics stay fixed.

Every Ticket run also checks its sessions' shell commands for force pushes, shared-branch history rewrites and recursive deletes outside the Worktree. Run metrics retain each matching command as an advisory flag; flags never block or fail a Ticket run.

Engineer the factory while the factory engineers the software.

Examples

Real pull requests

Real pull requests thirdshift made on its own repository. Judge the work yourself.

Does a second reviewer catch what thirdshift's own review lets through? 183 replayed reviews, Codex against a fresh Claude session: Fresh Eyes Beat a Second Family.

Before you run it

Requirements and platforms

Requirements

  • Your chosen Harness, installed and authenticated: claude (Claude Code, the default), codex (Codex CLI), agy (Antigravity CLI), grok (Grok Build), muse (Muse Code) or opencode (OpenCode, with a configured Model provider).
  • gh (GitHub CLI), logged in.
  • Node.js on PATH for Security runs, whose report validators use it.
  • git with a global user.name and user.email, and credentials that can push to the repository.

Platforms · Linux only

  • Test suite in CI: Ubuntu 24.04.3 and later, x86_64 and aarch64. On Apple Silicon macOS, run Ubuntu 24.04 aarch64 in a Linux VM such as Lima with vz and --mount-none. Keep repositories on the VM's Linux filesystem (e.g. ~/repos), not under /Users.
  • Release smoke check only: Rocky Linux 9.8 and later (x86_64) and WSL2 with Ubuntu 24.04 or later (x86_64). Keep WSL2 repositories on the Linux filesystem, not under /mnt/c. WSL1 is not supported.
  • Two statically linked Linux musl binaries. Native macOS (including Intel macOS) and native Windows have no binary.

Choose the Harness, Model and Effort with thirdshift setup or per command. Setup suggests Claude's documented Model aliases and accepts custom Model IDs. See Harness configuration and supported platforms.

About the name

Third shift

My dad, Mark Stephens, was a pressman at Tursack Printing, the print shop Robert Tursack Sr. founded in Philadelphia in 1959. My dad worked third shift at the Morgantown, Pennsylvania plant, keeping the big four-color presses running through the night. Sometimes I got to visit, and I always wondered whether I'd end up in printing myself. The lineage carries on. Bob Tursack went on to found Brilliant Graphics in Exton, where my mom, Melodee, did graphic design with him until he sold the company to Royercomm Prism in 2026. This is as close as I am to printing right now.

The printing press made copying words cheap. Agents are doing that for code. thirdshift is named for my dad's shift: the machines can run overnight, and I need something to keep them running.

- Jacob Stephens