Skip to main content
An index is only as good as last night’s docs. This recipe runs on a Runcrate schedule: every night at 03:00 London time a job starts, fetches every page in your sitemap, embeds only the ones whose text changed since the last run, and posts “3 changed, 1 removed” to Slack. The index lives on a volume, so the job’s machine can be thrown away. The first run over 215 pages cost a quarter of a cent; a night with no changes costs nothing in embeddings.

Build it in your project

Paste this line into your agent (Claude Code, Codex, Cursor, OpenCode, Cline). It sets up your key, then builds the pipeline in your project:

The code

One file per language. Both read RUNCRATE_API_KEY from the environment; nothing secret is in the code.

What the proof run cost

The Python file run by hand twice on Runcrate’s docs sitemap (215 pages), then --schedule against a fresh 10 GB volume. The schedule was validated and created, listed with its next run (03:00 BST the next day), and deleted with the volume before it ran. Measured on 2026-10-23 against api.runcrate.ai; costs are what the account was billed, read from each response’s X-LLM-Cost header or usage.cost. The TypeScript file: night 1 in 91.6 s for $0.0026, night 2 in 8.8 s for $0, and --schedule created the same schedule with image: node:22, then deleted. A scheduled run itself was not started in the proof; on the night it starts a job on the GPU in the spec, billed by the minute it runs (an A4000 is listed at $1.04 an hour on the day).

Scale it

  • Several sites: one schedule each, or one job that loops over sitemaps.
  • Bigger indexes: split pages into sections (as in the docs Q&A recipe) and keep vectors in a vector database on an instance.
  • Put RUNCRATE_API_KEY, WEBHOOK_URL and WEBHOOK_SECRET in your environment’s secrets: every job the schedule starts gets them, and nobody can read them back from the schedule.
  • A failed or paused schedule sends schedule.failed or schedule.paused to your workspace webhooks.

Gotchas found in the proof run

  • Schedules have no --code: the command fetches the script from a URL you control (curl ... -o /tmp/nightly.py), and the volume holds only the index.
  • The job only calls the API, so pick the lowest-priced GPU in NIGHTLY_GPU; every scheduled job needs one today.
  • runcrate schedule delete and volumes delete ask for confirmation, and with no terminal they wait: pipe echo y in scripts.
  • Make volumes with runcrate volumes create. The empty-state message suggests runcrate storage create, which is the old name.