---
title: Getting started
---

Sisyphus runs on packagist.linchpin.com beside packagist-plugin-manager. Locally, any WordPress site with WP-CLI works; a Studio site that also runs packagist-plugin-manager matches production best.

## Install

```bash
composer install
npm install
npm run build
```

Then put the plugin in the site's `wp-content/plugins/sisyphus` (a symlink to the checkout, or the built `build/sisyphus` directory) and activate it:

```bash
wp plugin activate sisyphus
```

Activation creates three tables: `{prefix}sisyphus_runs`, `{prefix}sisyphus_run_steps` and `{prefix}sisyphus_maps`. Sisyphus loads its own Action Scheduler; when packagist-plugin-manager's copy is also active, the newer one runs.

## Connect to api.linchpin.com

Which sites take part, and where their dev and staging environments are, lives in api.linchpin.com. Sisyphus reads it with an application client that has the `maintenance:read` and `maintenance:write` scopes, and `tests:run` for the Test step, defined in `wp-config.php`:

```php
define( 'SISYPHUS_API_CLIENT_ID', 'sisyphus' );
define( 'SISYPHUS_API_CLIENT_SECRET', '...' );
// Only to point somewhere other than production:
define( 'SISYPHUS_API_URL', 'http://127.0.0.1:8799/api/v1' );
```

