# Byoa Unlink

> BYOA unlink

- Skill: `pipecat-ai/byoa-unlink` (Agent Skill)
- Install (CLI): `npx skillmds@latest add pipecat-ai/byoa-unlink`
- Raw SKILL.md: https://api.skillmd.com/api/skills/pipecat-ai/byoa-unlink/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: pipecat-ai (https://skillmd.com/u/pipecat-ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/pipecat-ai/byoa-unlink

---


# BYOA unlink

Releases a corp ship that was claimed via `/byoa-link`, in two server calls:

1. `set` with `{ wake_secret: null, source_url: null }` — wipes the per-ship wake config while we still own the ship (the `set` action is owner-only).
2. `clear` — nulls `byoa_owner_character_id` and resets `byoa_mode` to `private`.

After both succeed the ship has no owner, no `source_url`, and no `wake_secret`, and goes back into the pool for any corp member to claim. Idempotent (re-running on an already-cleared ship returns success without error — the `set` call is skipped automatically).

This skill does **not** delete `.env.byoa`, tear down the operator's local daemon, or unprovision the Vercel deployment — those are the operator's own infrastructure to keep or discard. Pass `--clear-env` to also remove `.env.byoa` from the current directory.

## Parameters

```
/byoa-unlink [env] [--ship-id <uuid>] [--character-id <uuid>] [--access-token <jwt>] [--clear-env]
```

- **env**: `prod` (default) or `local`. Picks the game server endpoint:
  - `prod` → `https://api.gradient-bang.com`
  - `local` → sources `SUPABASE_URL` from `.env.supabase`
