| name | byoa-deploy-vercel |
| description | Deploy the BYOA wake-receiver Vercel Function from `deployment/vercel/`. Reads `.env.byoa`, pushes the operator's required env to the Vercel project, deploys via `npx vercel`, health-checks the URL, logs the operator in, and registers the resulting alias as the ship's `source_url` via `ship_byoa_configure`. Picks up from `/byoa-link` (which claims the ship and writes `.env.byoa`). Usage `/byoa-deploy-vercel [env]` (env defaults to `prod`; `live` is an accepted synonym for `prod`). |
BYOA: deploy Vercel wake function
env defaults to prod when omitted. live is accepted as a user-facing synonym for prod (e.g. /byoa-deploy-vercel live is equivalent to /byoa-deploy-vercel prod and to /byoa-deploy-vercel with no arg). local is the only other valid value.
Picks up where /byoa-link finishes. The operator's ship is already claimed as BYOA, .env.byoa is populated with BYOA_CHARACTER_ID / BYOA_SHIP_ID / BYOA_WAKE_SECRET, and the per-ship wake secret is registered server-side. This skill takes the template Vercel Function at deployment/vercel/ and walks the operator through deploying their own copy.
End state: a Vercel deployment at https://<their-project>.vercel.app/api/wake that auths inbound wakes against BYOA_WAKE_SECRET and spawns a persistent @vercel/sandbox running uv run byoa per wake. The skill prints a ready-to-run ship_byoa_configure set { source_url } curl so the operator can point their ship at it.
Parameters
/byoa-deploy-vercel [env] [--preview] [--no-link] [--out-url <path>] [--access-token <jwt>] [--skip-register]
-
env: prod (default, also accepts live as a synonym) or local. Picks the game server endpoint that /login + /ship_byoa_configure are called against (the auto-register step at the end):
prod / live → https://api.gradient-bang.com (hardcoded; operator never types it; no env file needed). If the operator types nothing, this is what they get.
local → sources SUPABASE_URL from .env.supabase (e.g. http://127.0.0.1:54321 when npx supabase start is running)
The dev env was dropped — it required internal-only env files that external developers don't have. The skill no longer needs EDGE_API_TOKEN either; ship_byoa_configure and my_corporation authenticate on the user JWT alone via the standard getAuthenticatedUser() pattern (Authorization: Bearer <jwt>).
-
--preview: deploy as a Vercel preview instead of production. Almost never what you want for BYOA: Vercel's default Standard Protection gates preview URLs behind SSO, so the game server can't reach them. Use only if you've disabled Project Protection or are testing with a bypass token.
-
--no-link: skip the link verification (steps 3a + 3b). Use only when you're certain deployment/vercel/.vercel/project.json is correct.
-
--out-url: write the final canonical (alias) URL to this file. Defaults to stdout only.
-
--access-token : skip the email+password prompt in step 8 by reusing an existing user JWT (e.g. one just minted by /byoa-link). Token must be valid for the same operator who owns the ship.
-
--skip-register: stop after the health-check; don't auto-register source_url. Falls back to printing a manual curl. Use when the operator wants to inspect the deployment first or doesn't have credentials handy.
Default deploy target is production. The BYOA wake endpoint must be publicly reachable by the game server, and only the production alias (<projectName>.vercel.app) is exempt from Vercel's Standard Protection. Per-deploy URLs (<projectName>-<hash>-<team>.vercel.app) are SSO-gated regardless of target.
Tested with Vercel CLI 54.x.
Game tool calls route through the bus, not direct HTTP. The BYOA harness running in the Vercel sandbox never calls the game server directly — it publishes BusGameToolCallRequest messages onto the Postgres bus, and the bot-side Orchestrator broker forwards them to Supabase using the bot's own SUPABASE_URL. wake_agent's injected env (BYOA_BUS_DATABASE_URL, BYOA_CHANNEL, BYOA_SHIP_ID, BYOA_CHARACTER_ID, BYOA_TASK_ID, BYOA_WAKE_REQUEST_ID) contains no game-server URL on purpose. Practical implication: for local-stack testing against a Vercel-deployed receiver, only the Postgres bus needs to be publicly reachable (e.g. via ngrok tcp 54322 + BYOA_BUS_DATABASE_URL set in .env.supabase). No second tunnel for the game server is required. See runtime/orchestrator.py _on_game_tool_call_request for the broker side.
Pre-flight
Stop with a clean error if any of these is true:
.env.byoa does not exist in cwd → direct the operator to run /byoa-link first.
.env.byoa is missing any required key: BYOA_WAKE_SECRET, BYOA_SHIP_ID, BYOA_CHARACTER_ID, TASK_LLM_PROVIDER, TASK_LLM_MODEL, and the API key matching the provider (one of ANTHROPIC_API_KEY / GOOGLE_API_KEY / OPENAI_API_KEY / MINIMAX_API_KEY). Check by sourcing the file first (set -a && source .env.byoa && set +a), then verifying each required var is non-empty ([ -n "$BYOA_WAKE_SECRET" ], etc.). Do NOT grep the raw file — commented-out lines like # BYOA_PROMPT=... will match a naive grep BYOA_PROMPT= and produce false "is set" readings. Operators routinely keep commented-out alternates in .env.byoa; source correctly skips them, so trust the resulting env, not the file's text.
- deployment/vercel/ does not exist or is missing
api/wake.ts, package.json, or vercel.json — the template was deleted or this skill is being run against the wrong checkout.
npx vercel --version errors (Vercel CLI not available via npx).
- For
env=local: .env.supabase is missing or SUPABASE_URL is unset inside it.
Resolve which API key is required from TASK_LLM_PROVIDER:
| Provider | Required key |
|---|
anthropic | ANTHROPIC_API_KEY |
google | GOOGLE_API_KEY |
openai | OPENAI_API_KEY |
minimax | MINIMAX_API_KEY |
If both BYOA_PROMPT and BYOA_PROMPT_FILE are unset, mention that the agent will fall back to the bundled default prompt at deployment/vercel/prompt.md (auto-loaded by wake.ts on every wake — operators can edit it pre-deploy, fork the deploy template, or override via BYOA_PROMPT / BYOA_PROMPT_FILE on the Vercel project env).
Steps
1. Load envs
set -a && source .env.byoa && set +a
Then resolve SUPABASE_URL per the env arg. If the operator typed nothing, treat it as prod. live is accepted as a user-facing synonym for prod:
case "${ENV_ARG:-prod}" in
prod|live) SUPABASE_URL=https://api.gradient-bang.com ;;
local) set -a && source .env.supabase && set +a ;;
*) echo "unknown env: ${ENV_ARG}; expected prod | live | local"; exit 1 ;;
esac
All curls in step 8 append /functions/v1/<endpoint>, so SUPABASE_URL must NOT include /functions/v1. Never echo BYOA_WAKE_SECRET or any *_API_KEY to the console.
2. Verify Vercel CLI login
npx vercel whoami
If this prints "Not authenticated" (or errors), tell the operator to run npx vercel login in their shell and re-run the skill. Do not try to log them in for them.
3. Verify (or set up) the Vercel link
The canonical link location is deployment/vercel/.vercel/project.json. All subsequent vercel commands must be run from deployment/vercel/ so they pick up the right link.
Skip-able if the link is already in place; otherwise the skill must stop until the operator establishes it — vercel link is interactive (scope / project name / create-new prompts) and operator-specific. Do not pass --yes.
3a. Check for a misplaced .vercel/ at the repo root or deployment/.
ls .vercel/project.json deployment/.vercel/project.json 2>/dev/null
If either prints, a previous vercel link was run from the wrong cwd. Bail with the exact remediation, pasted ready-to-run, and stop:
mkdir -p deployment/vercel
mv deployment/.vercel deployment/vercel/.vercel
rm -rf .vercel deployment/.vercel
Do not auto-move or auto-delete — the operator may have a legitimate .vercel/ for some other project in the repo. Let them pick.
3b. Confirm the canonical link exists.
ls deployment/vercel/.vercel/project.json 2>/dev/null
If present → linked, proceed to step 4.
If missing → stop and surface this exactly:
cd deployment/vercel && npx vercel link
Tell the operator: run that in their shell, follow the prompts (suggested project name: gradient-bang-byoa-<their-handle>), then re-run /byoa-deploy-vercel. The interactive prompts (scope / "link to existing?" / project name) can't be driven from this skill — they must run it themselves.
4. Push project env to Vercel
Push the values from .env.byoa to the production Vercel environment only. The wake function is invoked through the production alias (<projectName>.vercel.app) and preview/development environments are never reached by the game server, so syncing env vars to them is pure noise. Use the rm-then-add pattern so re-runs are idempotent.
All vercel invocations use --cwd deployment/vercel instead of cd deployment/vercel && ... — that way the snippet runs the same whether or not the caller wraps it in a subshell, and accidental cwd drift can't bleed into later steps. Keep --cwd if you edit these commands — chained cd patterns silently move the Bash-tool cwd and break later steps (the operator-side curl in step 8 tries to source .env.supabase from the repo root).
First resolve the LLM-provider API key name + value from TASK_LLM_PROVIDER in one shot (resolving both here avoids ${!VAR} indirect expansion, which works in bash but not zsh — and zsh is the default macOS shell):
case "$TASK_LLM_PROVIDER" in
anthropic) API_KEY_NAME=ANTHROPIC_API_KEY; API_KEY_VALUE="$ANTHROPIC_API_KEY" ;;
google) API_KEY_NAME=GOOGLE_API_KEY; API_KEY_VALUE="$GOOGLE_API_KEY" ;;
openai) API_KEY_NAME=OPENAI_API_KEY; API_KEY_VALUE="$OPENAI_API_KEY" ;;
minimax) API_KEY_NAME=MINIMAX_API_KEY; API_KEY_VALUE="$MINIMAX_API_KEY" ;;
*) echo "Unknown TASK_LLM_PROVIDER=$TASK_LLM_PROVIDER"; exit 1 ;;
esac
Then push every key to production. The function reads named globals (KEY / VAL) instead of positional bash args — the slash-command loader substitutes literal positional refs (dollar-N) inside fenced code blocks with the skill's command-line args, which silently corrupts shell snippets. Don't use bash positional parameters in skill snippets — use named env vars on the call line instead, as below:
push_env() {
[ -z "$VAL" ] && return
npx vercel --cwd deployment/vercel env rm "$KEY" production --yes >/dev/null 2>&1 || true
if npx vercel --cwd deployment/vercel env add "$KEY" production --value "$VAL" --yes >/dev/null 2>&1; then
echo " ✓ $KEY → production"
else
echo " ✗ $KEY → production FAILED"
fi
}
KEY=BYOA_WAKE_SECRET VAL="$BYOA_WAKE_SECRET" push_env
KEY=TASK_LLM_PROVIDER VAL="$TASK_LLM_PROVIDER" push_env
KEY=TASK_LLM_MODEL VAL="$TASK_LLM_MODEL" push_env
KEY="$API_KEY_NAME" VAL="$API_KEY_VALUE" push_env
[ -n "$BYOA_PROMPT" ] && KEY=BYOA_PROMPT VAL="$BYOA_PROMPT" push_env
[ -n "$BYOA_PROMPT_FILE" ] && KEY=BYOA_PROMPT_FILE VAL="$BYOA_PROMPT_FILE" push_env
[ -n "$TASK_LLM_THINKING_BUDGET" ] && KEY=TASK_LLM_THINKING_BUDGET VAL="$TASK_LLM_THINKING_BUDGET" push_env
[ -n "$BYOA_TOOL_CALL_TIMEOUT_SECONDS" ] && KEY=BYOA_TOOL_CALL_TIMEOUT_SECONDS VAL="$BYOA_TOOL_CALL_TIMEOUT_SECONDS" push_env
[ -n "$BYOA_AGENT_IDLE_TEARDOWN_SECONDS" ] && KEY=BYOA_AGENT_IDLE_TEARDOWN_SECONDS VAL="$BYOA_AGENT_IDLE_TEARDOWN_SECONDS" push_env
Note on --value: this puts the secret in the process command line, briefly visible to other local users via ps aux. Acceptable on a developer machine; if pushing on shared infrastructure use vercel env pull + manual edit instead.
If vercel env rm complains "Environment Variable was not found" on first run, that's fine — || true swallows it. The real failure mode is an action_required JSON blob from the add step; if you see one, surface the message and stop. Do not echo BYOA_WAKE_SECRET or API keys to the console in error reporting.
5. Deploy and capture the canonical alias
Default to production (see "Default deploy target" note above). Tee the output so we can grep for the alias line. Same --cwd rule as step 4 — don't replace with chained cd patterns, even in pipelines:
npx vercel --cwd deployment/vercel deploy --prod --yes 2>&1 | tee /tmp/byoa-deploy.log
For --preview (rarely correct for BYOA), drop --prod — but warn the operator the resulting URL will be SSO-gated.
After the deploy, capture two URLs:
DEPLOY_URL=$(grep -oE 'https://[a-z0-9-]+\.vercel\.app' /tmp/byoa-deploy.log | head -1)
ALIAS_URL=$(grep -oE 'Aliased: https://[^ ]+' /tmp/byoa-deploy.log | head -1 | cut -d' ' -f2)
if [ -z "$ALIAS_URL" ]; then
PROJECT_NAME=$(grep -o '"projectName":"[^"]*"' deployment/vercel/.vercel/project.json | cut -d'"' -f4)
ALIAS_URL="https://${PROJECT_NAME}.vercel.app"
fi
On non-zero exit from vercel deploy, surface the CLI's error and stop.
Use ALIAS_URL for everything downstream (health-check, smoke-test, source_url). The per-deploy DEPLOY_URL will 401 on any unauthenticated request because Vercel's Standard Protection gates it behind SSO — even when the function itself is wired correctly. Hitting it during health-checks is the single biggest source of false-negative deployment reports.