Skip to content

turnstile-spin: pivot SKILL to canonical siteverify#73

Merged
thomasgauvin merged 5 commits into
cloudflare:mainfrom
juleslemee:turnstile-spin-v2-compat
Jul 13, 2026
Merged

turnstile-spin: pivot SKILL to canonical siteverify#73
thomasgauvin merged 5 commits into
cloudflare:mainfrom
juleslemee:turnstile-spin-v2-compat

Conversation

@juleslemee

@juleslemee juleslemee commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

The Spin skill pivots from "deploy a managed siteverify Worker" to "wire canonical server-side siteverify in the customer's existing backend." This matches the design review on the V2 stratus MR (the deployed Worker reintroduces every problem it claimed to solve: URL-as-credential, CORS=* on the proxy, custom auth model on top of a system that already has one). Spin's job is now widget creation plus a curated agent prompt that points at https://challenges.cloudflare.com/turnstile/v0/siteverify directly.

What changes

SKILL.md is rewritten end-to-end. The 13-step wizard becomes a 12-step wizard: Step 9 (Worker deploy) collapses into the new Step 9 (wire widget + canonical siteverify in existing backend). The "things you must NOT do" list adds "do not deploy any extra infrastructure"; the recovery flow drops worker deploy and just fetches the secret to wire siteverify against the existing widget.

scripts/:

  • worker-deploy.shdeleted. No Worker to deploy.
  • auth-probe.sh — drops the Account.Workers Scripts:Edit probe. Only Account.Turnstile:Edit is required now.
  • validate.sh — rewritten. Drops the Worker /health and _worker metadata checks. Runs a dummy-token siteverify directly against challenges.cloudflare.com using the captured secret. Hostname check is now optional (skipped when CLOUDFLARE_API_TOKEN isn't set, so the dashboard-success-card flow can validate without manually creating a token).
  • widget-create.sh, fetch-secret.sh, persist-skill.sh — unchanged.

templates/worker/deleted in full (14 files, ~1,500 lines). No Worker template anymore.

references/ — all six framework references (vanilla-html, nextjs-app, nextjs-pages, astro, sveltekit, hugo) rewritten. Frontend snippet stays (widget embed via cf-turnstile div); backend snippet switches from "POST to YOUR_WORKER_URL" to canonical siteverify inside the customer's existing handler. Each reference now includes platform-specific siteverify patterns (Server Actions, Astro Actions, SvelteKit form actions, Pages Functions for static-site backends).

tests/validation.md — rewritten. Drops Worker URL probes; tests dummy-token siteverify + widget-domains check.

README.md — file-layout table updated; dropped the cloudflare/turnstile-siteverify reference (the managed Worker repo Spin used to deploy from).

What does not change

  • Telemetry marker turnstile-spin-v2 (set on every cf-turnstile div the skill writes). Older widgets stamped turnstile-spin-v1 from the legacy V1 agent flow stay tagged; the skill explicitly tells the agent to preserve that marker if encountered.
  • The recovery flow's secret-retrieval path (fetch-secret.sh). Unchanged.
  • The persistence flow (saves the bundle into .claude/skills/, .cursor/rules/, etc. so the agent can re-load it on follow-up tasks).

What is intentionally not yet in this MR

Two forward-direction tracks are scoped but not landed:

  • wrangler turnstile subcommands — would replace the agent's manual API-token setup with wrangler login's OAuth token. Needs Workers SDK team buy-in. SKILL.md will get a wrangler branch in Step 2 once shipped.
  • Workers env.TURNSTILE.verify binding — would replace the canonical fetch idiom inside a Worker backend with a typed call. Needs Workers Runtime team RFC. SKILL.md will get a Workers-backend variant in Step 9 once shipped.

Both are absent from this MR by design: the docs should not reference features that don't exist yet.

Related MRs

  • cloudflare/cloudflare-docs#31517 — pairs with this change; rewrites the user-facing developers.cloudflare.com/turnstile/spin page.
  • cloudflare/fe/stratus!39261 — pivots the V2 dashboard dialog to consume this skill.

Diff stats

30 files changed, +431 / -2,192. Net −1,761 lines.

Verification

  • All references/*.md and tests/validation.md re-read end-to-end; no remaining mentions of "Worker URL", "deploy", or "worker-deploy.sh".
  • Step references inside SKILL.md cross-checked: every "Step N (X)" reference matches the new 12-step numbering.
  • Spot-checked the inlined heredocs in scripts/*.sh for correct shell escaping.

jules lemee added 2 commits June 17, 2026 16:24
This skill stays as the v1 agent-led path; the dashboard's 'Set up with
Spin' button is the v2 parallel path. Two small SKILL.md prose edits so
the agent does the right thing when it encounters a v2-created widget:

- Recovery flow: dashboard's Deployment column flips on either v1 or
  v2 marker. If the user is recovering a dashboard-created widget, a
  Worker is likely already deployed in the account; confirm before
  redeploying, or skip to Step 10 to wire the frontend against the
  existing Worker URL.
- Telemetry marker: this skill always writes v1, but preserve v2 if
  you encounter it on an existing widget. Both feed the same
  account-level activation telemetry.

No changes to scripts, references, templates, or tests. Fresh widgets
created via this skill keep the turnstile-spin-v1 marker.
Drop the Worker deploy step from the wizard. Spin's job is now
widget creation plus a curated agent prompt that wires canonical
server-side siteverify into the customer's existing backend.

Changes:
- SKILL.md rewritten end-to-end (167 -> 211 lines)
- worker-deploy.sh deleted
- templates/worker/ deleted (14 files)
- auth-probe.sh drops Workers Scripts scope check
- validate.sh rewritten to dummy-token siteverify + optional hostname check
- All 6 framework references rewritten for canonical siteverify
- README.md + tests/validation.md updated

Pairs with cloudflare/cloudflare-docs and cloudflare/fe/stratus !39261.
juleslemee pushed a commit to juleslemee/workers-sdk that referenced this pull request Jul 1, 2026
Adds `wrangler turnstile widget create | list | get | update | delete`
so developers and AI coding agents can provision Cloudflare Turnstile
widgets from the CLI instead of dashboard-only.

Modelled on the hyperdrive command structure (createNamespace +
createCommand, single-purpose files per subcommand, cfetch client
layer). Requests the existing `challenge-widgets.write` OAuth scope
during `wrangler login`; the scope was added to wrangler's prod OAuth
client allowlist via cloudflare/iam/terraform-internal-oauth-clients
!137 (already applied).

Behaviour notes:
- `create` prints sitekey + secret + a backend-agnostic siteverify
  pointer (does not prescribe Workers as the backend).
- `update` does GET-then-merge-then-PUT since Turnstile's PUT
  requires the full body; strips `secret` from output to avoid an
  incidental leak when the user only intended to rename.
- `delete` prompts for confirmation (`--skip-confirmation`/`-y`
  bypasses); `fallbackValue: false` in non-interactive contexts.
- `create`/`list`/`update` accept `--json`; `get` is always JSON.
  Banner is suppressed with `--json` and in CI so output is pipeable.
- `--domain` accepts comma-separated values in addition to repeated
  flags.
- No new Cloudflare TypeScript SDK dependency (matches the hyperdrive
  pattern in the same repo); the surface can be migrated later.

19 unit tests via msw. Live-verified end to end against the API using
both an API token and the OAuth flow with the newly-allowlisted scope.

Companion changes (out of scope here):
- cloudflare/skills#73 - canonical SKILL.md rewrite for Turnstile Spin
- cloudflare/cloudflare-docs#31517 - public docs page
- stratus !39261 - dashboard Spin Lite dialog

Bach and OAuth-client sides:
- `challenge-widgets.write` OAuth scope was already registered in
  bach (derived from the `challenge_widgets_write` api_tokens role);
  no bach change was needed.
- cloudflare/iam/terraform-internal-oauth-clients !137 added
  `challenge-widgets.write` to the wrangler prod client's scopes
  list (applied + merged).
juleslemee pushed a commit to juleslemee/workers-sdk that referenced this pull request Jul 1, 2026
Adds `wrangler turnstile widget create | list | get | update | delete`
so developers and AI coding agents can provision Cloudflare Turnstile
widgets from the CLI instead of dashboard-only.

Modelled on the hyperdrive command structure (createNamespace +
createCommand, single-purpose files per subcommand, cfetch client
layer). Requests the existing `challenge-widgets.write` OAuth scope
during `wrangler login`; the scope was added to wrangler's prod OAuth
client allowlist via cloudflare/iam/terraform-internal-oauth-clients
!137 (already applied).

Behaviour notes:
- `create` prints sitekey + secret + a backend-agnostic siteverify
  pointer (does not prescribe Workers as the backend).
- `update` does GET-then-merge-then-PUT since Turnstile's PUT
  requires the full body; strips `secret` from output to avoid an
  incidental leak when the user only intended to rename.
- `delete` prompts for confirmation (`--skip-confirmation`/`-y`
  bypasses); `fallbackValue: false` in non-interactive contexts.
- `create`/`list`/`update` accept `--json`; `get` is always JSON.
  Banner is suppressed with `--json` and in CI so output is pipeable.
- `--domain` accepts comma-separated values in addition to repeated
  flags.
- No new Cloudflare TypeScript SDK dependency (matches the hyperdrive
  pattern in the same repo); the surface can be migrated later.

19 unit tests via msw. Live-verified end to end against the API using
both an API token and the OAuth flow with the newly-allowlisted scope.

Companion changes (out of scope here):
- cloudflare/skills#73 - canonical SKILL.md rewrite for Turnstile Spin
- cloudflare/cloudflare-docs#31517 - public docs page
- stratus !39261 - dashboard Spin Lite dialog

Bach and OAuth-client sides:
- `challenge-widgets.write` OAuth scope was already registered in
  bach (derived from the `challenge_widgets_write` api_tokens role);
  no bach change was needed.
- cloudflare/iam/terraform-internal-oauth-clients !137 added
  `challenge-widgets.write` to the wrangler prod client's scopes
  list (applied + merged).
juleslemee pushed a commit to juleslemee/workers-sdk that referenced this pull request Jul 1, 2026
Adds `wrangler turnstile widget create | list | get | update | delete`
so developers and AI coding agents can provision Cloudflare Turnstile
widgets from the CLI instead of dashboard-only.

Modelled on the hyperdrive command structure (createNamespace +
createCommand, single-purpose files per subcommand, cfetch client
layer). Requests the existing `challenge-widgets.write` OAuth scope
during `wrangler login`; the scope was added to wrangler's prod OAuth
client allowlist via cloudflare/iam/terraform-internal-oauth-clients
!137 (already applied).

Behaviour notes:
- `create` prints sitekey + secret + a backend-agnostic siteverify
  pointer (does not prescribe Workers as the backend).
- `update` does GET-then-merge-then-PUT since Turnstile's PUT
  requires the full body; strips `secret` from output to avoid an
  incidental leak when the user only intended to rename.
- `delete` prompts for confirmation (`--skip-confirmation`/`-y`
  bypasses); `fallbackValue: false` in non-interactive contexts.
- `create`/`list`/`update` accept `--json`; `get` is always JSON.
  Banner is suppressed with `--json` and in CI so output is pipeable.
- `--domain` accepts comma-separated values in addition to repeated
  flags.
- No new Cloudflare TypeScript SDK dependency (matches the hyperdrive
  pattern in the same repo); the surface can be migrated later.

19 unit tests via msw. Live-verified end to end against the API using
both an API token and the OAuth flow with the newly-allowlisted scope.

Companion changes (out of scope here):
- cloudflare/skills#73 - canonical SKILL.md rewrite for Turnstile Spin
- cloudflare/cloudflare-docs#31517 - public docs page
- stratus !39261 - dashboard Spin Lite dialog

Bach and OAuth-client sides:
- `challenge-widgets.write` OAuth scope was already registered in
  bach (derived from the `challenge_widgets_write` api_tokens role);
  no bach change was needed.
- cloudflare/iam/terraform-internal-oauth-clients !137 added
  `challenge-widgets.write` to the wrangler prod client's scopes
  list (applied + merged).
juleslemee pushed a commit to juleslemee/workers-sdk that referenced this pull request Jul 2, 2026
Adds `wrangler turnstile widget create | list | get | update | delete`
so developers and AI coding agents can provision Cloudflare Turnstile
widgets from the CLI instead of dashboard-only.

Modelled on the hyperdrive command structure (createNamespace +
createCommand, single-purpose files per subcommand, cfetch client
layer). Requests the existing `challenge-widgets.write` OAuth scope
during `wrangler login`; the scope was added to wrangler's prod OAuth
client allowlist via cloudflare/iam/terraform-internal-oauth-clients
!137 (already applied).

Behaviour notes:
- `create` prints sitekey + secret + a backend-agnostic siteverify
  pointer (does not prescribe Workers as the backend).
- `update` does GET-then-merge-then-PUT since Turnstile's PUT
  requires the full body; strips `secret` from output to avoid an
  incidental leak when the user only intended to rename.
- `delete` prompts for confirmation (`--skip-confirmation`/`-y`
  bypasses); `fallbackValue: false` in non-interactive contexts.
- `create`/`list`/`update` accept `--json`; `get` is always JSON.
  Banner is suppressed with `--json` and in CI so output is pipeable.
- `--domain` accepts comma-separated values in addition to repeated
  flags.
- No new Cloudflare TypeScript SDK dependency (matches the hyperdrive
  pattern in the same repo); the surface can be migrated later.

19 unit tests via msw. Live-verified end to end against the API using
both an API token and the OAuth flow with the newly-allowlisted scope.

Companion changes (out of scope here):
- cloudflare/skills#73 - canonical SKILL.md rewrite for Turnstile Spin
- cloudflare/cloudflare-docs#31517 - public docs page
- stratus !39261 - dashboard Spin Lite dialog

Bach and OAuth-client sides:
- `challenge-widgets.write` OAuth scope was already registered in
  bach (derived from the `challenge_widgets_write` api_tokens role);
  no bach change was needed.
- cloudflare/iam/terraform-internal-oauth-clients !137 added
  `challenge-widgets.write` to the wrangler prod client's scopes
  list (applied + merged).
Jules Lemee added 2 commits July 9, 2026 11:48
Wrangler 4.109 ships an alpha 'turnstile widget create/list/get/update/
delete' subcommand tree that talks to the same Cloudflare API as the
bundled widget-create.sh helper. When wrangler is installed with the
turnstile subcommand available, use it directly; otherwise fall back to
the curl-based script. Also updates Step 2 (CLI check) to name the
preference explicitly.

Server-side, dashboard-created widgets tag deployed_via=dashboard,
wrangler-created widgets tag deployed_via=wrangler, and curl-script
widgets tag deployed_via=api. The agent only needs to write the
turnstile-spin-v2 marker; the deployment channel is inferred from the
User-Agent/host on the create call.
…ompat

# Conflicts:
#	skills/turnstile-spin/SKILL.md
@juleslemee juleslemee marked this pull request as ready for review July 10, 2026 16:22
@thomasgauvin thomasgauvin merged commit 7021530 into cloudflare:main Jul 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants