# wzrrd.sh

Agent-first static Site and Pro video publishing on Cloudflare.

## What works now

- Publish static files or directories to `https://<slug>.wzrrd.sh/` anonymously with no setup.
- Claim an anonymous 24-hour Site after GitHub sign-in, or publish owned Sites with a saved Better Auth session.
- Inspect and manage owned Site metadata, indexing, expiration, and Organization Profile listing through CLI/API.
- Upload Pro video directly to R2, then let one Cloudflare Workflow own Stream encoding, Deepgram transcription, six-language subtitles, status history, and finalization.
- Trace video requests through Analytics Engine wide events and hard-revoke the watch share, provider copy, and R2 original.
- Discover the complete HTTP surface from one OpenAPI 3.1 contract. The CLI is hand-designed and is not generated.
- Current framework/SSR deploy commands still record receipts only; they do not deploy a live framework app.

## Install

Teach an agent:

```bash
npx skills add wzrrd-sh/wzrrd-cli --skill wzrrd-publish -g
```

Install the CLI:

```bash
curl -fsSL https://wzrrd.sh/install.sh | bash
```

The installer writes `~/.local/bin/wzrrd` and a typo-tolerant `wzzrd` alias. It does not shadow the system `w` command.

## Static Site quick start

```bash
wzrrd publish --file ./site --slug demo
```

Anonymous publishing needs no login. The Site expires after 24 hours, is `noindex` by default, and returns `claimUrl` for human ownership. Report both URLs. Use `--index` only when requested.

Projects can define `site.slug` and `publish.source` in `wzrrd.config.json`; schema: `https://wzrrd.sh/schema/config.json`.

Owned Site commands:

```bash
wzrrd site list
wzrrd site status --slug demo
wzrrd site set --slug demo --title "Demo" --description "Tiny preview" --indexing index
wzrrd site set --slug demo --expires-in 7d
wzrrd site set --slug demo --permanent
wzrrd site delete --slug demo
```

## Authentication

```bash
wzrrd auth-status
# Human terminal only when no live session exists:
wzrrd login
```

Static publishing does not require login. Owned Site mutations and Pro video do. Device login requires one human GitHub approval. Ask the human to run `wzrrd login` in their own interactive terminal and wait until it stores the session at `~/.config/wzrrd/auth.json`; then rerun `wzrrd auth-status`. An unattended run exits with `status: "awaiting_human_approval"` but cannot complete or resume the device-token exchange. Do not run `--no-open` and pretend approval alone saved a session.

## Pro video quick start

```bash
wzrrd video upload ./demo.mp4 --title "My demo"
wzrrd video status <slug>
wzrrd video trace <slug>
wzrrd video revoke <slug>
```

`video upload` streams the local file straight to an insert-only presigned R2 PUT, explicitly completes verification, and follows the cloud Workflow. Stdout stays one JSON receipt containing `watchUrl`, `shareSlug`, and `next_actions`; progress goes to stderr. Use `--no-wait` to return after the Workflow starts. v0 rejects files larger than 5 GiB and points to `sourceUrl` mode.

A 403 saying video publishing is a Pro feature is an entitlement refusal. Surface it; do not bypass it. Completed videos expose English plus translated captions (en, es, pt, fr, de, ja) at `/v/<slug>/captions.vtt` and `/v/<slug>/captions.<lang>.vtt`.

More video commands:

```bash
wzrrd video transcribe <slug>
wzrrd video transcribe --force <slug>
wzrrd video publish --provider <provider> --provider-asset-id <id> --playback-id <id> --title "Title"
wzrrd video transcript <slug> --vtt-key <r2-key>
```

The low-level provider/transcript verbs are integration paths. Normal Pro publishing should use `video upload`. Hard revoke verifies the R2 original is absent before completing the tombstone; failed cleanup stays retryable.

### Raw API upload sequence

Prefer the CLI. A direct API client must:

