Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions docs/workers-deployment-test-findings-2026-09-21.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Workers open-source deployment findings — 2026-09-21

## Scope

This record covers two real preview deployments:

- a Next.js 16 application adapted with Vinext and packaged as Wrangler's
native multipart bundle;
- a Vite SPA with a Worker-first `/api/*` route and xAPI AI calls.

Both applications were published through xAPI Workers. Wrangler was used only
for local framework packaging where needed.

## Existing platform work that must not be duplicated

xapi-backend PRs #248 and #250 already provide the backend contract used by
these deployments:

- complete code-module and static-asset Artifacts;
- multipart upload with bounded memory and integrity verification;
- native Smart Placement metadata;
- D1/R2 default resource location;
- web-application completeness checks before provider or financial effects.

#250 is the clean promotion replay of #248, not a second implementation. This
CLI branch must remain complementary to that backend work.

## Confirmed CLI gaps addressed here

1. Generated Wrangler metadata such as `configPath`, `userConfigPath`, and
`definedEnvironments` was reported as unsupported even though it is build
provenance, not Worker runtime state.
2. Wrangler `vars` were combined with Secret names. Public values must not be
copied, leaked into reports, or silently converted into Secrets.
3. Wrangler imports always generated `npm run build` and
`dist/worker.mjs`, even when a framework package already declared a native
`build:worker` command and `--outfile` bundle.
4. The repository may contain Workers commands before the currently published
npm package. Skills need to detect and report that release mismatch.
5. Project commands and low-level Artifact primitives appeared in one flat help
list. Help now makes `plan → push → promote` the normal path and labels
`build`, `upload`, and `deploy` as custom-CI or recovery operations.
6. Runtime inspection required several separate commands. `workers inspect`
now provides one read-only report while preserving failed sources as
`UNKNOWN` and excluding Secret values.
7. Preview push could create the Worker, budget, or managed resources before a
failing application build. `plan` and `push` now share one local preparation
path: build, validate the complete native Artifact, calculate the live diff
and cost-impact evidence, then allow remote writes. Push returns a read-only
inspection after the ACTIVE deployment and public health check.
8. A real Jev `workers plan --format json` exposed build progress on stdout,
corrupting the machine-readable plan even though the build succeeded. Build
stdout/stderr now remain visible on stderr; stdout is reserved for the CLI
result contract.

## Command boundary after the deployment tests

- `workers inspect` answers what is running now. It needs no local build and
never evaluates application routes.
- `workers plan` answers what the next deployment will change. It creates local
build output, validates its exact hash and assets, reads live state and the
available price-book metadata, and performs no remote write.
- `workers push` repeats that deterministic preparation, displays the final
plan, waits for confirmation, applies preview changes, and returns inspection
evidence.
- `workers promote` releases the accepted immutable Artifact to production.

## Deferred backend work

The following should be implemented only after the native deployment candidate
has completed its normal dev → staging → main promotion:

- first-class desired state and API mutations for Cloudflare `plain_text`
bindings;
- one correlation ID spanning Dispatcher/User Worker logs and downstream xAPI
AI usage records;
- structured runtime error classes that distinguish Worker, xAPI gateway,
provider, authentication, and response-schema failures.

Until plain-text bindings exist, the importer fails closed on non-empty
Wrangler `vars`. `--accept-partial` records an explicit user decision but still
does not copy their values.

## Items confirmed outside platform scope

- model output that omitted application-specific JSON fields;
- selecting Gemini or DeepSeek instead of native Jev;
- drone hover/landing control behavior;
- browser-cookie quotas;
- absence of KV, D1, R2, Queue, Durable Object, or Workflow when the application
does not require them.

These are application design or integration concerns and must not be fixed by
restricting the Workers platform.
4 changes: 2 additions & 2 deletions skills/xapi-workers/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ description: Deploy, operate, and verify applications on xAPI-managed Cloudflare

# xAPI Workers for Platforms

Use the `xapi` CLI (`xapi-to` is the same executable). Verify `xapi workers --help` before using it; an older installation may lack these commands. Do not silently replace managed deployment with Wrangler direct deployment.
Use the `xapi` CLI (`xapi-to` is the same executable). Verify `xapi workers --help` before using it; an older published installation may lack these commands even when the repository already contains them. Stop and report the version mismatch instead of silently replacing managed deployment with Wrangler direct deployment. Wrangler `deploy --dry-run --outfile` is allowed only as a local framework packaging step; the resulting Artifact must still be published with xAPI.

## Start with scope

- Identify the control-plane host, Worker ID, and **preview or production** from the project and `workers get`. Test control plane and preview environment are separate choices.
- Authentication precedence: `XAPI_KEY`, `XAPI_API_KEY`, then `~/.xapi/config.json`. Keys need `workers:read` and, for changes, `workers:write`, plus access to the target Worker. A scoped-out Worker can return 404.
- Production API host is `api.xapi.to`; testing uses `XAPI_API_HOST=api.test.xapi.to` (host only). Load secrets from the user's existing secure environment. Never print keys, include them in code/artifacts, or send the xAPI key to a public Worker URL or Cloudflare. Runtime application authentication is separate.
- Start with `workers get <worker-id>`, `workers capabilities`, and `workers resources list <worker-id> --env <environment>`. Read-only inspection needs no extra approval. Use existing user authorization for changes; don't expand cleanup from a test environment to production.
- Start with `workers inspect [worker-id] --env <environment>` and `workers capabilities`. Use `workers plan --env <environment>` when a local project is available and desired-state drift matters. `inspect` reads current runtime state only. `plan` runs the configured local build with credential-shaped environment variables removed, validates the exact Artifact, and compares it with live state without writing to the xAPI control plane. It also shows the budget cap, active price-book visibility, and usage-dependent resource changes; never present those estimates as an accrued invoice. Use existing user authorization for changes; don't expand cleanup from a test environment to production.

## Load the relevant workflow

Expand Down
33 changes: 32 additions & 1 deletion skills/xapi-workers/references/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@

## Project workflow

Use one command layer for one task. For normal application deployment, stay in
the project workflow:

| Intent | Command | Writes live state |
| --- | --- | --- |
| Inspect one running environment | `workers inspect [worker-id] --env ENV` | No |
| Build locally and compare exact desired state with xAPI | `workers plan --env ENV` | No remote writes |
| Rebuild, present the final plan, reconcile and deploy preview | `workers push --env preview` | Yes, after confirmation |
| Release the accepted preview Artifact | `workers promote --to production` | Yes |
| Restore an earlier active version | `workers rollback --env ENV ...` | Yes |

`workers inspect` accepts an explicit Worker ID or resolves it from the current
`xapi.worker.json`. It combines Worker, environment, active Artifact and
Deployment, routing, resource, Secret metadata, domain, and billing freshness
reads into one report. Optional read failures stay `UNKNOWN`, never zero or
success. It never reads Secret values and performs no health request that might
trigger application behavior. Use `workers plan` separately when comparing
local desired state with xAPI. Plan runs the configured local build first, validates
the native bundle and static assets, and then displays the exact Artifact hash,
resource/Secret/routing changes, budget-cap delta, price-book availability, and
usage-dependent cost effects. A budget is a cap rather than a predicted charge;
unknown traffic and storage must remain unknown.
`workers build`, `upload`, and `deploy` are lower-level Artifact primitives for
custom CI and recovery. A managed `build` only produces an Artifact; `deploy`
only activates an existing Artifact. Neither replaces project convergence by
`push`.

```sh
export XAPI_API_HOST=api.test.xapi.to
xapi workers templates
Expand Down Expand Up @@ -66,11 +93,15 @@ Rollback restores code and compatibility settings, not data, schema, Secret valu

Use the project's installed/pinned CLI, lockfile installation, and a scoped secret `XAPI_KEY`. Keep `XAPI_API_HOST` explicit and separate test/production credentials. CLI deployment does not require SSH into an API server or a Cloudflare account token.

Run plan, build/push, active-status and business checks in order. `--non-interactive` suppresses prompts; it does not accept retention policy or bypass preflight:
Run plan, push, inspect, active-status and business checks in order. Both plan
and push prepare the local Artifact; push performs that work before any Worker,
budget, resource, Artifact, or Deployment write. `--non-interactive` suppresses
prompts; it does not accept retention policy or bypass preflight:

```sh
xapi workers plan --env preview --format json
xapi workers push --env preview --non-interactive
xapi workers inspect --env preview --format json
```

Promote in the already authorized release job after preview acceptance. Follow repository AGENTS.md and branch/PR rules; do not infer release authorization from a successful preview push. On uncertain results inspect deployments/logs and retry unchanged inputs so stable idempotency keys can recover the same operation. Do not change IDs or clear deletion flags to force deployment through.
Expand Down
2 changes: 1 addition & 1 deletion skills/xapi/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Use granular commands only for multi-step work. Keep the instance ID, terminate

## Hosted Workers

Read `guides/workers.md` before creating, importing, planning, pushing, promoting, rolling back, attaching Cloudflare resources, scheduling tasks, or inspecting logs. Workers are continuously addressable JavaScript applications; Sandbox is ephemeral arbitrary compute. Prefer the project workflow: `workers init`, `workers plan --env preview`, `workers push --env preview`, then `workers promote --to production`. `init` has distinct new-project, existing frontend, Wrangler import, and Next.js SSR adapter paths; select the matching path from the guide instead of repeatedly regenerating project files. Use `xapi.worker.json` as managed-resource desired state, let `plan` compare live state, and use `workers resources pull` only to adopt healthy remote-only resources. Git is optional. `push` builds and uploads an immutable Artifact, including separately declared native static assets, uses stable recovery keys, and never silently deletes stateful resources or Secrets. For web applications, inspect `webAppReady`: path-prefix-aware applications can use fallback routing, while root-relative routes and OAuth callbacks need a dedicated hostname. An optional platform-owned ephemeral Sandbox build can produce the same Artifact type. Rollback restores code and compatibility settings, never KV/D1/R2/DO/Queue/Workflow/schedule data or Secret values. Run the provider capability check before provisioning so missing permissions such as D1 Edit are reported precisely. KV, D1, R2, Durable Object, Queue, Workflow, Secret, schedule, managed-domain, observability, and billing data are environment- or Worker-scoped; never assume preview and production share state. Queue messages use the documented route envelope, are delivered at least once, and require an idempotent target route. Only `ACTIVE` means deployment succeeded.
Read `guides/workers.md` before creating, importing, planning, pushing, promoting, rolling back, attaching Cloudflare resources, scheduling tasks, or inspecting logs. Workers are continuously addressable JavaScript applications; Sandbox is ephemeral arbitrary compute. Prefer the project workflow: `workers init`, `workers plan --env preview`, `workers push --env preview`, then `workers promote --to production`. `init` has distinct new-project, existing frontend, Wrangler import, and Next.js SSR adapter paths; select the matching path from the guide instead of repeatedly regenerating project files. Use `xapi.worker.json` as managed-resource desired state. `plan` runs and validates the configured local build, compares its exact Artifact and resource declarations with live state, and shows budget/price-book impact without remote writes; `inspect` reports what is already running. Use `workers resources pull` only to adopt healthy remote-only resources. Git is optional. `push` prepares the same immutable Artifact before any remote mutation, including separately declared native static assets, shows the final plan, uses stable recovery keys, and never silently deletes stateful resources or Secrets. For web applications, inspect `webAppReady`: path-prefix-aware applications can use fallback routing, while root-relative routes and OAuth callbacks need a dedicated hostname. An optional platform-owned ephemeral Sandbox build can produce the same Artifact type. Rollback restores code and compatibility settings, never KV/D1/R2/DO/Queue/Workflow/schedule data or Secret values. Run the provider capability check before provisioning so missing permissions such as D1 Edit are reported precisely. KV, D1, R2, Durable Object, Queue, Workflow, Secret, schedule, managed-domain, observability, and billing data are environment- or Worker-scoped; never assume preview and production share state. Queue messages use the documented route envelope, are delivered at least once, and require an idempotent target route. Only `ACTIVE` means deployment succeeded.

## Usage Workflow

Expand Down
35 changes: 34 additions & 1 deletion skills/xapi/guides/workers.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ source of truth for the entrypoint, compatibility settings, and static assets.
Managed KV, D1, R2, Durable Object, Queue, and Workflow declarations belong in
`xapi.worker.json`. The file contains no credential and may be committed.

Use `xapi workers inspect --env preview` for one read-only operational view of
the linked Worker. It reports the active environment, routing, Artifact,
Deployment, resource and Secret metadata, domains, and billing freshness.
Unavailable sources remain `UNKNOWN`. Use `plan` for desired-state comparison.
Plan runs and validates the configured local build, then compares that exact
Artifact and desired resources with the live snapshot. It performs no remote
writes. `inspect` never builds, deploys, probes application routes, or reads
Secret values.

Choose the `init` form from the project you actually have:

| Starting point | Command | What `init` does |
Expand Down Expand Up @@ -118,6 +127,13 @@ xapi workers push --env preview
write a partial project unless the user explicitly accepts the report with
`--accept-partial`.

Wrangler `vars` are public plain-text bindings. The importer never copies their
values and never silently converts them into encrypted Secrets. A non-empty
`vars` block is reported as `UNSUPPORTED` until xAPI desired state has an
explicit plain-text binding workflow. Move only genuinely sensitive values to
`secrets`, set them with `workers secrets set`, and keep public values out of
the generated project until the binding is supported.

The project workflow does not require Git. Git repository, branch, and commit
are optional provenance, not authentication and not a deployment prerequisite.
It runs the configured build, creates the remote Worker when `workerId` is
Expand All @@ -144,7 +160,7 @@ Choose the command by intent:
| Adopt live-only resources | `resources pull` | Live read, then safe local merge |
| Stop declaring a resource | `resources remove` | Local desired state only |
| Delete resource data | `resources destroy --yes` | Local desired state and one live environment |
| Check convergence | `workers plan` | None |
| Preview exact deployment changes | `workers plan` | Local build output only |

Use this normal flow to add a resource:

Expand All @@ -161,6 +177,12 @@ xapi workers plan --env preview
xapi workers push --env preview
```

`plan` reports the current and desired daily budget, active price-book
visibility, and any new metered Worker/resource declarations. Exact charges
remain usage-dependent; the CLI does not invent request, CPU, storage, or
operation volume. Use `inspect` and billing views for accrued usage and billing
freshness.

`--env both` creates matching declarations, not shared storage. `resources add`
is idempotent and rejects conflicting binding reuse. `resources update`
replaces the complete declaration. Before linking it can correct any local
Expand Down Expand Up @@ -232,6 +254,17 @@ npm run build
npx wrangler deploy --dry-run --config dist/server/wrangler.json --outfile dist/app.worker.bundle
```

When `package.json` contains a framework `build:worker` script with Wrangler's
`--outfile`, `init --from-wrangler` infers both the command and `.bundle` path.
Review the generated `xapi.worker.json`. If the framework uses a custom script,
provide the values during import instead of editing an ambiguous default:

```bash
xapi workers init --from-wrangler dist/server/wrangler.json \
--build-command "pnpm run package:worker" \
--build-output dist/app.worker.bundle
```

Point the project build output to `dist/app.worker.bundle`; omit `build.main`.
Set `assets.directory` to the framework's client output (for example
`dist/client`). Then use `xapi workers plan --env preview` and
Expand Down
Loading
Loading