diff --git a/README.md b/README.md
index 21e6bf5..878849b 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ flowchart LR
u2["GitHub, over the API and git"]
u3["Dropbox, over the API"]
end
- sched["A scheduler
workflow_dispatch on a cron"] --> host
+ sched["katoptra/dispatch
workflow_dispatch, on a schedule"] --> host
subgraph job["One GitHub Actions job per run"]
host["The runner: task sync"] --> box["The toolbox image: task pipeline"]
end
@@ -94,7 +94,7 @@ The same path on a laptop and in Actions. On a laptop it starts at `task sync`.
```mermaid
sequenceDiagram
- participant D as A scheduler
+ participant D as katoptra/dispatch
participant W as sync.yml (reusable)
participant H as Host: task
participant O as op run
@@ -573,8 +573,9 @@ Three surfaces, all fed by the toolbox.
the failure path. A check on the mirror's schedule, with a grace that covers a queued
run plus a full one, emails when the grace passes without a ping. Nothing sends
`/start`, so the grace does not cap a run; pause the check before a first fill. Because
- nothing in a mirror starts a run, the check also watches the scheduler: a cron that
- stops firing looks exactly like a pipeline that stops finishing.
+ nothing in a mirror starts a run, the check also watches the scheduler,
+ [katoptra/dispatch](https://github.com/katoptra/dispatch): a tick that stops firing
+ looks exactly like a pipeline that stops finishing.
- **The job summary.** `report` appends one table to the Actions job page in three
layers, the toolbox's rows, the engine's, the mirror's, all counted from `.run/` and
never from the log, whose lines are dropped silently past a limit. It is the first
@@ -637,7 +638,8 @@ Two reusable workflows and one composite action. A mirror's callers are a few li
### `sync.yml`
-One mirror, one run. The caller is a `workflow_dispatch` that a scheduler triggers; it
+One mirror, one run. The caller is a `workflow_dispatch` that
+[katoptra/dispatch](https://github.com/katoptra/dispatch) triggers; it
passes `vars` through and inherits its repository secrets.
```mermaid
diff --git a/docs/superpowers/specs/2026-09-08-toolbox-library-design.md b/docs/superpowers/specs/2026-09-08-toolbox-library-design.md
index 08e6fb7..f40e310 100644
--- a/docs/superpowers/specs/2026-09-08-toolbox-library-design.md
+++ b/docs/superpowers/specs/2026-09-08-toolbox-library-design.md
@@ -20,9 +20,13 @@ is started, contained, secured, rendered and reported comes from here.
| Versioning | Semver tags `vX.Y.Z`; a release moves the floating `v` tag and pushes `-vX.Y.Z` and `-v` image tags | Consumers pin `v1` once, in the include URL and the image name |
| Secrets | `op.env` of `op://` references, resolved by `op run` on the host; names cross into the container, never values | Org rule; GitHub secrets still work through the `PASS` var |
| Workflows | Reusable `sync.yml` and `check.yml` under `.github/workflows`, a composite action that installs task and op at the lock's versions | A mirror's caller workflow is ten lines |
-| Clock | jshvn/dispatch triggers `workflow_dispatch` on each mirror; no `schedule:` in any mirror | One calendar, no 60-day cron shutoff |
+| Clock | katoptra/dispatch triggers `workflow_dispatch` on each mirror; no `schedule:` in any mirror | One calendar, no 60-day cron shutoff |
| The check | `task check` renders the whole pipeline inside the image with `--dry --force` and diffs it against the committed `render.txt` | Any change to what a mirror executes is a visible diff; this is the one check |
+The clock was jshvn/dispatch, a Cloudflare Worker, when this was written; since
+2026-09-21 it is [katoptra/dispatch](https://github.com/katoptra/dispatch), a Go binary on
+a systemd timer. The contract in the row is unchanged.
+
## The consumer contract
A mirror repository holds: