⎿ { batches: [ b_8f3a… → 3 steps ok ] } — proof, by ss:// ref + fingerprint
Done. Three secrets live in prod. Nobody pasted anything; I never saw a value.
Secret Shuttle Approval
Secret Shuttle
Push 3 secrets from batch b_8f3a… → vercel:production, supabase:<ref>
Environmentproduction
Destinationsvercel · supabase
Agentag_2c1…
scene 01 — claude code · ~/projects/myapp
~/projects/myapp — claude
>let's deploy this to prod. you'll need to set the STRIPE_WEBHOOK_SECRET and a couple of vercel env vars
I can wire up the Vercel deployment, but I shouldn't put production secrets into my context.
Once Vercel is deployed, I'll list the env var keys you need to set. You'll have to paste the actual values into the Vercel dashboard (or share them with me only if you accept that they'll appear in this conversation).
>…there's gotta be a better way
scene 02 — claude code · reading the skill
~/projects/myapp — claude
>wait — I heard about secret-shuttle. set it up so I don't have to babysit secrets in chat
⏺WebFetch(raw.githubusercontent.com/.../SKILL.md)
⎿ Fetched 3,481 bytes — "agent operating manual"
Got it. Quick model:
• Local daemon owns a vault, unlocked by a passphrase
you (not me) type into a local web window.
• I work through refs like
ss://stripe/prod/STRIPE_WEBHOOK_SECRET — never the raw value.
• Production actions open an approval window in your browser. You approve there. No CLI bypass.
• For Vercel, GitHub Actions, Cloudflare, Supabase I use shipped templates — the secret reaches the CLI on stdin or a 0600 env-file. Never argv, never env.
Want me to install it?
>yes
scene 03 — installing · unlocking the vault
~/projects/myapp — claude
⏺Bash(npx secret-shuttle init)
⎿ { "daemon": "started", "pid": 8421 }
Opening passphrase window in your browser…
(I cannot read the passphrase. Type it into the window →)
waiting
Unlock Secret Shuttle
Create a vault passphrase
This protects every secret you'll store. The CLI never sees it. Lose it and the vault is unrecoverable.
scene 04 — installing the agent skill
~/projects/myapp — claude
init already wrote my skill — .claude/skills/secret-shuttle/SKILL.md (3,481 bytes; it detected a Claude project).
Skill loaded. From here I'll follow the protocol — status first, prefer template over browser, never log raw values, surface manual_recovery_required if the daemon can't prove the secret is gone.
Ready for the next request.
>
scene 05 — first quick win · generate + push to vercel
~/projects/myapp — claude
>generate an INTERNAL_CRON_SECRET for prod and add it to vercel
⏺Bash(secret-shuttle status --json)
⎿ daemon_reachable: true · unlocked: true
agentic_browser.available: false (not needed)
⏺Bash(secret-shuttle secrets set \
--name INTERNAL_CRON_SECRET --env production \
--kind random_32_bytes \
--allow-domain vercel.com \
--allow-action use_as_stdin)
⎿ approval_required → opening UI
…waiting for approval (1 of 2)
Secret Shuttle Approval
✓ approved
Secret Shuttle
Generate and store a new secret ss://local/prod/INTERNAL_CRON_SECRET (production)
Environmentproduction
Injectable intovercel.com
Action scopeuse_as_stdin
Secret Shuttle Approval
Secret Shuttle
Run template vercel-env-add with secret ss://local/prod/INTERNAL_CRON_SECRET
Environmentproduction
Templatevercel-env-add
param: nameINTERNAL_CRON_SECRET
param: environmentproduction
Technical details
Binary/usr/local/bin/vercel
Binary sha2561b4f…0e7d
Deliverystdin
scene 06 — daemon-owned chrome · marking the reveal + field
⏺Bash(secret-shuttle browser mark pick --as reveal-btn)
⎿ (click the reveal button →)
▸ marked: reveal-btn
⏺Bash(... mark pick --as webhook-secret-field)
⎿ ▸ marked: webhook-secret-field
ready for reveal-capture
Stripe Dashboard — daemon-managed Chrome
‹›
🔒dashboard.stripe.com/webhooks/we_1NaKx2…
⟳
S
Stripe
Developers › Webhooks › we_1NaKx2…
Endpoint signing secret
Stripe signs the webhook event body with this secret. Verify the signature before processing.
Signing secretwhsec_••••••••••••••••••••••••••••
Signing secrets begin with whsec_ and are 38 characters.
webhook-secret-field
reveal-btn
scene 07 — reveal-capture · daemon takes the wheel
claude
⏺Bash(secret-shuttle reveal-capture \
--name STRIPE_WEBHOOK_SECRET \
--env production --source stripe \
--reveal-handle reveal-btn \
--field-handle webhook-secret-field \
--allow-domain dashboard.stripe.com \
--allow-domain vercel.com)
⎿ approval_required → opening UI
🔒 blind mode active
agent observation suspended
Stripe — daemon-managed Chrome
‹›
🔒dashboard.stripe.com/webhooks/we_1NaKx2…
⟳
S
Stripe
Developers › Webhooks › we_1NaKx2…
Endpoint signing secret
Signing secretwhsec_••••••••••••••••••••••••••••
BLIND · agent observation suspended
Secret Shuttle Approval
Secret Shuttle
Click reveal-btn on dashboard.stripe.com, capture into ss://stripe/prod/STRIPE_WEBHOOK_SECRET (from webhook-secret-field, mode field), hide it, and auto-resume only if the secret is verified gone from the daemon-observable DOM.
Environmentproduction
URL hostdashboard.stripe.com
Injectable intostripe.com, vercel.com
Capture modefield
Technical details
Browser targetpage/9c…f2
Reveal fpfp:b3a…d2
Field fpfp:f7e…11
Approving authorizes auto-resume only if the secret is verified gone from the daemon-observable DOM (capture and absence checks pass). If not, blind mode stays on.
scene 08 — inject-submit · daemon writes, clicks save, hands back
claude
Captured. value_visible_to_agent: false. Navigating to Vercel env vars…
Inject ss://stripe/prod/STRIPE_WEBHOOK_SECRET into value-field on vercel.com, click save-button, wait for success, and auto-resume only if the secret is verified gone from the daemon-observable DOM.
Environmentproduction
URL hostvercel.com
Injectable intostripe.com, vercel.com
Success markerEnvironment Variable Added
Technical details
Browser targetpage/8a…21
Field fpfp:c91…83
Submit fpfp:5e2…07
Approving authorizes auto-resume only if the secret is verified gone from the daemon-observable DOM (success and absence checks pass). If not, blind mode stays on.
scene 09 — all green · the loop closes
~/projects/myapp — claude
Injected and submitted. absence_proof: passed. Observation auto-resumed.
⏺Bash(secret-shuttle status)
⎿ daemon: running (pid 8421)
vault: unlocked
browser: ready (proxy active)
policy: ok (allow-list scoped)
local files: ok (0600)
agentic flows: available
Done.
Stripe webhook signing secret is now in Vercel production env. You never saw the value. I never saw the value. It never appeared in any argv, env var, log line, or chat transcript.