---
title: Sisyphus
---

<!-- wp:docspress/hero {"eyebrow":"Linchpin plugin","title":"Nightly rolling maintenance","description":"Every night Sisyphus copies a site's production onto dev, scrubs the copy, rolls the night's updates into the site's maintenance branch, deploys it to dev and tests it. A night that passes opens a snapshot PR, and a person promotes it by merging.","primaryLabel":"Get started","primaryUrl":"/wordpress-plugins/sisyphus/getting-started/","primaryNewTab":false,"secondaryLabel":"Triage a failed night","secondaryUrl":"/wordpress-plugins/sisyphus/troubleshooting/","secondaryNewTab":false,"visualVariant":"image","layout":"editorial","mediaPosition":"right","mediaWidth":44,"imageScale":100,"height":"compact","tone":"theme","textAlign":"left","showGrid":false,"showOrbit":false} /-->

Sisyphus runs Linchpin's nightly rolling maintenance from packagist.linchpin.com. Every night it syncs a site's production to dev, cleans the dev data, rolls the night's updates into the site's `maintenance` branch, deploys that to dev and tests it. A night that passes is frozen as a `snapshot/YYYY-MM-DD` branch with a PR to `staging` or `main`, and a person promotes it by merging that PR. The boulder goes back up the hill every night.

