# Hosted Handoff

Use this checklist after the hosted container path in
[`hosting.md`](./hosting.md) is configured.

## Operator Preflight

Before the remote canary, verify:

- DNS for `https://<host>` resolves to the deployed host or load balancer.
- Ports 80 and 443 are open if the checked-in Caddy profile terminates HTTPS.
- The WorkOS dashboard allowlists exactly `https://<host>/callback`.
- `COVIBE_HOSTED_URL` is the origin only, with no `/callback`, query string,
  hash, credentials, or private-network host.
- `NEXT_PUBLIC_WORKOS_REDIRECT_URI` is exactly `https://<host>/callback`.
- `COVIBE_DATABASE_BACKEND=postgres` and `DATABASE_URL` point at the rehearsal
  PostgreSQL service or the production Cloud SQL database. `COVIBE_UPLOAD_DIR`
  points at persistent upload storage. For `co-vibe.dev`, use the GCP
  production path in [`gcp-production.md`](./gcp-production.md) before customer
  traffic.
- `DATABASE_URL` is a NON-superuser, non-owner role and `COVIBE_POSTGRES_ADMIN_URL`
  is the owner role used only for init + provisioning. Confirm the runtime role
  is not a superuser/table owner, otherwise row-level security is bypassed.

If any of these are uncertain, fix them before inviting customer developers.

## Customer Rehearsal

Before a customer handoff, with Docker and WorkOS env available, run:

```bash
npm run readiness:customer
```

It first checks free disk, Docker daemon readiness, and WorkOS env so operators
do not wait through app/browser checks when the container path cannot finish.
It then runs `npm run readiness`, builds the hosted image once with the
fail-closed container smoke, and reuses that image for the WorkOS-mode container
smoke and hosted-canary rehearsal.

This proves both halves of the product:

- the cloud app can run as a hosted WorkOS tenant control plane
- developers can connect agents from their own repos through the local
  companion and MCP bridge

## Remote Hosted Canary

After deploy:

```bash
npm run readiness:hosted -- https://<host>
```

The hosted canary verifies health, the exact compact `/api/mcp` tool surface,
the companion package download, WorkOS auth mode, sign-in reachability,
protected API rejection, hidden local-dev routes, malformed MCP envelope
handling, and missing plus invalid MCP-token rejection.
Run `npm run canary:hosted -- --help` to inspect the underlying canary URL
forms and local-rehearsal flag without starting probes.

This command is the remote hosted canary proof and fails before downstream
checks if no hosted origin is supplied. It must run against the real HTTPS
customer origin, not a localhost or private-network rehearsal, callback URL,
credential-bearing URL, query string, hash, or other path.

The wrapper normalizes trailing slashes and derives the WorkOS callback as
`<origin>/callback` for its production-doctor step.
`COVIBE_HOSTED_URL=https://<host> npm run readiness:hosted` is equivalent if
your shell prefers environment variables. The wrapper also loads `.env*` files
like the app. A successful run ends with `PASS hosted readiness`.

## Final Handoff

For final customer handoff, run:

```bash
npm run readiness:handoff -- https://<host>
```

It fails before downstream checks if the URL is missing, localhost,
private-network, HTTP, credential-bearing, a callback/path/query/hash URL, or a
temporary tunnel domain. When the permanent origin is valid, it runs a fast
remote `/api/health`, `/api/mcp`, and `/downloads/co-vibe.tgz` preflight first
(`npm run readiness:handoff:preflight -- --help` prints the isolated preflight
usage without contacting the host).
That means DNS, TLS, WorkOS mode, MCP tool-count/surface, missing companion-package,
broken sign-in, public protected-API issues, unauthenticated token creation, and
exposed local-only routes, malformed MCP envelopes, and missing/invalid
MCP-token rejection, and token-shaped response leaks fail before the long local gate.
It also rejects tiny, malformed, or non-Co-Vibe companion packages before install.
Next it runs `npm run doctor:production` with the same hosted origin, so
callback-origin, auth-mode, cookie, and companion-install mistakes fail before
the long local customer rehearsal.
Timeout failures name the exact remote endpoint that stalled so operators can
fix the right hosted route before rerunning the long gate.
It then runs `npm run readiness:customer` and `npm run readiness:hosted`
against that same origin. A
successful run ends with `PASS customer handoff`.

In CI, the `Permanent hosted handoff` job uses the `COVIBE_HOSTED_URL`
repository secret by default. Manual workflow dispatch can provide `hosted_url`
to verify a newly deployed permanent origin before updating that secret.

## Data Backup

Before upgrades or schema-affecting releases, back up the hosted data volume:

```bash
docker compose run --rm --no-deps -v "$PWD":/backup --entrypoint sh covibe \
  -c 'tar czf "/backup/covibe-data-$(date +%Y%m%d-%H%M%S).tgz" -C /app/data .'
```

The archive contains uploaded profile photos and other volume-backed runtime
files. Back up PostgreSQL separately with your database backup process. Store
all backups outside the deploy host before rebuilding containers.

## Customer Setup

1. Sign in through `/auth/sign-in` (it redirects to the hosted WorkOS AuthKit
   page), then create the tenant and first workspace at `/onboarding`.
2. Invite or create users from Settings.
3. Each developer installs the companion package with the command shown in
   Settings -> Agent setup. Hosted deployments default to
   `npm install --save-dev https://<host>/downloads/co-vibe.tgz`; after public
   npm publication you may override that with `npm install --save-dev co-vibe`.
4. Each developer runs `npm exec -- covibe-local setup --base-url <host>` and
   `npm exec -- covibe-local doctor --base-url <host>`. Use the hosted origin
   only, such as `https://co-vibe.example.com`; setup and doctor reject
   credential-bearing URLs, callback URLs, query strings, hashes, or other paths
   before writing or trusting local config.
5. With no token exported, setup starts the browser device flow: it prints a
   short code, the developer approves the request in the console at
   `/setup/authorize`, and per-agent typed tokens land in the developer's
   `~/.covibe/credentials.json` (mode 0600) — no manual token creation or
   export needed (see [`device-setup.md`](./device-setup.md)).
6. Alternatively, a manually created token from Settings -> Agent setup can be
   exported as `COVIBE_MCP_TOKEN` before setup; it keeps precedence over the
   credentials file, is used for setup checks, and is never written to repo
   config. Keep it set when launching agents on this legacy path.
7. The Agent Setup copy block runs `covibe-local doctor` against the same
   hosted origin after setup and then exits; it does not start the long-running
   watch loop.
8. Setup installs one machine-level watch service by default (skip with
   `--no-service`): a `tech.covibe.companion` launchd LaunchAgent on macOS or
   a `covibe-companion` systemd user unit on Linux, starting at login and
   restarting on failure. It syncs snapshots, telemetry inbox flushes, and
   session heartbeats for every repo that registered itself from agent
   activity against this server — no per-repo watcher or per-repo registration
   command. The unit embeds no token; credentials are re-read from
   `~/.covibe/credentials.json` at runtime, so token rotation needs no
   reinstall. `npm exec -- covibe-local service install --base-url <host>`
   (re)installs it manually — required when setup ran from a temporary npx
   cache, which refuses the install and prints this fix — and `service status`
   / `service uninstall` manage it; on Linux, `loginctl enable-linger` keeps
   it alive after logout. Installing also migrates and removes any legacy
   per-repo units.
9. For foreground debugging, `npm exec -- covibe-local watch --base-url <host>`
   runs the same machine-level loop in a terminal, and `--repo <path>`
   restricts it to a single repo.

Setup tells each developer that repos they work in are logged to Co-Vibe
unless excluded; a developer keeps a personal repo private with
`npm exec -- covibe-local exclude` in that repo (see
[`device-setup.md`](./device-setup.md)).

The hosted app never needs to run on developer laptops for normal customer use.
Only the local companion runs beside Claude Code, Codex, Cursor, or another
agent runtime.
