Scheduled-PR

Documentation

Commands

Comment on a pull request. You need write access on GitHub, or Contribute on Azure DevOps — a comment from anyone else is refused, including help and status.

On GitHub, install the App on the account that owns the repository first. A comment is ignored until it is installed there.

CommandEffect
/schedule friday 18:00Merge at that time, in your timezone
/schedule 2026-10-05 18:00 Europe/BerlinExplicit date and zone
/schedule 2026-10-05 18:00 UTC+2A fixed offset from UTC
/schedule 2026-10-05T16:00ZAn absolute instant
/schedule in 3 hoursRelative to now
/schedule friday 18:00 squashChoose the merge method
/reschedule tomorrow 09:00Move an existing schedule
/unscheduleCancel it
/schedule statusShow the current schedule
/schedule helpThis table, on the pull request

A bare time is read in your own timezone, learned from the dashboard or from any command where you named one. Failing that, the repository’s configured zone. Commands inside code fences are ignored, so you can write about them without triggering them.

Labels

On GitHub, a label that starts with schedule: is the same as a /schedule comment. The rest of the name is the time. Removing the label cancels the schedule. You still need write access — a label from anyone else is ignored.

schedule:friday 18:00
↳ Same as /schedule friday 18:00
schedule:2026-10-05T16:00Z
↳ An absolute instant

Useful when a bot or workflow already applies labels. The label has to be added to that pull request; a repository label that is not on the PR does nothing.

Azure DevOps

There is no Entra app. Scheduled-PR never creates a personal access token for you — you make one in Azure DevOps and paste it into the extension.

  1. Install the Scheduled-PR extension on the organization from the Visual Studio Marketplace.
  2. In Azure DevOps, open User settings → Personal access tokens and create a token. Scope it to this organization. Grant Code: Read & write. Copy the token when Azure shows it — it is not shown again.
  3. Open Repos → Scheduled-PR, paste the token, and click Connect. That stores the token and creates the service hooks.
  4. Comment the same commands on a pull request, or use Schedule merge… on the pull request menu.

When the token expires or you rotate it, open the hub and Reconnect with a new one. Reconnect also replaces the service hooks. Nothing is pasted into scheduled-pr.dev itself.

Repository configuration

.scheduled-pr.yml

Optional. Commit it to the root of your repository, on the default branch. Every key has a default, so a file with one line is valid. An invalid file does not disable scheduling — the defaults apply and the pull request comment says what was wrong.

version: 1
timezone: Europe/Berlin
default_merge_method: squash      # merge | squash | rebase

on_failure: retry                 # retry | fail | wait-for-checks
retry:
  max_attempts: 10
  backoff: exponential          # exponential | fixed
  give_up_after: 2h

on_new_commits: keep              # keep | cancel

# Merges happen only inside these. Declare none and any time is allowed.
allowed:
  - { days: [mon, tue, wed, thu], from: "18:00", to: "22:00" }

# Applied on top. Blocked always beats allowed.
blackout:
  - { days: [fri], after: "15:00" }
  - { days: [sat, sun] }

require:
  checks_green: true
  approvals: 1
  no_changes_requested: true

max_lead_time: 90d
KeyDefaultWhat it doesExamples
timezoneUTCZone for bare times, when the person has none of their own. An IANA name, or a fixed offset
  • UTC
  • UTC+2
  • UTC-5
  • Europe/Berlin
default_merge_methodmergeUsed when a command names no method. Must be one the repository allows
  • merge
  • squash
  • rebase
on_failureretryretry backs off; fail gives up at once; wait-for-checks waits for a check suite to finish
  • retry
  • fail
  • wait-for-checks
retry.max_attempts10Attempts before giving up and saying why
  • 1
  • 10
  • 50
retry.give_up_after2hWall-clock limit, whichever comes first
  • 30m
  • 2h
  • 1d
on_new_commitskeepkeep follows the new head; cancel drops the schedule when commits land
  • keep
  • cancel
allowedany timeMerges happen only inside these windows. Both bounds required; a window may run past midnight
  • { days: [mon, tue, wed, thu], from: "18:00", to: "22:00" }
  • { days: [fri], from: "18:00", to: "02:00" }
blackoutnoneApplied on top of allowed. Blocked always beats allowed
  • { days: [sat, sun] }
  • { days: [fri], after: "15:00" }
  • { days: [mon], before: "08:00" }
require.checks_greentrueRefuse to merge while checks are red or running
  • true
  • false
require.approvals0Minimum approving reviews
  • 0
  • 1
  • 2
require.no_changes_requestedtrueRefuse while a reviewer has requested changes
  • true
  • false
max_lead_time90dHow far ahead a merge may be scheduled
  • 2h
  • 7d
  • 90d

The file is re-read every few minutes, so a change takes effect without reinstalling anything.

What happens at the scheduled time

  1. The pull request is read again from GitHub or Azure DevOps. Nothing cached is trusted.
  2. It must be open, not a draft, free of conflicts, passing whatever you require, and outside any blackout window.
  3. The merge is pinned to the current commit, so a push landing mid-merge is rejected rather than merged unseen.
  4. If it cannot merge, the comment is edited with the reason in GitHub’s own words, the next attempt time, and when it will stop trying.

A closed or already-merged pull request cancels the schedule quietly. Conflicts, red required checks, and a merge method the repository forbids all stop it immediately — retrying those would never succeed.

What counts against your plan

One unique pull request scheduled within a calendar month. Rescheduling the same pull request as often as you like still counts once. Cancelling does not give the unit back — otherwise the free plan would be unlimited to anyone willing to schedule and cancel.

Documentation — Scheduled-PR