source/skills/hosting/SKILL.md
Sets up Vercel hosting for the project. Triggers vercel login via browser device auth, creates or links a Vercel project, provisions Vercel Blob storage, and stores project metadata in .bodega.md.
npx skillsauth add mitcheman/bodega hostingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Sets up where the site will live on the internet. We use Vercel — free for stores at this scale, solid CLI, composes cleanly with the vercel-plugin.
.bodega.md. Apply the resume contract from
setup/SKILL.md ("Resume contract — every sub-skill follows this"):
state.hosting: done → ask if user wants to re-run.state.hosting: in-progress / partial → resume from
hosting.last_completed_step + 1 (substep labels below).state.hosting: failed → show failed_reason, ask retry-or-restart.vercel --version. Missing → install:
npm install -g vercel.In order:
vercel-authed (after Step 1)scope-resolved (after Step 2a)project-linked (after Step 2b/2c)blob-store-created (after vercel blob store add)blob-store-connected (after vercel blob store connect)preview-url-recorded (after Step 4)Write hosting.last_attempted_step: <next> BEFORE each substep, then
update hosting.last_completed_step: <substep> AFTER. On full
success, set state.hosting: done and clear both substep fields.
Bare vercel login drops into an interactive auth-method picker
(Google / GitHub / Email / SAML), which hangs in non-TTY shells
(every AI coding agent context). Pick one of these instead:
| Context | Command | Why |
|---|---|---|
| Agent / non-TTY | vercel login --github | Specifies the auth method up front, opens browser device-auth, no picker. The user still authorizes in browser, but the picker step is skipped. |
| Agent + headless CI | VERCEL_TOKEN=<token> vercel whoami | Skips login entirely. User pre-creates a token at vercel.com/account/tokens. |
| Real terminal | vercel login | Fine — picker works in a TTY. |
Auto-detect: if process.stdout.isTTY is false, never run bare
vercel login. Default to vercel login --github and ask the user
which method to use only if they push back.
First, your site needs somewhere on the internet to live. I'll use Vercel — that's the company that will run your site day-to-day. Free for stores at your size, and the account is yours (I'm not in the middle).
Here's what's about to happen:
- I'll open the Vercel login in your browser. You'll see a short code on the Vercel page — the same code will be shown here. Click Confirm in the browser if the codes match.
- If you don't have a Vercel account yet, the same flow creates one — no separate signup. Use Google or GitHub for the fastest path; tell me if you'd rather use email.
- Come back here and say "done" when the browser tells you "You are now logged in."
vercel login --github(non-TTY-safe; barevercel loginhangs on the auth-method picker in agent shells). Browser device-auth.vercel whoamito verify.Headless alternative: set
VERCEL_TOKENenv var; skip login entirely.
Run vercel login --github (or --email <addr>, --gitlab,
--bitbucket, --saml per the user's preference). Wait for browser
confirmation. Verify with vercel whoami. Capture the Vercel account
email as operator.email in .bodega.md.
If VERCEL_TOKEN is already set in env, skip the login step entirely
and proceed straight to verification.
Check if current folder is already linked (.vercel/project.json exists).
projectId + orgId from the file, skip the rest.vercel link prompts for the team/scope when an account has more
than one. The --yes flag handles the project-creation confirmation
but not the scope picker — without --scope=<slug> the command hangs
in non-TTY/agent shells, exits cleanly, and writes nothing to
.vercel/. Result: every subsequent vercel env, vercel deploy,
vercel blob etc. errors with "Your codebase isn't linked to a
project on Vercel."
This is the most common silent-failure mode of the entire setup. Always
resolve scope before running vercel link.
vercel teams ls --json
Parse the response:
slug.mitcheman (personal),
acme-agency) and let them pick by number.vercel login --github.Cache the chosen scope for the rest of the session and write it to
.bodega.md so reconfigure / standalone re-runs of hosting reuse the
same scope.
Slug from business.name in .bodega.md. Example:
"Mudd Mann Studio" → mudd-mann-studio.
vercel link --yes --project <slug> --scope=<scope-slug>
If the slug is taken under that scope, append -1, -2 and retry.
vercel link is the most-likely silent-failure step in the whole
flow. Verify before continuing:
test -f .vercel/project.json || (echo "vercel link failed silently — bail" >&2; exit 1)
vercel project inspect --json
If .vercel/project.json is missing, do not proceed to Step 3 — the
storage-provision and env-var-add commands will all fail with
"isn't linked to a project." Re-run Step 2a/2b with explicit --scope
or surface the error to the user.
Setting up your store on Vercel — picking which account it lives under, then reserving the name. Give me a second.
(If multi-account, ask which one to use, by number.)
vercel teams ls→ resolve scope.vercel link --yes --project <slug> --scope=<scope>. If slug taken, suffix-1. Verify.vercel/project.jsonexists before continuing.
One Vercel Blob store for products and images. The CLI surface for
storage has shifted twice — verify with vercel blob --help
before assuming any specific subcommand shape:
| Vercel CLI | Subcommand shape | Notes |
|---|---|---|
| 49 and earlier | vercel storage create --type blob <name> | top-level storage; gone |
| 50–51 | vercel blob store add <name> + vercel blob store connect <name> | nested store add/store connect; gone |
| 52+ (current) | vercel blob create-store <name> --access=public --yes | flat verbs; one shot, no separate connect step |
This SKILL targets CLI 52+. Doctor warns + bails if the user's CLI
is older than 50 (MIN_VERCEL_MAJOR in doctor/scripts/check.mjs),
so you can assume 52+ here. If you're somehow on 50/51, upgrade:
npm i -g vercel@latest.
# Create the blob store + connect it to all environments in one
# command. --yes accepts the "connect to environments?" prompt
# (which would otherwise hang in non-TTY shells). --access=public
# is required: bodega stores both product images AND magic-link
# records as public blobs (the magic-link records rely on
# unguessable 32-byte token paths instead of access control).
#
# Idempotent — list-stores returns project-linked stores; if
# bodega-store already shows up, skip create.
if ! vercel blob list-stores 2>/dev/null | grep -q '^\s*bodega-store\b'; then
vercel blob create-store bodega-store --access=public --yes
fi
# Verify the token landed on the production env
vercel env ls production | grep -q '^BLOB_READ_WRITE_TOKEN\b' \
|| { echo "❌ BLOB_READ_WRITE_TOKEN not provisioned"; exit 1; }
No separate
connectstep on CLI 52. There used to be avercel blob store connectsubcommand on CLI 50/51 — it's gone. Linking happens duringcreate-storevia the prompt that--yesaccepts, or never. If a previous setup created a store without linking it, the only way to link it after the fact is the Vercel dashboard (Storage → bodega-store → Connect Project) — there's no CLI path. So always runcreate-storewith--yesso the link happens atomically with creation.
--access=publicis required. The flag isn't optional on CLI 52 —vercel blob create-store bodega-store(no flag) errors with "access is required". And bodega specifically needspublic: the SDK'sauth/blob-storage.tsandroutes/upload.tsboth callput(..., { access: 'public', ... }), which requires a public-capable store. A--access=privatestore would refuse public puts.
If create-store errored or the token didn't land, the dashboard
path:
bodega-store and "Connect Project"
to the muddmann project, or "Create" a new Blob store, name it
bodega-store, set Access to Public, link to the muddmann
project on creation.vercel env ls production | grep BLOB_READ_WRITE_TOKEN.Don't proceed to bodega:deploy without the token in env — every
magic-link request, every image upload, every product write will
500 (or 503 with a clearer message after SDK ≥ 0.3.1).
✓ Your site has a home on the internet. ✓ Set up storage for your product photos — the images live on your Vercel account, not mine. You own them.
✓ Vercel project linked: <slug> ✓ Blob store created: bodega-store ✓ BLOB_READ_WRITE_TOKEN provisioned
No deploy yet. Just record the default URL. Read project info:
vercel project inspect --json
Record as vercel.preview_url in .bodega.md.
.bodega.mdoperator:
email: [email protected]
vercel:
project_id: prj_abc123
slug: mudd-mann-studio
preview_url: mudd-mann-studio.vercel.app
blob_store: bodega-store
state:
hosting: done
Return control to the calling skill (usually setup).
state.hosting: skipped, tell
them honestly that setup can't continue without it. Exit politely.state.hosting: partial and note the missing piece.vercel login handles tokens
in ~/.vercel/auth.json; we don't touch them.{{command_prefix}}bodega:backup sets
up a GitHub repo, the deploy pipeline stays CLI-based.development
Roll back a Bodega-provisioned project. Walks the user through removing the Vercel project, blob store, GitHub repo, Stripe webhook, and (optionally) `.bodega.md` itself. The merchant's Stripe account stays — that's their data.
business
Reports the current state of the store — what's set up, what's pending, what the URLs are, and what to do next.
testing
First-time Bodega setup. Detects whether the folder has an existing project (adapt) or is empty (greenfield), asks about voice and beneficiary, writes .bodega.md, and orchestrates the full flow through hosting, payments, deploy, and admin.
testing
Re-ask the voice and beneficiary questions and update .bodega.md. Useful when the user's preference changes or the store is being handed off to someone new.