尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Mint per-user, revocable Claude/agent skills from a Cloudflare Worker — the API secret bakes itself into the skill at download time. HMAC-derived keys, never stored; one-integer revocation; no app-level auth.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Mint per-user, revocable Claude skills from your own Cloudflare Worker — the secret bakes itself into the skill at download time.
Live, against stash-demo.hsieh-ting-lin.workers.dev: the credential is baked in (never typed), the CLI just works, then revoking it server-side kills the already-downloaded skill on the spot.查看完整 README ↗Mint per-user, revocable Claude skills from your own Cloudflare Worker — the secret bakes itself into the skill at download time.
Live, against stash-demo.hsieh-ting-lin.workers.dev: the credential is baked in (never typed), the CLI just works, then revoking it server-side kills the already-downloaded skill on the spot.
A tiny, self-contained reference implementation of a paradigm: instead of
pasting an API key into every agent and every machine, your server mints a
personalized Agent Skill
on download — a .skill bundle with a .env already baked in. The agent
unzips it and immediately knows your infra, authenticated, with a credential
that is scoped to one person, derived not stored, and revocable with a single
integer.
Runs free on Cloudflare Workers + KV + D1. No app-level auth code — Cloudflare Access handles identity; this repo handles minting.
Every time you start a new project, your agent doesn't know your private infra. So you do one of two bad things:
Static secrets don't fit a world where agents are the API consumers. You want to hand each agent (each person, each laptop) its own credential, know who is calling, and be able to kill exactly one of them without rotating everyone.
The skill carries its own secret, and the server mints it per user.
┌─────────────┐ Access login ┌──────────────────────────┐
│ browser │ ────────────────▶ │ Worker: GET /api/me/skill│
│ (console) │ │ bakes .env { base,key, │
└─────────────┘ ◀── stash.skill ─│ email } + zips skill/ │
(zip w/ .env) └──────────────────────────┘
│ unzip into ~/.claude/skills/
▼
┌─────────────┐ Bearer key + ┌──────────────────────────┐
│ any agent │ X-User-Email │ Worker: /api/kv/* │
│ (stash CLI)│ ────────────────▶ │ re-derives key, verifies │
└─────────────┘ ◀── data ────────│ (the ONLY gate, public) │
└──────────────────────────┘
The key is never stored anywhere:
key = "stashk_" + base64url( HMAC-SHA256( SERVER_SECRET, `${email}:${version}` ) )
SERVER_SECRET is one global Worker secret.version is a per-user integer in D1 — the only per-user state.(secret, email, version) and constant-time compares. Nothing to look up, nothing to leak.| Static API key | skill-with-secret |
|---|---|
| Stored in DB / env → leaks if either leaks | Derived, never stored. Leak the whole DB → zero usable keys |
| One key for everyone | One key per person, bound to their email by HMAC |
| Revoke = rotate the shared key = break everyone | Revoke one user by bumping their integer version |
| Agent must be told the URL + key by hand | Baked into the skill at download — agent just works |
| Can't tell who's calling | Every call carries a verified email |
| Anyone can probe "is this email a member?" | Anti-enumeration: unknown email and bad key are indistinguishable, with uniform timing |
This is the right shape for the agent era: a credential that is minted, self-installing, attributable, and individually revocable — with the auth boundary kept at the edge (Cloudflare Access), not reimplemented in your app.
A public, no-login demo running the exact same Worker with DEMO_MODE=1, which
swaps Cloudflare Access for a throwaway per-browser identity. Open it, download a
real .skill, and rotate it to watch the old one get revoked — no account
needed.
Stand up your own in one command (wrangler login first):
pnpm setup:demo # creates D1 + KV, sets the secret, deploys — prints the URL
CI can also auto-deploy on every push to main
(.github/workflows/deploy-demo.yml). Details in docs/DEMO.md.
It's a sandbox: throwaway secret, disposable KV, ephemeral identities. The real paradigm keeps Access in front (see Quickstart).
pnpm install
cp wrangler.toml.example wrangler.toml # fill in ids (see docs/SETUP.md)
wrangler secret put STASH_KEY_SECRET # openssl rand -hex 32
pnpm db:migrate:remote
pnpm deploy
Then put the minting routes behind Cloudflare Access (via the Zero Trust
dashboard, or any CLI that drives the Access API), open the console at your
Worker's URL, and click Download stash.skill. Full walkthrough:
docs/SETUP.md.
After unzipping the download into ~/.claude/skills/stash/:
stash put demo "it works" # ① the minted skill talks to your Worker
stash get demo # → it works
# …click "Rotate key" in the console…
stash get demo # → 401: this skill was revoked ← the whole point
# …re-download, unzip, retry…
stash get demo # → it works again
That rotate → 401 → re-download arc is the entire value proposition in three
commands: a credential you can kill and re-mint, per person, in one click.
There's also a browser path — the console page (/) can put/get/ls
against the protected resource live, so you can see the loop without a terminal.
worker/
index.ts # route wiring: public API (bearer) vs minting (Access)
lib/apikey.ts # HMAC key derivation + the anti-enumeration middleware ★
lib/access.ts # Cloudflare Access JWT verify (+ localhost dev bypass)
routes/resource.ts # the example protected resource — a per-user KV stash
routes/mint.ts # /key, /key/rotate, /skill (zips the bundle + baked .env)
console.ts # the self-contained demo page
skill/ # SOURCE OF TRUTH for the minted skill (SKILL.md + CLI)
scripts/gen-bundle.mjs# snapshots skill/ into the Worker (it has no filesystem)
migrations/0001_init.sql # users(email, key_version) — the salt, never the key
Want this for your infra? Replace routes/resource.ts with your own
endpoints and rewrite skill/ to drive them. The minting + auth machinery
(apikey.ts, mint.ts, access.ts, gen-bundle.mjs) is the reusable core —
that's the part you paste into every project.
SubtleCrypto.timingSafeEqual over fixed-
length digests).STASH_KEY_SECRET is unset.401 and run the same
HMAC + compare work, so membership can't be enumerated by response or timing.key_version is immediate and total for that user, and
invisible to everyone else.MIT — see LICENSE.