Skip to main content

Install

Install the CLI from npm (Node.js 22 or later):
To run an unreleased commit instead, run it from source (the workspace packages resolve to their TypeScript sources, so it runs through the tsx loader rather than a build):
Then, in your app’s repository:
--setup turns the plan into credentials you can run it with, in one pass in your own terminal. For each provider the plan uses it shows the page where the token is created and the least it needs, takes the token from the environment or asks for it (hidden input, never written to disk), and checks it with one read-only request. Then, after a yes for each, it stores the checked tokens as GitHub Actions secrets of your origin with your own gh (the value goes to gh secret set on stdin, nowhere else), and writes .github/workflows/sponson.yml with the action pinned to the commit of the installed version’s release tag (an existing file is never overwritten). TODOs the plan still has (a placeholder such as a project id init could not find) are listed first, and the workflow is not offered until they are filled in: it would run a plan that cannot work. A default the plan runs with but you should look at (a recipe’s documented default, such as Stripe’s webhook path, marked # CHECK:) is listed as “please check” and blocks nothing. Run it again any time, also on an existing plan; --yes accepts every offer for scripted use, --json reports what init detects (todo and check), each credential’s status without a value, and next: { command, why }, where command is the command to run next (sponson plan once ready, sponson init --setup when a token only needs to be typed) or null when the next step is not a command (filling in a TODO, making a new token), and why says what to do. Agents ask a human to run it rather than handle a token themselves (SKILL.md).
<version> is the installed version; the commit is the one its release tag points at. Where each provider’s token is created and what to pick is listed per provider in docs/providers.md. sponson init reads the repository’s files only (no network, no credentials): .vercel/project.json and vercel.json, netlify.toml and .netlify/state.json, package.json dependencies, Prisma and Drizzle configs, .neon, and the variable names in .env.example, .env.local and the other .env* files. It never reads a value out of them, except to recognise a database host such as *.neon.tech. It writes a line only for what it found (one database: a Neon branch, a PlanetScale branch and password, or a Supabase preview branch, in that order of preference when several are detected; the Vercel or Netlify preview variable that references it under the name your code reads; a Clerk redirect or a Supabase Auth redirect for the preview URL), fills in the project ids it can find, and marks each one it cannot with a TODO comment saying where to look (vercel link, netlify link, neonctl projects list, supabase link). LaunchDarkly gets a commented example line to fill in with a flag key and uncomment. A Wrangler configuration (wrangler.toml, wrangler.json) gives a Cloudflare Pages variables line with the project’s name; Pages preview variables are shared by every preview, so no per-PR value is wired into them. A provider managed by recipes gets its recipe’s line, ready when the plan has everything it needs and commented out with a TODO otherwise. With nothing detected it writes the Vercel + Neon template. Besides the plan, init writes one line, .sponson/ (where local receipts go), into .gitignore. A service init detects that no adapter or recipe manages yet is listed as “not supported yet”, with where to ask for it (or why no API can manage it), and never silently dropped: today Pusher Channels and Liveblocks.
A value is filled in once its # TODO comment is gone too: until then it counts as a placeholder. sponson init --json reports the same under detected (also on a re-run with --setup, where todo is what the plan still has): found and unsupported (each with its evidence), todo (each placeholder’s path and hint) and assumed (true when the plan starts from the template). Paths are relative to the working directory in text and absolute in JSON. Which providers are covered today, and what is planned, is measured in docs/coverage.md. Beyond the built-in adapters, any JSON REST API is reachable with the generic http adapter, and the providers it has been verified against ship as recipes: one plan line names a provider operation and fills in its params, for example recipe: cloudflare.dns_cname with a zone_id, a name and a target. Each recipe cites the API docs it was checked against and runs through create, re-apply, drift and destroy in the test suite. Third-party adapters and secret sources load as plugins: SPONSON_PLUGINS=sponson-adapter-x,./local-adapter.mjs, each module exporting register(registry). Credentials come from the providers’ own conventions (VERCEL_TOKEN for Vercel; every adapter’s variable is listed under built-in ops). Sponson has no credential store of its own: sponson init --setup checks them and hands them to GitHub’s. In GitHub Actions, one workflow with three triggers calls the same action:
The action comments the plan and the receipt on the pull request. See action/README.md.