1. `POST /api/videos/uploads` with the wzrrd bearer session.
2. PUT bytes to the returned top-level `uploadUrl` using only `upload.headers`. Never send the wzrrd bearer token or cookies to R2.
3. `POST /api/videos/uploads/{shareSlug}/complete` with the wzrrd bearer session.
4. `GET /api/videos/{shareSlug}/status` until terminal.
5. `POST /api/videos/{shareSlug}/revoke` when cleanup is required.

Request/response schemas live in the OpenAPI contract.

## Organization Profiles

```bash
wzrrd org profile status
wzrrd org profile enable --handle my-handle
wzrrd org profile disable
wzrrd site profile --slug demo --listed true
```

Profiles are explicit, opt-in Organization pages at `https://wzrrd.sh/@<handle>`; feeds are at `https://wzrrd.sh/@<handle>/feed.json`.

## Diagnose

```bash
wzrrd doctor && wzrrd auth-status
```

Use this before guessing. It checks root app, wildcard router, auth/session state, and core storage connectivity.

## MCP

Connect a Streamable HTTP MCP client to `https://wzrrd.sh/mcp` with the same wzrrd bearer credential used by the HTTP API. Protected-resource metadata is at `https://wzrrd.sh/.well-known/oauth-protected-resource`. The server derives six schemas from OpenAPI: `listSites`, `publishSite`, `createVideoUpload`, `getVideoStatus`, `transcribeVideo`, and `revokeVideo`. Pro enforcement stays at the underlying API boundary. Local files cannot cross a remote MCP call, so use the CLI for local video upload or give `createVideoUpload` a public `sourceUrl`.

## Machine-readable discovery

- OpenAPI JSON: https://wzrrd.sh/openapi.json
- OpenAPI YAML: https://wzrrd.sh/openapi.yaml
- Generated API catalog: https://wzrrd.sh/.well-known/api-catalog
- Agent Auth discovery: https://wzrrd.sh/.well-known/agent-configuration
- OAuth protected-resource discovery: https://wzrrd.sh/.well-known/oauth-protected-resource
- Agent skills index: https://wzrrd.sh/.well-known/agent-skills/index.json
- Hosted publish/video skill: https://wzrrd.sh/.well-known/agent-skills/wzrrd-publish/SKILL.md
- Agent card: https://wzrrd.sh/.well-known/agent-card.json
- MCP server card: https://wzrrd.sh/.well-known/mcp/server-card.json

## Complete HTTP operation inventory

This inventory is rendered from `openapi.yaml`, not maintained separately.

