Skip to content

[Turnstile] Add Spin docs page#31195

Open
juleslemee wants to merge 8 commits into
cloudflare:productionfrom
juleslemee:turnstile-spin-docs
Open

[Turnstile] Add Spin docs page#31195
juleslemee wants to merge 8 commits into
cloudflare:productionfrom
juleslemee:turnstile-spin-docs

Conversation

@juleslemee

Copy link
Copy Markdown

Adds the canonical docs page for Turnstile Spin at /turnstile/spin/.

What's on the page

  • A "Quick start (humans)" copy-pasteable prompt that inlines the full Spin skill so anyone using an AI coding agent (Claude Code, Cursor, Codex, OpenCode, Copilot) can run it from anywhere without first installing the skill.
  • The agent-readable Spin skill: when to load, hard scope boundaries (no email/SMS, no custom Worker, no Pages duplication, etc.), recovery flow against existing widgets, the 9-step wizard, telemetry marker convention.
  • "What happens after you paste the prompt": narrated walkthrough so humans reading the page know what to expect.
  • Migrating from reCAPTCHA / hCaptcha section.
  • Per-framework code examples + edge cases.

Also adds the matching plain-markdown copy at public/turnstile/spin/index.md so the agent's Step 8 (persist skill) can fetch it via curl.

Companion PRs

Internal context

Tier 3 launch tracked in NC-8209. PRD: https://jira.cfdata.org/browse/NC-8209

Validation: `pnpm run check` passes on the spin MDX. No type errors or broken internal links specific to this page.

Adds /turnstile/spin/ documenting the Turnstile Spin agent skill: how to invoke it, what it does end-to-end (widget create, Worker deploy, frontend snippets, validation), the full inlined SKILL.md prompt for paste-into-agent flows, recovery flow, edge cases, and migration from reCAPTCHA/hCaptcha.

Companion to the skill PR at cloudflare/skills#58.

Internal PRD: https://jira.cfdata.org/browse/NC-8209
@cloudflare-docs-bot

cloudflare-docs-bot Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review

⏸️ Automatic reviews for this PR are paused.

This PR has already received 2 automatic reviews. To run another review, a codeowner can comment /review or /full-review.

Tip: Keep PRs in draft mode until they are ready for review — the bot skips draft PRs automatically.

jules lemee added 4 commits June 3, 2026 11:23
Sync to the refactored skill bundle. The MDX page's inlined paste-into-agent prompt now consists of the (much shorter) SKILL.md orchestration + a bootstrap section that writes the 6 helper scripts under /tmp/turnstile-spin-scripts/. Total prompt length is comparable to before; the architecture is cleaner because the agent now branches on structured JSON output from deterministic scripts instead of inline bash interpretation.

Companion to cloudflare/skills#58.
Per Marina's review feedback, add the Beta badge to the Spin landing page (matching the multi-cloud-networking pattern):

- title gets the "(beta)" suffix
- sidebar.badge.text set to "Beta"
Move spin/index.mdx to spin.mdx so the page is a flat sidebar
sibling of Plans, Concepts, etc., instead of a collapsible group
with a single child. Shorten sidebar.label from
"Spin (one-shot setup)" to "Spin".
Addresses 5 findings from Miguel's review:

1. Resolved wrangler login contradiction. The skill prose said "don't
   use wrangler login because OAuth lacks Account.Turnstile:Edit" but
   the human walkthrough, the troubleshooting table, and the 403
   recovery section all instructed the agent to run wrangler login.
   Replaced with token-creation guidance everywhere.

2. Fixed multi-account handling in auth-probe.sh. The script hardcoded
   .accounts[0].id and treated any user-set CLOUDFLARE_ACCOUNT_ID
   pointing at a non-first account as a mismatch. It now checks
   membership in the accounts array, emits a new multiple_accounts
   status when the token covers >1 accounts and the env var is unset,
   and only uses [0] when there is exactly one account.

3. Added a Workers scope probe. The script docstring claimed status:ok
   meant both Turnstile and Workers scope were present, but the code
   only hit GET /challenges/widgets. Added a second probe against
   /workers/scripts that emits missing_workers_scope when the token
   lacks Account.Workers Scripts:Edit, preventing widget creation
   followed by Worker deploy failure.

4. Fixed wrangler secret put without --name in the human walkthrough.
   The script uses --name correctly; the docs prose did not, so the
   secret would land on wrangler.toml's default worker name. Also
   reordered: deploy first (so the named Worker exists), then put the
   secret on it. Made set_secret failure fatal in worker-deploy.sh
   (was previously swallowed; the script could emit status:ok with
   no secret on the Worker).