Without them, every run fails at Preflight with a message naming the constants. [Constants](../reference/index.md#constants) lists every one Sisyphus reads.

## Enroll a site

**Maintenance › Sites** lists every enrolled site and registers new ones, with no Pressable ids to look up. **Maintenance** is a top-level menu, just under the Dashboard. **Register a site** opens a form:

- **Production site** lists the Pressable-hosted sites in api.linchpin.com that are not enrolled yet.
- **Dev environment** and **Staging environment** list the account's Pressable staging sites, leaving out sandboxes. The form will not save a dev that another site already uses, or a dev that is also the staging, because the nightly sync overwrites dev.
- **GitHub repository** is filled in from packagist-plugin-manager's mapping when it has one.
- Run time, time zone, where snapshots are promoted to, and **Run nightly**. Branches are under **Branches**. A site's Ghost Inspector suites are mapped to it in api.linchpin.com, not here.

A site's name opens its page, where a site is shown and changed. **Edit** opens its **Settings** there (its repository, run time, time zone and **Run nightly**), and **Edit map** its environment map. **Pause** or **Run nightly** turns a site off or on without unenrolling it. The screen saves through the same code as the command below.

From WP-CLI:

```bash
wp sisyphus enroll builditbelieveit.com --dev=1833215 --staging=1339268 --staging-branch=staging --enable
wp sisyphus sites
```

`<site>` is the production site's hostname or its id in api.linchpin.com. `--dev` and `--staging` are Pressable site ids. The API checks each with Pressable and refuses one that is the production site, a sandbox (its forced password breaks testing), or not a staging site at all, because the nightly sync overwrites dev. With no `--repo`, the repository packagist-plugin-manager maps to the site is used. Enabling needs the production site's Pressable id, a dev and a repository. Options left out keep their value.

```text
Repository linchpin/linchpin.com, from packagist-plugin-manager's mapping.
Success: builditbelieveit.com is enabled: dev linchpindev.linchpin.build (1833215), staging builditbelieveit-staging.linchpin.build (1339268), repository linchpin/linchpin.com, runs at 02:00 America/New_York.
```

`wp sisyphus sites` then lists it, with `--enabled` for only the sites that run:

<!-- wp:docspress/terminal-session {"title":"Every enrolled site","shell":"bash","prompt":"$","command":"wp sisyphus sites","output":"site                  id  enabled  dev                                   staging                                            repo                   runs                    promotes\nbuilditbelieveit.com  36  yes      linchpindev.linchpin.build (1833215)  builditbelieveit-staging.linchpin.build (1339268)  linchpin/linchpin.com  02:00 America/New_York  snapshots into main"} /-->

Every `enroll` option is in the [WP-CLI reference](../reference/cli.md#enroll).

## Nightly runs

A site set to **Run nightly** starts on its own at its run time, in its time zone (02:00 America/New_York unless the form says otherwise). Sisyphus checks every 15 minutes, so a run starts within a quarter of an hour of its time. A site runs once a night: a Run now earlier in the evening does not stop that night's run, and a night missed by more than six hours, because packagist.linchpin.com was down, is skipped rather than run in the working day.

To see where each site stands, and when it runs next:

<!-- wp:docspress/terminal-session {"title":"Where each site stands against its run time","shell":"bash","prompt":"$","command":"wp sisyphus schedule","output":"site                  due  last_run_time            detail\nbuilditbelieveit.com  no   2026-10-28 06:00:00 UTC  Run 17 started after its last run time. Next run at 2026-10-29 02:00 EDT."} /-->

`last_run_time` is the latest time the site's run time came round, in UTC. `wp sisyphus schedule --start` starts the sites that are due now, as the check does. Each check's outcome is in the `sisyphus_schedule_check` action's log under Tools, Scheduled Actions.

## See where every site stands

**Maintenance › Overview**, where the menu opens, shows every environment on each enrolled site's environment map, in columns for development, staging and production: what each runs now, how far each is ahead of the environments after it, last night's steps, and when the next run starts. Sites whose last run failed come first, with the step that failed, why, and its GitHub run. A site's name opens its page, with the commits waiting to be promoted and its recent deploys. What the deployment log says is kept for a few minutes; **Reload** reads it again.

## Map a site's environments

Every site is drawn the same way wherever it appears, on its Overview card and its page: its environment map, with its development, staging and production environments as cards in columns and arrows for how code is promoted between them and how production's data is copied back. Each card says what the environment runs now, and each arrow where the work along it stands.

**Edit map**, on a site's Overview card or its page, turns that same drawing into the editor in place (`&edit=map`). Drag environments in from the list beside it (the client's, and Pressable sites api.linchpin.com does not know yet), drag a card into the column for where it sits, and drag from a card's blue dot to another card to draw a path. Click a card or a path to change it. The **Checks** say what the map is missing, and **Save map** shows what saving changes in the site's enrollment (its nightly target, branches and where snapshot PRs open) before it saves. **Done** goes back to the drawing.

## Start a run

<!-- wp:docspress/callout {"tone":"warning","title":"A run overwrites dev","content":"<p>After Preflight, the Sync step copies production's database and uploads onto the site's dev Pressable site. Start a run only for a site whose dev is meant to be overwritten.</p>","collapsible":false} /-->

**Run now** is on a site's Overview card, on its page, and on **Maintenance › Sites** when you hover the site. It asks first, naming the dev environment the run will overwrite, and is offered only for a site that runs nightly, since Preflight refuses a paused one. **Maintenance › Runs** lists the 20 most recent runs with the step each is on, reloads itself while one is going, and **Steps** opens every step's status and message.

A site has one run going at a time. While its run is queued or running, **Run now** is held, naming the run, and **Restart** beside it is the way to start over. Restart asks first, then fails the run at the step it reached ("Restarted by" you), asks GitHub to cancel the workflow that step started, such as Deploy to Dev, and starts a new run from Preflight, which overwrites dev again. Run now on the Sites screen that meets a run going turns into the same question. A run left unfinished with nothing queued to tick it, as deactivating the plugin leaves one, is failed as "Abandoned" when the next run starts, rather than blocking the site.

From WP-CLI:

```bash
wp sisyphus run builditbelieveit.com
wp action-scheduler run --group=sisyphus
wp sisyphus show 12
```

<!-- wp:docspress/terminal-session {"title":"Start a run","shell":"bash","prompt":"$","command":"wp sisyphus run builditbelieveit.com","output":"Success: Started run 12 for builditbelieveit.com. Tick it with: wp action-scheduler run --group=sisyphus"} /-->

`run` creates the run and queues its first tick. Action Scheduler runs the ticks on its own; `wp action-scheduler run --group=sisyphus` runs the ones that are due now. Each tick advances the run by one step, and a step that is waiting is checked again after its poll interval. While the site's last run is still going, `run` is refused with that run's number; `wp sisyphus run builditbelieveit.com --restart` does what **Restart** does.

Preflight fails a run for a site that is not enrolled, is enrolled but not enabled, or has no dev, and for a dev without Safety Net, and hands the enrollment to every later step. When api.linchpin.com does not answer, it waits and asks again for up to 15 minutes before failing. Sync then asks api.linchpin.com for the transfer and checks it every five minutes until it finishes; past three hours the run fails. A sync already running onto dev is adopted rather than started again. Cleanup waits until Safety Net has scrubbed the copy.

Update then runs the repository's **Rolling Maintenance** workflow, which brings `main` and the night's green Renovate updates into `maintenance`. Conflicts it cannot settle itself go to Resolve, which answers them through ai.linchpin.com; a conflict nobody could answer fails the run and leaves an issue for a person. Deploy runs **Deploy to Dev** on `maintenance` and waits for it, Test runs the site's nightly Ghost Inspector suites against dev, and Snapshot runs **Snapshots** to freeze the night and open its PR. The workflow steps go through packagist-plugin-manager's GitHub App, so it has to be configured on the same site, and the repository needs:

- `.github/workflows/maintenance.yml` with a `correlation_id` input in its run name;
- `.github/workflows/deploy-dev.yml`, started only by `workflow_dispatch`, with the same `correlation_id`;
- `.github/workflows/snapshots.yml`, with `correlation_id`, `sha` and `target` inputs;
- a **Development** environment that allows `maintenance`, with dev's `SITE_ID`, `SITE_URL`, `HOST` and `SSH_USER`.

linchpin/linchpin.com has all four. [Architecture](../development/architecture.md) says what each step reads and writes.

`wp sisyphus list` shows the 20 most recent runs (`--limit` for more):

<!-- wp:docspress/terminal-session {"title":"The five most recent runs","shell":"bash","prompt":"$","command":"wp sisyphus list --limit=5","output":"id  site                  status  started                  finished\n17  builditbelieveit.com  passed  2026-10-28 06:09:32 UTC  2026-10-28 06:44:36 UTC\n16  builditbelieveit.com  passed  2026-10-27 11:33:34 UTC  2026-10-27 12:04:37 UTC\n15  builditbelieveit.com  failed  2026-10-27 06:15:33 UTC  2026-10-27 06:21:34 UTC\n14  builditbelieveit.com  passed  2026-10-26 12:47:43 UTC  2026-10-26 13:00:33 UTC\n13  builditbelieveit.com  failed  2026-10-26 06:10:33 UTC  2026-10-26 06:40:36 UTC"} /-->

`wp sisyphus show <id>` prints the run and each step's status, times and message; [Triage a failed night](../troubleshooting.md#find-the-step-that-failed) shows one. `show` and `list` take `--format=json`, `csv` or `yaml`.

## Remove it

Deactivating keeps the run history and the maps, and cancels every queued Sisyphus action, the ticks and the nightly check, since nothing would answer them. Uninstalling drops all three tables.