- **--ship-id**: ship UUID to release. Defaults to `BYOA_SHIP_ID` in `.env.byoa`.
- **--character-id**: caller's character UUID. Defaults to `BYOA_CHARACTER_ID` in `.env.byoa`. Must be the current BYOA owner (server returns 403 otherwise).
- **--access-token**: reuse an existing user JWT instead of prompting for email/password. Token must belong to the same operator who owns the ship.
- **--clear-env**: after a successful unlink, delete `.env.byoa`. Off by default — keep the file if you intend to re-`/byoa-link` the same ship soon (you'll just need a fresh wake secret on re-link anyway, but the IDs are reusable).

## Pre-flight

Stop with a clean error if any of these is true:

- Both `.env.byoa` is missing AND `--ship-id` was not provided. There's nothing to unlink.
- `--ship-id` provided but no `--character-id` AND `.env.byoa` doesn't have one — the server needs to know which character is making the call.
- For `env=local`: `.env.supabase` is missing or `SUPABASE_URL` is unset inside it.

## Steps

### 1. Resolve env + IDs

```bash
# Load .env.byoa if present
[ -f .env.byoa ] && set -a && source .env.byoa && set +a

# Resolve SUPABASE_URL
case "${ENV_ARG:-prod}" in
  prod)  SUPABASE_URL=https://api.gradient-bang.com ;;
  local) set -a && source .env.supabase && set +a ;;
esac

SHIP_ID="${ARG_SHIP_ID:-$BYOA_SHIP_ID}"
CHARACTER_ID="${ARG_CHARACTER_ID:-$BYOA_CHARACTER_ID}"
```

Surface the resolved ship + character IDs (8-char prefixes) to the operator before proceeding so they can catch a wrong-account mistake before the POST.

### 2. Get a user JWT

If `--access-token` was passed, use it directly. Otherwise prompt for email + password:

```bash
LOGIN_RESPONSE=$(curl -s -X POST "${SUPABASE_URL}/functions/v1/login" \
  -H "Content-Type: application/json" \
  -d "{\"email\": \"$EMAIL\", \"password\": \"$PASSWORD\"}")
ACCESS_TOKEN=$(echo "$LOGIN_RESPONSE" | grep -o '"access_token":"[^"]*"' | head -1 | cut -d'"' -f4)
```

On 401 / `success: false`: don't retry. Surface the response body and stop. Never echo `$PASSWORD` or `$ACCESS_TOKEN` to chat.

### 3a. POST set (null wake config)

Wipe the stored `source_url` and `wake_secret` while we still own the ship. The `set` action is owner-only, so this must run before `clear`.

```bash
SET_RESPONSE=$(curl -s -X POST "${SUPABASE_URL}/functions/v1/ship_byoa_configure" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d "{
    \"character_id\": \"$CHARACTER_ID\",
    \"ship_id\": \"$SHIP_ID\",
    \"action\": \"set\",
    \"wake_secret\": null,
    \"source_url\": null
  }")
```

Expected success: `{"success":true,"action":"set","wake_secret_updated":true,"source_url_updated":true,...}`.

If the response is `403 Only the current BYOA owner can set wake config`, the ship is already unowned (or owned by someone else) — skip to step 3b, which will either succeed idempotently or surface the real ownership mismatch with its own 403. Don't treat this 403 as fatal here.

For any other non-2xx (500, network error, etc.): surface the body and stop. Don't proceed to `clear` if the wipe genuinely failed — leaving a stale `source_url` / `wake_secret` on an unowned ship is the failure mode this whole change is meant to prevent.

### 3b. POST clear (release ownership)

```bash
curl -s -X POST "${SUPABASE_URL}/functions/v1/ship_byoa_configure" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d "{
    \"character_id\": \"$CHARACTER_ID\",
    \"ship_id\": \"$SHIP_ID\",
    \"action\": \"clear\"
  }"
```

Expected success: `{"success":true,"ship_id":"...","byoa_owner_character_id":null,"byoa_mode":"private","changed":true}`. The `changed: false` variant is also success — it means the ship was already cleared (idempotent).

### 4. (Optional) Remove `.env.byoa`

Only if `--clear-env` was passed:

```bash
[ -f .env.byoa ] && rm -f .env.byoa && echo "removed .env.byoa"
```

Don't touch other operator-owned state (`.env.supabase`, the Vercel project, the local wake daemon, etc.) — out of scope.

### 5. Report

Print a terse summary:

- Ship released: `<ship_id>` (8-char prefix)
- Mode reset to `private`, owner null
- `source_url`: cleared (or "skipped — ship already unowned" if step 3a was bypassed)
- `wake_secret`: cleared (or "skipped — ship already unowned")
- `.env.byoa`: kept / removed (per `--clear-env`)
- Next steps: any corp member can now claim this ship via `/byoa-link <env> --ship-id <ship_id>`. Operator-side cleanup (`vercel project rm`, killing `byoa --serve`, etc.) is the operator's call.

## Failure modes

- **`.env.byoa` missing AND no `--ship-id`**: nothing to unlink — point operator at `/byoa-link` to claim a ship first, or supply `--ship-id`.
- **403 `Only the current BYOA owner can set wake config`** (on step 3a): expected when the ship is already unowned. The skill falls through to `clear` automatically. If `clear` then also 403s with "Only the current BYOA owner can clear BYOA", the ship is genuinely owned by someone else — see below.
- **403 `Only the current BYOA owner can clear BYOA`**: the JWT belongs to a different operator. Either log in as the right account, supply `--access-token` from the right account, or have a corp admin override at the DB level.
- **403 `Only corp members can configure BYOA on this ship`**: the caller isn't in the ship's corp. Same remediation as above.
- **404 `ship_not_found`**: bad `--ship-id`. Confirm it matches what `/byoa-link list` showed.
- **409 `ship_busy`**: the ship has an active task in flight. The server refuses to flip ownership mid-task to avoid task-attribution ambiguity. Wait for the task to finish (or cancel it from the bot side), then re-run.
- **401 from `/login`**: bad credentials. Don't retry; surface the body and stop.
- **`changed: false` in the success response**: ship was already unowned. Treat as success — the operator might have previously cleared it manually or via a separate session.

## What this skill does NOT do

- Tear down operator-owned infrastructure (Vercel deployment, local `byoa --serve` daemon, ngrok tunnel, etc.). The skill releases the database link and wipes the server-side wake config; the operator decides whether to keep their wake receiver standing for a future re-claim.
- Touch `.env.bot`, `.env.supabase`, or any other env file. Only `.env.byoa` is in scope, and only when `--clear-env` is passed.
- Notify other corp members that the ship is now claimable. The ship just appears as `claimable_by_me: true` on their next `/byoa-link list` call.

