[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7516PC7GZGW9DMBETTKDBE1":3,"skill-same:01M7516PC7GZGW9DMBETTKDBE1":49},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":26,"commitSha":27,"skillDirectory":28,"forksCount":29,"repositoryHtmlUrl":30,"repositoryHomepageUrl":31,"ownerHtmlUrl":32,"ownerBlogUrl":31,"ownerDescription":33,"updatedAt":34,"install":35,"resources":48},"01M7516PC7GZGW9DMBETTKDBE1","oauth-flow",null,"Implements OAuth 2.0 and OpenID Connect correctly - authorization code with PKCE, client credentials for machine-to-machine, state and nonce, exact redirect URI matching, safe token storage, refresh rotation with reuse detection, scopes, ID token validation via JWKS, and logout - aligned with RFC 9700 (OAuth Security BCP) and RFC 7636 (PKCE). Use when someone asks \"add Google or Microsoft login\", \"implement OAuth in our app\", \"where should I store the refresh token\", \"how do I validate an ID token\", or is wiring an app to an identity provider or third-party API. Do NOT use for auditing a whole application's security posture - use security-audit instead; for line-level review of an auth diff, use secure-code-review.","SkillMedev\u002Fskills","SkillMedev","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F298078254?v=4","01M74ZSGTQ918CB0VXW4EG3RMX","SkillMe","01M74ZSGVBT497NA95CBT8JTY4",25,"MIT","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Foauth-flow\u002FSKILL.md",[],[],"2026-11-11 18:11:01",false,"---\nname: oauth-flow\ndescription: Implements OAuth 2.0 and OpenID Connect correctly - authorization code with PKCE, client credentials for machine-to-machine, state and nonce, exact redirect URI matching, safe token storage, refresh rotation with reuse detection, scopes, ID token validation via JWKS, and logout - aligned with RFC 9700 (OAuth Security BCP) and RFC 7636 (PKCE). Use when someone asks \"add Google or Microsoft login\", \"implement OAuth in our app\", \"where should I store the refresh token\", \"how do I validate an ID token\", or is wiring an app to an identity provider or third-party API. Do NOT use for auditing a whole application's security posture - use security-audit instead; for line-level review of an auth diff, use secure-code-review.\nmetadata:\n  title: \"OAuth & OIDC Flow\"\n---\n\n# OAuth & OIDC Flow\n\nOAuth bugs fail silently: a login that works in the demo can still accept forged callbacks, leak refresh tokens to page scripts, or link an attacker's account to a victim's. The costly mistake this skill prevents is copying a flow that \"works\" - implicit grant, tokens in localStorage, unchecked state, an ID token decoded but never verified - and shipping an account-takeover path no functional test will catch.\n\n## Operating procedure\n\nDecide the grant and token storage before writing a route; most OAuth flaws are architecture choices.\n\n### Step 1: Choose the grant\n\n- A user signs in (web, SPA, native): authorization code + PKCE. RFC 9700 requires PKCE for public clients and recommends it for confidential ones - use it for both.\n- No user present: client credentials, confidential clients only.\n- Never implicit (fragment tokens leak via history and scripts) or password credentials (RFC 9700: must not be used).\n- SPAs: prefer a backend-for-frontend (BFF) that holds tokens and gives the browser only an httpOnly session cookie.\n- Native apps: system browser, not a webview (RFC 8252).\n\n### Step 2: Register the client tightly\n\n- Redirect URIs use exact string matching - no wildcards or prefixes; only a native app's loopback port may vary.\n- Separate clients and redirect URIs per environment.\n- Prefer private_key_jwt or mTLS client auth over shared secrets; secrets stay server-side.\n- Request minimum scopes, add more incrementally, and check the granted scope in the token response.\n\n### Step 3: Build the authorization request\n\n- code_verifier: 43-128 characters from [A-Z a-z 0-9 - . _ ~]; 32 random bytes base64url-encoded gives 43.\n- code_challenge = BASE64URL(SHA-256(code_verifier)), unpadded, with code_challenge_method=S256. Never plain.\n- state: at least 128 random bits, bound to the browser session, single use. PKCE blocks code injection, but state still stops login CSRF where you cannot verify the provider enforces PKCE.\n- nonce (OIDC): random, later compared to the ID token's nonce claim.\n\nKeep verifier, state, nonce, and return path in a server-side transaction or encrypted httpOnly cookie (~10 minute TTL). Allowlist the return path, or the callback becomes an open redirector.\n\n### Step 4: Handle the callback\n\n1. On error show a generic failure. Compare state in constant time; reject on mismatch or missing transaction; delete the transaction (single use).\n2. If an iss parameter is returned (RFC 9207), require the expected issuer - this blocks mix-up attacks.\n3. Exchange the code server-side with the identical redirect_uri, the code_verifier, and client authentication.\n4. Validate the ID token (Step 5) before creating a session; rotate the session ID; redirect to the validated return path.\n\n### Step 5: Validate the ID token\n\nNever just decode it. Verify:\n\n- Signature via the provider's JWKS, key chosen by kid; on an unknown kid refetch once (rate limited) to follow rotation.\n- alg in an explicit allowlist (e.g. RS256, ES256); reject none.\n- iss exactly equals the discovered issuer; aud contains your client_id (with multiple audiences, azp equals client_id).\n- exp in the future, clock skew of 60 seconds or less; nonce equals the stored value.\n\nKey users by (iss, sub), never email; auto-link by email only when email_verified is true and the provider is authoritative for the domain. The ID token is not an API credential - APIs take the access token and check its audience.\n\n### Step 6: Store tokens\n\n- Web apps and BFFs: server-side session store or an encrypted httpOnly, Secure, SameSite cookie.\n- SPAs without a backend: access token in memory only; never refresh tokens in localStorage or sessionStorage - any XSS reads them.\n- Native: Keychain or Android Keystore.\n- Never put tokens in URLs, logs, or error reports.\n\n### Step 7: Refresh with rotation and reuse detection\n\n- Each refresh issues a new refresh token and invalidates the old one; presentation of an already-used token revokes the whole token family.\n- Public clients must use rotation or sender-constrained tokens (DPoP or mTLS) per RFC 9700.\n- Make refresh single-flight so concurrent tabs do not trip reuse detection; refresh ~60 seconds before exp.\n\n### Step 8: Logout\n\nDestroy the session, revoke the refresh token (RFC 7009), and for single sign-out redirect to end_session_endpoint with id_token_hint. Clearing a cookie alone leaves the refresh token valid.\n\n## Worked example\n\nNext.js App Router BFF using jose. seal\u002Funseal, createSession, fail, and basicAuth are your helpers.\n\n```ts\n\u002F\u002F imports: NextRequest, NextResponse (next\u002Fserver); createRemoteJWKSet, jwtVerify (jose);\n\u002F\u002F          randomBytes, createHash, timingSafeEqual (node:crypto)\n\n\u002F\u002F app\u002Fapi\u002Fauth\u002Flogin\u002Froute.ts\nexport async function GET(req: NextRequest) {\n  const verifier = randomBytes(32).toString(\"base64url\");\n  const challenge = createHash(\"sha256\").update(verifier).digest(\"base64url\");\n  const state = randomBytes(32).toString(\"base64url\");\n  const nonce = randomBytes(32).toString(\"base64url\");\n  const returnTo = safeReturnPath(req.nextUrl.searchParams.get(\"returnTo\"));\n\n  const url = new URL(OIDC.authorization_endpoint);\n  url.search = new URLSearchParams({\n    response_type: \"code\", client_id: CLIENT_ID, redirect_uri: REDIRECT_URI,\n    scope: \"openid email profile\", state, nonce,\n    code_challenge: challenge, code_challenge_method: \"S256\",\n  }).toString();\n  const res = NextResponse.redirect(url);\n  res.cookies.set(\"oauth_tx\", await seal({ verifier, state, nonce, returnTo }), {\n    httpOnly: true, secure: true, sameSite: \"lax\", path: \"\u002Fapi\u002Fauth\", maxAge: 600,\n  });\n  return res;\n}\n\n\u002F\u002F app\u002Fapi\u002Fauth\u002Fcallback\u002Froute.ts\nconst JWKS = createRemoteJWKSet(new URL(OIDC.jwks_uri));\n\nexport async function GET(req: NextRequest) {\n  const p = req.nextUrl.searchParams;\n  const tx = await unseal(req.cookies.get(\"oauth_tx\")?.value);\n  const state = p.get(\"state\") ?? \"\";\n  const code = p.get(\"code\");\n  if (!tx || !code || state.length !== tx.state.length ||\n      !timingSafeEqual(Buffer.from(state), Buffer.from(tx.state))) return fail();\n  if (p.get(\"iss\") && p.get(\"iss\") !== OIDC.issuer) return fail();\n\n  const r = await fetch(OIDC.token_endpoint, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application\u002Fx-www-form-urlencoded\",\n               Authorization: basicAuth(CLIENT_ID, CLIENT_SECRET) },\n    body: new URLSearchParams({ grant_type: \"authorization_code\", code,\n      redirect_uri: REDIRECT_URI, code_verifier: tx.verifier }),\n  });\n  if (!r.ok) return fail();\n  const tokens = await r.json();\n\n  const v = await jwtVerify(tokens.id_token, JWKS, { issuer: OIDC.issuer,\n    audience: CLIENT_ID, algorithms: [\"RS256\"], clockTolerance: 60,\n  }).catch(() => null);                      \u002F\u002F throws on any failed check\n  if (!v || v.payload.nonce !== tx.nonce) return fail();\n  const { payload } = v;\n\n  const res = NextResponse.redirect(new URL(tx.returnTo, req.url));\n  res.cookies.delete({ name: \"oauth_tx\", path: \"\u002Fapi\u002Fauth\" });\n  await createSession(res, { userKey: `${payload.iss}|${payload.sub}`,\n                             refreshToken: tokens.refresh_token });\n  return res;\n}\n```\n\nWith response_mode=form_post (Apple, when requesting name or email) the callback is a cross-site POST that drops SameSite=Lax cookies: use SameSite=None; Secure and read the form body.\n\n## Provider gotchas\n\n- Google: refresh tokens need access_type=offline and usually arrive only on first consent.\n- Microsoft Entra ID: on the common or organizations endpoints iss carries the user's tenant ID - validate against an allowlist of tenant issuers.\n- GitHub OAuth Apps are not OIDC: no ID token; key on the numeric user ID.\n- Apple: name arrives only on first authorization; the client secret is a JWT you sign, valid six months at most.\n\n## Thresholds\n\n- code_verifier 43-128 chars; state and nonce at least 128 bits; transaction TTL ~10 minutes, single use.\n- Access tokens 5-60 minutes; rotated refresh tokens with idle timeout and absolute lifetime (e.g. 30-90 days).\n- ID token clock skew 60 seconds or less; one refresh-and-retry per 401.\n\n## Deliverable\n\nA working integration plus a design note (grant, client auth, redirect URIs per environment, token locations, rotation, revocation, ID token checks, logout) and negative tests for state mismatch, nonce mismatch, wrong audience, expired token, and refresh token reuse.\n\n## Do NOT\n\n- Do not use implicit or password grants, PKCE plain, or wildcard redirect URIs.\n- Do not store refresh tokens in localStorage, sessionStorage, or non-httpOnly cookies.\n- Do not accept an ID token without verifying signature, iss, aud, exp, and nonce; never accept alg none.\n- Do not use the ID token as an API bearer token, or link accounts by unverified email.\n\n## Quality bar\n\n- Every check (state, nonce, iss, aud, exp, signature, reuse) has a negative test that fails closed.\n- No token in a URL, log line, or script-readable storage; key rotation needs no deploy; logout makes the refresh token unusable.\n\n## Escalation\n\nUse security-audit for the surrounding app, secure-code-review for the auth diff, threat-model-stride for account-linking designs, secrets-hygiene for a leaked client secret, and api-design for how APIs accept access tokens.\n","# OAuth & OIDC Flow\n\nOAuth bugs fail silently: a login that works in the demo can still accept forged callbacks, leak refresh tokens to page scripts, or link an attacker's account to a victim's. The costly mistake this skill prevents is copying a flow that \"works\" - implicit grant, tokens in localStorage, unchecked state, an ID token decoded but never verified - and shipping an account-takeover path no functional test will catch.\n\n## Operating procedure\n\nDecide the grant and token storage before writing a route; most OAuth flaws are architecture choices.\n\n### Step 1: Choose the grant\n\n- A user signs in (web, SPA, native): authorization code + PKCE. RFC 9700 requires PKCE for public clients and recommends it for confidential ones - use it for both.\n- No user present: client credentials, confidential clients only.\n- Never implicit (fragment tokens leak via history and scripts) or password credentials (RFC 9700: must not be used).\n- SPAs: prefer a backend-for-frontend (BFF) that holds tokens and gives the browser only an httpOnly session cookie.\n- Native apps: system browser, not a webview (RFC 8252).\n\n### Step 2: Register the client tightly\n\n- Redirect URIs use exact string matching - no wildcards or prefixes; only a native app's loopback port may vary.\n- Separate clients and redirect URIs per environment.\n- Prefer private_key_jwt or mTLS client auth over shared secrets; secrets stay server-side.\n- Request minimum scopes, add more incrementally, and check the granted scope in the token response.\n\n### Step 3: Build the authorization request\n\n- code_verifier: 43-128 characters from [A-Z a-z 0-9 - . _ ~]; 32 random bytes base64url-encoded gives 43.\n- code_challenge = BASE64URL(SHA-256(code_verifier)), unpadded, with code_challenge_method=S256. Never plain.\n- state: at least 128 random bits, bound to the browser session, single use. PKCE blocks code injection, but state still stops login CSRF where you cannot verify the provider enforces PKCE.\n- nonce (OIDC): random, later compared to the ID token's nonce claim.\n\nKeep verifier, state, nonce, and return path in a server-side transaction or encrypted httpOnly cookie (~10 minute TTL). Allowlist the return path, or the callback becomes an open redirector.\n\n### Step 4: Handle the callback\n\n1. On error show a generic failure. Compare state in constant time; reject on mismatch or missing transaction; delete the transaction (single use).\n2. If an iss parameter is returned (RFC 9207), require the expected issuer - this blocks mix-up attacks.\n3. Exchange the code server-side with the identical redirect_uri, the code_verifier, and client authentication.\n4. Validate the ID token (Step 5) before creating a session; rotate the session ID; redirect to the validated return path.\n\n### Step 5: Validate the ID token\n\nNever just decode it. Verify:\n\n- Signature via the provider's JWKS, key chosen by kid; on an unknown kid refetch once (rate limited) to follow rotation.\n- alg in an explicit allowlist (e.g. RS256, ES256); reject none.\n- iss exactly equals the discovered issuer; aud contains your client_id (with multiple audiences, azp equals client_id).\n- exp in the future, clock skew of 60 seconds or less; nonce equals the stored value.\n\nKey users by (iss, sub), never email; auto-link by email only when email_verified is true and the provider is authoritative for the domain. The ID token is not an API credential - APIs take the access token and check its audience.\n\n### Step 6: Store tokens\n\n- Web apps and BFFs: server-side session store or an encrypted httpOnly, Secure, SameSite cookie.\n- SPAs without a backend: access token in memory only; never refresh tokens in localStorage or sessionStorage - any XSS reads them.\n- Native: Keychain or Android Keystore.\n- Never put tokens in URLs, logs, or error reports.\n\n### Step 7: Refresh with rotation and reuse detection\n\n- Each refresh issues a new refresh token and invalidates the old one; presentation of an already-used token revokes the whole token family.\n- Public clients must use rotation or sender-constrained tokens (DPoP or mTLS) per RFC 9700.\n- Make refresh single-flight so concurrent tabs do not trip reuse detection; refresh ~60 seconds before exp.\n\n### Step 8: Logout\n\nDestroy the session, revoke the refresh token (RFC 7009), and for single sign-out redirect to end_session_endpoint with id_token_hint. Clearing a cookie alone leaves the refresh token valid.\n\n## Worked example\n\nNext.js App Router BFF using jose. seal\u002Funseal, createSession, fail, and basicAuth are your helpers.\n\n```ts\n\u002F\u002F imports: NextRequest, NextResponse (next\u002Fserver); createRemoteJWKSet, jwtVerify (jose);\n\u002F\u002F          randomBytes, createHash, timingSafeEqual (node:crypto)\n\n\u002F\u002F app\u002Fapi\u002Fauth\u002Flogin\u002Froute.ts\nexport async function GET(req: NextRequest) {\n  const verifier = randomBytes(32).toString(\"base64url\");\n  const challenge = createHash(\"sha256\").update(verifier).digest(\"base64url\");\n  const state = randomBytes(32).toString(\"base64url\");\n  const nonce = randomBytes(32).toString(\"base64url\");\n  const returnTo = safeReturnPath(req.nextUrl.searchParams.get(\"returnTo\"));\n\n  const url = new URL(OIDC.authorization_endpoint);\n  url.search = new URLSearchParams({\n    response_type: \"code\", client_id: CLIENT_ID, redirect_uri: REDIRECT_URI,\n    scope: \"openid email profile\", state, nonce,\n    code_challenge: challenge, code_challenge_method: \"S256\",\n  }).toString();\n  const res = NextResponse.redirect(url);\n  res.cookies.set(\"oauth_tx\", await seal({ verifier, state, nonce, returnTo }), {\n    httpOnly: true, secure: true, sameSite: \"lax\", path: \"\u002Fapi\u002Fauth\", maxAge: 600,\n  });\n  return res;\n}\n\n\u002F\u002F app\u002Fapi\u002Fauth\u002Fcallback\u002Froute.ts\nconst JWKS = createRemoteJWKSet(new URL(OIDC.jwks_uri));\n\nexport async function GET(req: NextRequest) {\n  const p = req.nextUrl.searchParams;\n  const tx = await unseal(req.cookies.get(\"oauth_tx\")?.value);\n  const state = p.get(\"state\") ?? \"\";\n  const code = p.get(\"code\");\n  if (!tx || !code || state.length !== tx.state.length ||\n      !timingSafeEqual(Buffer.from(state), Buffer.from(tx.state))) return fail();\n  if (p.get(\"iss\") && p.get(\"iss\") !== OIDC.issuer) return fail();\n\n  const r = await fetch(OIDC.token_endpoint, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application\u002Fx-www-form-urlencoded\",\n               Authorization: basicAuth(CLIENT_ID, CLIENT_SECRET) },\n    body: new URLSearchParams({ grant_type: \"authorization_code\", code,\n      redirect_uri: REDIRECT_URI, code_verifier: tx.verifier }),\n  });\n  if (!r.ok) return fail();\n  const tokens = await r.json();\n\n  const v = await jwtVerify(tokens.id_token, JWKS, { issuer: OIDC.issuer,\n    audience: CLIENT_ID, algorithms: [\"RS256\"], clockTolerance: 60,\n  }).catch(() => null);                      \u002F\u002F throws on any failed check\n  if (!v || v.payload.nonce !== tx.nonce) return fail();\n  const { payload } = v;\n\n  const res = NextResponse.redirect(new URL(tx.returnTo, req.url));\n  res.cookies.delete({ name: \"oauth_tx\", path: \"\u002Fapi\u002Fauth\" });\n  await createSession(res, { userKey: `${payload.iss}|${payload.sub}`,\n                             refreshToken: tokens.refresh_token });\n  return res;\n}\n```\n\nWith response_mode=form_post (Apple, when requesting name or email) the callback is a cross-site POST that drops SameSite=Lax cookies: use SameSite=None; Secure and read the form body.\n\n## Provider gotchas\n\n- Google: refresh tokens need access_type=offline and usually arrive only on first consent.\n- Microsoft Entra ID: on the common or organizations endpoints iss carries the user's tenant ID - validate against an allowlist of tenant issuers.\n- GitHub OAuth Apps are not OIDC: no ID token; key on the numeric user ID.\n- Apple: name arrives only on first authorization; the client secret is a JWT you sign, valid six months at most.\n\n## Thresholds\n\n- code_verifier 43-128 chars; state and nonce at least 128 bits; transaction TTL ~10 minutes, single use.\n- Access tokens 5-60 minutes; rotated refresh tokens with idle timeout and absolute lifetime (e.g. 30-90 days).\n- ID token clock skew 60 seconds or less; one refresh-and-retry per 401.\n\n## Deliverable\n\nA working integration plus a design note (grant, client auth, redirect URIs per environment, token locations, rotation, revocation, ID token checks, logout) and negative tests for state mismatch, nonce mismatch, wrong audience, expired token, and refresh token reuse.\n\n## Do NOT\n\n- Do not use implicit or password grants, PKCE plain, or wildcard redirect URIs.\n- Do not store refresh tokens in localStorage, sessionStorage, or non-httpOnly cookies.\n- Do not accept an ID token without verifying signature, iss, aud, exp, and nonce; never accept alg none.\n- Do not use the ID token as an API bearer token, or link accounts by unverified email.\n\n## Quality bar\n\n- Every check (state, nonce, iss, aud, exp, signature, reuse) has a negative test that fails closed.\n- No token in a URL, log line, or script-readable storage; key rotation needs no deploy; logout makes the refresh token unusable.\n\n## Escalation\n\nUse security-audit for the surrounding app, secure-code-review for the auth diff, threat-model-stride for account-linking designs, secrets-hygiene for a leaked client secret, and api-design for how APIs accept access tokens.\n",{"name":5,"metadata":24,"description":7},{"title":25},"OAuth & OIDC Flow","main","97a13607d669157a4a16d5ba79b77f208319f7b9","skills\u002Foauth-flow",3,"https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills","https:\u002F\u002Fskillme.dev","https:\u002F\u002Fgithub.com\u002FSkillMedev","MCP-native catalog of Claude Agent Skills. Browse, recommend, install, and auto-apply skills in chat. Open source, every skill free and clonable on GitHub.","2026-10-14 03:19:31",{"source":8,"skillName":5,"commands":36,"prompt":46,"zipAvailable":47},[37,40,43],{"tool":38,"command":39},"npx","npx skills add SkillMedev\u002Fskills --skill oauth-flow",{"tool":41,"command":42},"bunx","bunx skills add SkillMedev\u002Fskills --skill oauth-flow",{"tool":44,"command":45},"pnpm","pnpm dlx skills add SkillMedev\u002Fskills --skill oauth-flow","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Foauth-flow\u002FSKILL.md",true,[],[50,60,67,74,81,88],{"skillNo":51,"name":52,"nameZh":53,"description":54,"descriptionZh":55,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":56,"categories":57,"keywords":58,"publishedAt":59},"01M75271B256DF3FX2VG5VRYEE","zone-2-cardio-plan","有氧运动计划","Use when someone asks to build a steady-state cardio plan, train an aerobic base or Zone 2, structure easy or endurance weekly cardio, train by heart-rate zones, or improve resting heart rate, VO2, or endurance. Builds a heart-rate-zone aerobic training block with session structure, modality choice, and progression. General fitness guidance, not medical advice. Do NOT use to design a strength or lifting program (use Strength Training Plan), high-intensity interval conditioning, HIIT, or circuits (use Conditioning & HIIT Program), or a mobility\u002Fflexibility routine (use Mobility Routine).","当有人要求制定稳态有氧训练计划、进行有氧基础训练或达到第二区间、安排轻松或耐力型的每周有氧训练、按心率区间训练，或提高静息心率、最大摄氧量或耐力时，可以使用此方案。该方案构建了一个包含训练计划结构、训练方式选择和进度安排的心率区间有氧训练模块。本方案仅提供一般健身指导，不构成医疗建议。请勿用于设计力量或举重训练计划（请使用力量训练计划）、高强度间歇训练 (HIIT) 或循环训练（请使用体能训练和 HIIT 计划），或灵活性\u002F柔韧性训练（请使用灵活性训练计划）。","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fzone-2-cardio-plan\u002FSKILL.md",[],[],"2026-11-11 18:27:18",{"skillNo":61,"name":62,"nameZh":6,"description":63,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":64,"categories":65,"keywords":66,"publishedAt":59},"01M7526VP1QBBKYBE17S1WR86Y","youtube-script-writer","Writes retention-engineered long-form YouTube scripts on a hook\u002Fbody\u002Fpayoff architecture - a first-30-seconds hook that survives the retention cliff, a beat-sheet body with mini-hooks and bridges, timed pattern interrupts, and a payoff that over-delivers - with B-roll and editing cues marked inline. Use when someone says \"script my next video\", \"my retention graph dies at the start\", \"tighten this draft\", or \"outline a video on X\". Do NOT use for the 3-second opener of TikTok, Reels, or Shorts - use video-hook-writer instead; do NOT use for spoken voiceover synced to on-screen tutorial actions - use narration-script instead; do NOT use for a sales demo built on a buyer's discovery notes - use demo-script instead; do NOT use to design the thumbnail and title - use thumbnail-concept instead.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fyoutube-script-writer\u002FSKILL.md",[],[],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":59},"01M7526P2T0WKMHDXS4Q58237T","win-back-campaign","Designs segmented win-back email sequences for dormant users - dormancy tiers, a three-beat sequence with a single proportional incentive, and a suppression rule - and measures success by re-activation, not opens. Use when someone says \"our users went quiet\", \"design a win-back campaign\", \"how do I re-engage lapsed customers\", \"should we email people who haven't logged in for months\", or lifecycle messaging has stopped landing with a lapsed segment. Do NOT use for recovering an unfinished checkout - use abandoned-cart-sequence instead. Do NOT use for diagnosing and fixing why active customers cancel - use churn-reduction instead. Do NOT use for building always-on onboarding or nurture flows - use email-drip-builder instead.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fwin-back-campaign\u002FSKILL.md",[],[],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":59},"01M7526HF2RCDJ50P93WRZRHVV","wikipedia-style","Writes neutral, verifiable, encyclopedic prose following Wikipedia's core content policies and manual of style - NPOV, inline citations, notability-backed claims, and a strict ban on promotional language. Use when someone asks \"write this like a Wikipedia article\", \"draft a Wikipedia page for this company or person\", \"make this neutral and encyclopedic\", or \"why does my article draft keep getting rejected\". Do NOT use for persuasive or opinion writing - use op-ed-writer instead; for thesis-driven academic papers, use academic-essay; for verifying claims in existing text, use fact-checker.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fwikipedia-style\u002FSKILL.md",[],[],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":59},"01M7526D43CTGRKGKNQ2GB0KVX","whitepapers","Structures and writes authoritative B2B whitepapers - a standalone executive summary, a data-sized problem statement, methodology, evidence-driven findings, recommendations, and a soft call to action - flagging every claim that needs a real citation. Use when a marketer asks \"write a whitepaper on this topic\", \"turn our research into a lead-gen asset\", \"make this credible enough for executives\", or a draft reads like a product pitch instead of analysis. Do NOT use for customer-story-driven proof - use case-study-builder instead; for policy audiences, use policy-brief.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fwhitepapers\u002FSKILL.md",[],[],{"skillNo":89,"name":90,"nameZh":6,"description":91,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":59},"01M75268423Y3K50SY5WC2NX2G","white-space-analysis","Finds unmet market gaps by ranking jobs-to-be-done on importance versus satisfaction, overlaying them against current solutions and workarounds, and validating that each gap is real, winnable, and worth winning. Use when someone asks \"where are the gaps in this market\", \"what's underserved here\", \"where should we play next\", or is hunting for product, feature, or market-entry opportunities. Do NOT use for profiling competitors and building battle cards - use competitive-intelligence instead; for putting a dollar figure on an identified opportunity - use market-sizing instead; for extracting jobs-to-be-done from raw customer interviews - use jtbd-extractor instead.","https:\u002F\u002Fgithub.com\u002FSkillMedev\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fwhite-space-analysis\u002FSKILL.md",[],[]]