# @kody/vercel — agent notes Human setup and intent live in `README.md`. This file is for agents: import paths, smoke / dryRun execute snippets, edge cases, and fork setup. Secrets by name only — never paste token or client-secret values into chat. ## Secrets / auth names | Name | Role | | --- | --- | | `vercelToken` | Default access-token secret (user scope, host `api.vercel.com`) | | `vercelToken-` | Alternate token when caller passes `account: ""` | | custom via `secretName` | Any saved token name; selects token lane and ignores `integrationName` | | integration `vercel` | OAuth lane via `integrationName: "vercel"` (REST permissions private beta) | Hosts: `api.vercel.com` (REST, required), `vercel.com` (OAuth authorize/dashboard). Token save URL: ``` https://kody.codes/account/secrets/new?name=vercelToken&description=Vercel%20access%20token%20(Bearer%20for%20api.vercel.com)&allowedHosts=api.vercel.com&scope=user ``` OAuth connect (prefilled; paste client id in the form, `flow=pkce`): ``` https://kody.codes/connect/oauth?provider=vercel&authorizeUrl=https%3A%2F%2Fvercel.com%2Foauth%2Fauthorize&tokenUrl=https%3A%2F%2Fapi.vercel.com%2Flogin%2Foauth%2Ftoken&flow=pkce&pkce=true&scopes=openid%20email%20profile%20offline_access&allowedHosts=api.vercel.com%2Cvercel.com&apiBaseUrl=https%3A%2F%2Fapi.vercel.com&dashboardUrl=https%3A%2F%2Fvercel.com%2Fdocs%2Fsign-in-with-vercel&providerSetupInstructions=Create%20a%20Sign%20in%20with%20Vercel%20app%20and%20register%20redirect%20URI%20exactly%20https%3A%2F%2Fkody.codes%2Fconnect%2Foauth.%20REST%20API%20permissions%20for%20this%20OAuth%20lane%20are%20in%20private%20beta%20%E2%80%94%20prefer%20an%20access%20token%20for%20teams%2C%20projects%2C%20and%20deployments.%20Paste%20the%20client%20id%20into%20this%20form. ``` Reconnect: `https://kody.codes/connect/oauth?provider=vercel`. ## Import paths | Export | Import | | --- | --- | | dispatcher (defaults to smoke-test) | `kody:@kody/vercel` | | request (escape hatch) | `kody:@kody/vercel/request` | | get-user | `kody:@kody/vercel/get-user` | | list-teams | `kody:@kody/vercel/list-teams` | | get-team | `kody:@kody/vercel/get-team` | | list-projects | `kody:@kody/vercel/list-projects` | | get-project | `kody:@kody/vercel/get-project` | | list-deployments | `kody:@kody/vercel/list-deployments` | | get-deployment | `kody:@kody/vercel/get-deployment` | | create-deployment | `kody:@kody/vercel/create-deployment` | | list-domains | `kody:@kody/vercel/list-domains` | | add-domain | `kody:@kody/vercel/add-domain` | | list-env-vars | `kody:@kody/vercel/list-env-vars` | | create-env-var | `kody:@kody/vercel/create-env-var` | | smoke-test | `kody:@kody/vercel/smoke-test` | Prefer named helpers over `request` when available. ## Smoke test Dry-run (no live `/v2/user` call): ```js import smokeTest from 'kody:@kody/vercel/smoke-test' export default async function main() { return await smokeTest({ dryRun: true }) } ``` Or via package root: ```js import vercel from 'kody:@kody/vercel' export default async function main() { return await vercel({ dryRun: true }) } ``` Without `vercelToken` (and without a connected `vercel` integration), a live call still returns `{ ok: true, live: false }` plus setup URLs. With credentials it reads a trimmed `/v2/user` profile — no writes. ## dryRun / confirm snippets ```js import addDomain from 'kody:@kody/vercel/add-domain' export default async function main() { return await addDomain({ project: 'example-app', name: 'www.example.com', dryRun: true, }) } ``` ```js import createDeployment from 'kody:@kody/vercel/create-deployment' export default async function main() { return await createDeployment({ name: 'example-app', target: 'preview', dryRun: true, }) } ``` ```js import createEnvVar from 'kody:@kody/vercel/create-env-var' export default async function main() { return await createEnvVar({ project: 'example-app', key: 'EXAMPLE_FLAG', value: '1', target: ['preview'], dryRun: true, }) } ``` Live writes need `confirm: true` in addition to (or instead of) skipping dry-run. Do not set deployment `target: 'production'` unless the caller explicitly asked. ## Read examples ```js import listProjects from 'kody:@kody/vercel/list-projects' export default async function main() { return await listProjects({ teamSlug: 'acme', search: 'docs' }) } ``` ```js import listDeployments from 'kody:@kody/vercel/list-deployments' export default async function main() { return await listDeployments({ projectId: 'prj_…', limit: 10 }) } ``` ```js import listEnvVars from 'kody:@kody/vercel/list-env-vars' export default async function main() { return await listEnvVars({ project: 'example-app' }) } ``` ```js import request from 'kody:@kody/vercel/request' export default async function main() { return await request({ path: '/v2/user' }) } ``` ## Edge cases - Hard-coded retired account aliases (`kent`, `kentcdodds`, `epicweb`, `epic-web`, `kcd`) throw — pass `secretName` or `integrationName` instead. - `secretName` selects the token lane and ignores `integrationName`. - Env-var dry-run previews redact `value`; `list-env-vars` never returns values. - Mutating `request` methods require `dryRun: true` or `confirm: true`. - Full-account tokens need `teamId` / `teamSlug` when targeting team resources; team-/project-scoped tokens infer scope. - No personal project names or team slugs are hard-coded in this package. ## Fork / setup for agents 1. Fork this listing into the caller's account (`communityFork` / adopt flow as appropriate). 2. Save the caller's own `vercelToken` (or connect OAuth) and approve `api.vercel.com`. 3. Clear any `pending_secret_package_approvals` after publish/fork. 4. Smoke-test with `kody:@kody/vercel/smoke-test` (`dryRun: true` first, then live read-only) from `execute`. 5. Keep `community-icon.svg` / `icon.svg` branding assets intact unless deliberately updating official Vercel artwork.