- `GET /mcp` — Open the optional MCP server message stream (bearerSession | agentGrantBearer | bootstrapOperatorBearer | videoServiceBearer)
- `POST /mcp` — MCP server (Streamable HTTP transport) (bearerSession | agentGrantBearer | bootstrapOperatorBearer | videoServiceBearer)
- `OPTIONS /mcp` — Read MCP transport method and header support (anonymous allowed)
- `GET /openapi.json` — Read the OpenAPI contract as JSON (anonymous allowed)
- `GET /openapi.yaml` — Read the canonical OpenAPI contract as YAML (anonymous allowed)
- `POST /api/agent-grants/request` — Request a capability-scoped agent grant (anonymous allowed)
- `GET /api/agent-grants/status` — Poll an agent grant (anonymous allowed)
- `POST /api/agent-grants/approve` — Approve an agent grant (anonymous allowed; operator-only)
- `GET /api/auth/{all}` — Delegated Better Auth GET operation (anonymous allowed)
- `POST /api/auth/{all}` — Delegated Better Auth POST operation (anonymous allowed)
- `PUT /api/auth/{all}` — Delegated Better Auth PUT operation (bearerSession | betterAuthCookie)
- `PATCH /api/auth/{all}` — Delegated Better Auth PATCH operation (bearerSession | betterAuthCookie)
- `DELETE /api/auth/{all}` — Delegated Better Auth DELETE operation (bearerSession | betterAuthCookie)
- `GET /api/auth/github` — Redirect to the Better Auth GitHub callback (anonymous allowed)
- `GET /api/sites` — List Sites (anonymous allowed)
- `POST /api/sites` — Publish a static Site (anonymous allowed)
- `GET /api/sites/{slug}` — Read a Site record (anonymous allowed)
- `PATCH /api/sites/{slug}` — Update Site metadata or lifecycle (bearerSession | betterAuthCookie | agentGrantBearer | bootstrapOperatorBearer)
- `DELETE /api/sites/{slug}` — Delete a Site (bearerSession | betterAuthCookie | agentGrantBearer | bootstrapOperatorBearer)
- `POST /api/sites/{slug}/profile` — List or unlist a Site on its Organization Profile (bearerSession | betterAuthCookie)
- `GET /claim/{slug}` — Claim an anonymous Site through the browser session flow (betterAuthCookie | bearerSession)
- `GET /api/org/profile` — Read the active user's Organization Profile (bearerSession | betterAuthCookie)
- `PUT /api/org/profile` — Enable, update, or disable the active user's Organization Profile (bearerSession | betterAuthCookie)
- `GET /api/ssr-sites` — List registered prototype SSR Sites (anonymous allowed)
- `POST /api/ssr-sites` — Register a prototype SSR Site (bearerSession | betterAuthCookie | agentGrantBearer | bootstrapOperatorBearer)
- `GET /api/webhooks` — List Pro outbound webhook registrations (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `POST /api/webhooks` — Register a Pro outbound webhook (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `DELETE /api/webhooks/{id}` — Remove a Pro outbound webhook (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `POST /api/videos` — Register an existing provider video (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `POST /api/videos/uploads` — Create a direct R2 upload session or mirror a source URL (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `POST /api/videos/uploads/{shareSlug}/complete` — Verify a direct R2 upload and start its Workflow (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `GET /api/videos/{shareSlug}/status` — Read video and Workflow status (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `POST /api/videos/{shareSlug}/transcribe` — Start or restart transcription (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `PATCH /api/videos/{shareSlug}/transcript` — Store an inline transcript or attach transcript artifacts (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `POST /api/videos/{shareSlug}/revoke` — Revoke a video and its original (videoServiceBearer | bootstrapOperatorBearer | bearerSession | betterAuthCookie)
- `GET /v/{slug}/poster.jpg` — Read the visibility-gated progressive JPEG poster (anonymous allowed)
- `GET /v/{slug}/captions.vtt` — Read English WebVTT captions (anonymous allowed)
- `GET /v/{slug}/captions.{lang}.vtt` — Read translated WebVTT captions (anonymous allowed)
- `POST /api/webhooks/stream` — Receive a Cloudflare Stream provider callback (streamWebhookSignature; provider callback)
- `POST /api/webhooks/deepgram` — Receive a Deepgram transcription callback (deepgramCallbackToken; provider callback)
- `POST /api/testing/pro-session` — Mint a deterministic Better Auth testing session (bootstrapOperatorBearer; operator-only)
- `PUT /api/testing/pro-entitlement` — Enable the fixed Pro test identity entitlement (bootstrapOperatorBearer; operator-only)
- `DELETE /api/testing/pro-entitlement` — Disable the fixed Pro test identity entitlement (bootstrapOperatorBearer; operator-only)

## Raw agent prompt

```txt
Publish this artifact with wzrrd.sh.

AGENT RULES:
1. For a static file or directory, publish immediately without login:
   wzrrd publish --file <path> --slug <slug>
2. Return the JSON receipt's live url. If it includes claimUrl, return that too and say the anonymous Site expires in 24 hours unless claimed.
3. For video, first run wzrrd auth-status. If no live session exists, ask the human to run wzrrd login in their own interactive terminal and wait for completion. An agent cannot finish device approval or save the resulting session by itself.
4. Upload video with: wzrrd video upload <file> --title "<title>"
5. Follow JSON next_actions. Revoke disposable test videos when finished.
6. If wzrrd is missing: curl -fsSL https://wzrrd.sh/install.sh | bash
```