The plan is the [Rolling Maintenance Plan](https://app.clickup.com/9014128748/docs/8cmhc3c-54414) (LINCHPIN-5851). The pilot is builditbelieveit.com on Pressable.

<!-- wp:docspress/audience-paths {"eyebrow":"Choose a path","title":"What are you here to do?","description":"Sisyphus has two kinds of reader: the engineers building and running the pipeline, and whoever triages a failed night.","paths":[{"title":"Put a site on the nightly run","description":"Install the plugin, connect it to api.linchpin.com, enroll a site and start a run.","url":"/wordpress-plugins/sisyphus/getting-started/","cta":"Get started","icon":"rocket","accent":"blue","newTab":false},{"title":"Triage a failed night","description":"Find the step that failed, what its message means, and how to run the night again.","url":"/wordpress-plugins/sisyphus/troubleshooting/","cta":"Triage it","icon":"troubleshoot","accent":"coral","newTab":false},{"title":"Change the pipeline","description":"How a run moves through its steps, what each step talks to, and how to add one.","url":"/wordpress-plugins/sisyphus/development/architecture/","cta":"Read the architecture","icon":"code","accent":"gold","newTab":false},{"title":"Look something up","description":"Every wp sisyphus command and option, the hooks, and the wp-config constants.","url":"/wordpress-plugins/sisyphus/reference/","cta":"Open the reference","icon":"terminal","accent":"green","newTab":false}],"columns":2,"tone":"theme","textAlign":"left","compact":false,"showNumbers":false} /-->

## A night

Each run goes through eight steps in order. A step that fails stops the run, and the steps after it never run, so a night snapshots only when everything before it passed.

<!-- wp:docspress/diagram {"title":"The steps of a run","type":"flow","source":"Preflight -> Sync: enrolled, Safety Net on dev\nSync -> Cleanup: production copied onto dev\nCleanup -> Update: dev scrubbed\nUpdate -> Resolve: Rolling Maintenance ran\nResolve -> Deploy: maintenance has main\nDeploy -> Test: Deploy to Dev passed\nTest -> Snapshot: suites passed","caption":"The order in Core\\Services::steps(), which the sisyphus_steps filter can change."} /-->

## What exists today

| Piece | State |
| --- | --- |
| Run engine: steps, ticks, deadlines, run history | Built |
| `wp sisyphus run`, `show`, `list`, `schedule` | Built |
| Nightly schedule: each enabled site starts on its own at its run time, in its time zone, once a night | Built (LINCHPIN-5875) |
| Run now on the Sites screen, the Overview and a site's page, and a Runs screen that follows each run step by step; one run per site at a time | Built |
| Restart: stop a site's run that is still going at the step it reached, cancelling the GitHub workflow that step started, and start a new one from Preflight. **Restart** on the Overview and a site's page, and `wp sisyphus run --restart` | Built |
| Stays active through packagist-plugin-manager's plugin cleanup | Built (needs the `linchpin_governing_cleanup_allowlist` filter in packagist-plugin-manager) |
| packagist-plugin-manager's environment views show each enrolled production's last run, its next run time and a link to the Overview | Built (LINCHPIN-5888; needs the `linchpin_governing_environment_maintenance` filter in packagist-plugin-manager) |
| Install registry in api.linchpin.com: `wp sisyphus sites` and `enroll`, and a Preflight that refuses a site not enrolled, not enabled, or with no safe dev | Built (LINCHPIN-5854; needs the api's `/maintenance/enrollments` and a `maintenance` client) |
| Pressable production-to-dev sync of the database and uploads, 3-hour timeout | Built (LINCHPIN-5855; needs the api's `/maintenance/.../syncs`) |
| Dev data cleanup: Deploy to Dev installs our Safety Net release on dev, Preflight refuses to sync onto a dev without it, and the cleanup step waits until it has scrubbed the copy | Built (LINCHPIN-5856; needs the linchpin/actions release with `safety_net`, and `safety_net: true` in the site repo's `deploy-dev.yml`) |
| Branch update and deploy to dev: Rolling Maintenance brings `main` and the night's green updates into `maintenance`, then the site repo's Deploy to Dev ships it | Built (LINCHPIN-5857; needs packagist-plugin-manager's GitHub App, and in the site repo `deploy-dev.yml`, a Rolling Maintenance that takes `correlation_id`, and a Development environment) |
| Resolve: conflicts Rolling Maintenance could not settle are answered through ai.linchpin.com, hunk by hunk, cheapest first (a rule, then clef, then Sonnet), and Rolling Maintenance checks and applies the answers | Built (LINCHPIN-5903; needs Mantle on this site with its gateway key, allowing `@cf/cloudflare/clef` and Sonnet, and the linchpin/actions release with `resolve-merge`'s `publish-conflicts`, turned on in the site repo's `maintenance.yml`) |
| Test: the site's nightly Ghost Inspector suites run against dev through api.linchpin.com, and any failing test fails the night. A site with no nightly suite passes, saying so | Built (LINCHPIN-5858, 5911; needs the api's `/tests` routes with its `GHOST_INSPECTOR_API_KEY`, and `tests:run` on Sisyphus's client. Suites are mapped in the api (LINCHPIN-5910) and written in LINCHPIN-5905) |
| ClickUp failure tasks | LINCHPIN-5859 |
| Snapshot: a night that passes freezes `snapshot/YYYY-MM-DD` at the commit it tested and opens its PR into the promotion target; a person promotes it by merging. The Overview's **Review & merge** opens that PR | Built (LINCHPIN-5860; needs `snapshots.yml` in the site repo, which also cleans up merged, closed and stale snapshots) |
| Deployment log: every deploy, to every environment, records in api.linchpin.com the commits it shipped since that environment's last one, and the Runs screen lists what each dev deploy shipped | Built (LINCHPIN-5861; needs the api's `/deployments`, the linchpin/actions release with `report-deployment`, and the `DEPLOYMENTS_API_CLIENT_ID` and `DEPLOYMENTS_API_CLIENT_SECRET` organization secrets). my.linchpin.com and Mantle read it later |
| Sites screen: every enrolled site, and a form to register one by picking from lists; a site's name, **Edit** and **Edit map** open its page | Built (LINCHPIN-5866, 5918; needs the api's `/maintenance/choices`) |
| One drawing of a site everywhere: the Overview card and the site's page draw its environment map, read-only, with what each environment runs and where each path stands; **Edit map** edits it in place, and the site's **Settings** sit on the same page | Built (LINCHPIN-5918) |
| Deployments screen: a page listing every deploy of every client's sites, one tab per environment, filtered by client and status, with what each shipped | Built (LINCHPIN-5861; needs the api's paged `/deployments` with `include=clients`) |
| Maintenance menu: Sites, Runs, Deployments and About under one top-level menu, just under the Dashboard | Built (LINCHPIN-5880) |
| Overview: each site's development, staging and production, how far each is ahead of the environments after it, last night's steps and the next run, failed sites first; and a page per site with what is waiting to be promoted and its recent deploys | Built (LINCHPIN-5882; needs the api's `/deployments/latest` and packagist-plugin-manager's GitHub App for the comparisons) |
| Promotion: the newest merged snapshot followed past its PR, through release-please's PR and the release to the environment it promotes to, each stage with its state and link; and **Live now**, what each environment runs with that release's notes and summary | Built (LINCHPIN-5917; needs packagist-plugin-manager's GitHub App to read closed PRs and releases. A production deploy's notes list a snapshot's updates once api.linchpin.com completes them from what the deploy shipped, linchpin/api#519) |

Every site set to **Run nightly** starts on its own at its run time. **Run now** and `wp sisyphus run` start one at any other time.

## Read next

- [Getting started](getting-started/index.md): install it locally, enroll a site and start a run.
- [Triage a failed night](troubleshooting.md): what each step's failure means, and what to do about it.
- [Reference](reference/index.md): every `wp sisyphus` command, the hooks and the constants.
- [Development](development/index.md): the gates, the build and the release.
- [Architecture](development/architecture.md): how a run moves through its steps, and how to add one.