5. Fixed jq shape mismatch in curl fallback. Was '.account.id'
   (singular, wrong); now '.accounts[0].id' (matches wrangler whoami
   --json output and the helper script).
@migueldemoura

migueldemoura commented Jun 4, 2026

Copy link
Copy Markdown
Member

Skill being checked elsewhere, else double-checked by @marinaelmore (probably needs to be added as a CO)

jules lemee added 3 commits June 4, 2026 11:16
Two more findings from review:

1. The framework code examples (Vanilla HTML, Next.js App, Next.js Pages,
   Astro, SvelteKit, Hugo) set form action / fetch directly to the Spin
   Worker URL. The Worker is a siteverify proxy: it validates the token
   and returns { success } but does not persist form data. Pointing the
   form at the Worker means every signup or subscribe submission is
   silently dropped. Rewrote all six tabs to gate-then-forward: POST the
   token to the Worker, check success, then submit to the user's real
   endpoint (/api/subscribe placeholder). Updated the prose at Step 6 to
   call out the contract and the failure mode explicitly.

2. worker-deploy.sh captured only stderr from npx wrangler deploy
   (2>"$deploy_log"), then grepped the file for the workers.dev URL.
   Wrangler emits the success URL on stdout in current versions, so the
   script could deploy successfully and still emit url_parse_failed.
   Capture both streams (>"$deploy_log" 2>&1).
Comprehensive sweep before another reviewer round. Findings:

P1 — would fail at the shell or violate stated contracts:
1. Removed all references to `wrangler turnstile` subcommand (does
   not exist in current wrangler; the recommended Step 4 path was
   the API curl; Step 7c hostname check and recovery flow now also
   use the API directly).
2. fetch-secret.sh now returns `clearance_level` and `domains` so
   the recovery flow's pre-clearance scope check is actually
   implementable.
3. Dropped the `?widget=<id>` URL trigger from the recovery flow —
   nothing in the skill parsed it. Recovery now uses a verbal
   trigger (user tells the agent they have an existing sitekey).
4. validate.sh hits `/health` (not `/`) so the diagnostic stops
   lying about what was checked and breaks predictably if the
   Worker template ever differentiates the two routes.
7. Rewrote Next.js (App + Pages) and SvelteKit examples so they
   delegate to a clearly-marked `/* existing submit logic */`
   placeholder instead of replacing the user's handler with a
   hardcoded `fetch('/api/subscribe', ...)`. Updated the prose
   contract to spell out both failure modes (don't replace the form
   target, don't replace the existing handler).

P2 — clear customer impact:
5. worker-deploy.sh URL parser now falls back from the workers.dev
   regex to a broader URL match (excluding cloudflare.com hosts) so
   custom domains and Workers for Platforms don't return
   url_parse_failed on a successful deploy.
6. auth-probe.sh reworded the Workers scope probe comment to be
   honest about its best-effort nature (Custom Token UI does not
   guarantee Read alongside Edit).
9. persist-skill.sh now installs the canonical bundle (SKILL.md +
   scripts/ + references/) via degit from cloudflare/skills instead
   of writing the inlined bootstrap version, so persisted skills can
   re-run without falling back to the /tmp/ bootstrap path.
11. Wizard flow Step 5 documents the set_secret_failed recovery path
    (was only in the conversation-flow Step 9).
12. validate.sh asserts the `_worker` metadata field is present in
    the dummy-siteverify response (Step 7b promised this assertion
    but the script never checked).
13. Standardised on `<worker_name from worker-deploy.sh output>` in
    edge case tables; removed the $WORKER_NAME env var reference
    that was never exported.
14. Migration substitutions: tell the agent to *delete* the manual
    hidden input (Turnstile renders `cf-turnstile-response` itself),
    not rename it. Documented that the Worker template now accepts
    the reCAPTCHA-style `response` field name for drop-in backend
    migration. "Hash suffix" reworded to "random suffix" with
    `openssl rand -hex 3`.
16. worker-deploy.sh `set_secret` failure now captures wrangler's
    stderr and includes a `detail` field in the error JSON instead
    of swallowing it.
- Replaced the timestamp-tail Worker-name suffix with openssl rand
  (3 bytes hex = 6 chars), falling back to the timestamp tail if
  openssl is absent. Docs prose already said "hash"; the script
  body now matches.
- Step 3 parallel-work hint now scopes itself to option 3 (paste in
  chat). Options 1 (export + relaunch) and 2 (save to file +
  relaunch) restart the agent session and lose any pre-fetched
  state, so the doc no longer tells the agent to do work that gets
  thrown away.
@migueldemoura migueldemoura enabled auto-merge (squash) June 5, 2026 16:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants