Loading...
Loading...
Use when building or maintaining real-time collaborative apps with the DeepSpace SDK on Cloudflare Workers — scaffolding new apps, adding features, debugging a `worker.ts` that imports from `deepspace` / `deepspace/worker` or uses `RecordRoom`, `__DO_MANIFEST__`, or `npx deepspace`. Also use when the user mentions DeepSpace or app.space, or asks for anything involving real-time sync, multiplayer state, live cursors / presence, whiteboards or canvases, collaborative text editing (Yjs), channel-based chat, per-role permissions (RBAC), Durable Object rooms, Stripe-backed subscriptions / paywalls / one-time products / tips / refunds, or one-package deploy to `.app.space` — even if they don't name DeepSpace explicitly.
npx skill4agent add deepdotspace/deepspace-skill deepspace<name>.app.spacedevtest.dev.varssecret_textdeploy# 1. Scaffold (no auth required — npm fetches create-deepspace via npx on demand)
npm create deepspace@latest <app-name>
cd <app-name>
# <app-name> seeds the directory AND wrangler.toml's `name` (= deploy subdomain),
# but both are editable after scaffold — see references/architecture.md § App-name
# rules. Scaffold into the directory you want; don't scaffold-then-move.
#
# CLI is non-interactive by default (agent-friendly): omitting <app-name> prints
# usage and exits 1 instead of prompting on stdin. Pass `--interactive` / `-i`
# for the prompt-driven wizard. Probe with `--help` / `-h` (plain stdout, no
# ANSI) or `--version` / `-v` before invoking when scripting.
# Three invocation forms work — the scaffolder is permissive about target state:
# a) From a parent dir, target does not exist: creates <app-name>/ fresh.
# b) From a parent dir, target is near-empty: scaffolds in-place into <app-name>/.
# c) From inside the target dir (any near-empty): scaffolds in-place into cwd; pass `.`
# to inherit the dir's name (lowercased).
# "Near-empty" = only boilerplate is allowed: .git, .gitignore, .gitattributes,
# .github/, LICENSE*, README*, any *.md, .vite, .wrangler, .dev.vars, .DS_Store.
# Anything else triggers `Directory <name> already exists` and the scaffolder bails.
# `.git` is allowed but not required — empty / unversioned dirs scaffold fine,
# and a trailing `git init` runs only when no `.git` exists yet.
# 2. One-time login — opens browser, polls up to 10 minutes. Interactive; pause and
# have the user complete the OAuth flow at the keyboard.
npx deepspace login
# 3. Local dev (Vite + worker in-process; HMR on localhost:5173, --strictPort fails loudly on clash)
npx deepspace dev # default
npx deepspace dev --port 5180 # parallel apps
npx deepspace dev --prod # same UI, but workers point at production
# 3a. Clean up leaked workerd/vite (your own — never a sibling session's):
npx deepspace kill # kills listener on 5173 + its workerd children
npx deepspace kill --port 5180 # different port
npx deepspace kill --all # sweeps every workerd/wrangler/vite on the box
# 4. Provision test accounts (one-time per machine; pool is shared across all apps, hard cap of 10)
npx deepspace test-accounts list # check what's already there
npx deepspace test-accounts create --email <…@deepspace.test> --password <p> --name <n>
# 5. Run tests (auto-installs Playwright + chromium on first run; always uses dev workers)
npx deepspace test # default suite (smoke + api)
npx deepspace test e2e # all Playwright specs
npx deepspace test unit # vitest
# 5a. Capture a Playwright screenshot of any URL (shares the same chromium install as `test`).
npx deepspace screenshot http://localhost:5173/ out.png
npx deepspace screenshot http://localhost:5173/ out.png --full-page --wait-for-timeout 500
# 6. Install scaffold features
# MUST run `add --list` in THIS session before hand-rolling any non-trivial UI —
# building from scratch when a scaffold feature exists is a defect. Never claim
# to have run it without actually executing it and quoting the output; prior
# knowledge of the feature set does not count.
npx deepspace add --list # REQUIRED first — discover available features
npx deepspace add --info <name> # inspect what a feature installs
npx deepspace add <feature> # install into current app
# 7. Discover & test platform integrations from the CLI
# Discovery is free (no login, no app dir, no dev server) — agents can probe the
# catalog cold. Only `invoke <ep> --body` actually calls the endpoint and is
# billed to the logged-in user.
npx deepspace integrations list # NO AUTH — full catalog
npx deepspace integrations info openai/chat-completion # NO AUTH — schema + example body for one endpoint
npx deepspace invoke openai/chat-completion --body '{...}' # AUTH REQUIRED — actually call it (billed to caller)
npx deepspace invoke openai/chat-completion --body-file - # AUTH REQUIRED — body via stdin (cat req.json | …)
# `npx deepspace invoke --list` and `--info` are aliases for the no-auth forms above.
# 8. Deploy (subdomain comes from wrangler.toml's `name` field — rename there, not at deploy time)
npx deepspace deploy # → <wrangler.name>.app.space
# 9. (Optional) Buy & attach a custom domain to the deployed app
npx deepspace domain search <query> # find available domains and prices
npx deepspace domain buy <domain> # buy via Stripe Checkout (browser opens)
npx deepspace domain list # list domains you own
npx deepspace domain attach <domain> --app <name> # re-point a domain at a different app
# 10. (Optional) Publish the deployed app to the DeepSpace community library
npx deepspace library publish [--name "<title>"] [--description "<short>"] [--category <cat>]
npx deepspace library unpublish <handle>
# 11. (Optional) Provision a DeepSpace-managed GitHub repo for users without their own GitHub account
npx deepspace managed-repos list
npx deepspace managed-repos create <app-name> # platform-owned private repo
npx deepspace managed-repos token <repo-id> # short-lived clone token
npx deepspace managed-repos delete <repo-id> --yes # per-day quota appliesdeepspace logindevtest-accountsdeploynpx deepspace whoami--json~/.deepspace/sessionwhoami// Frontend (React)
import { RecordProvider, RecordScope, useQuery, useMutations, useAuth } from 'deepspace'
// Worker (Cloudflare Worker)
import { RecordRoom, verifyJwt, CHANNELS_SCHEMA } from 'deepspace/worker''deepspace/server'captureScreenshotreferences/payments.mdreferences/sdk-reference.md'deepspace/testing'references/testing.md| Path | Purpose |
|---|---|
| Hono app worker; |
| Cloudflare config. |
| Provider stack: |
| File-based routes via generouted. |
| Collection schemas. Ships |
| 15 theme presets; active one set on |
| Tailwind v4 entry; |
| Top-nav entries — add new pages here so |
| |
| Server-action handlers. |
| Scheduled tasks for |
| Background-job handlers for |
| Per-integration billing config ( |
| System prompt + tool allowlist for |
| Hono handlers for the 4 AI chat endpoints ( |
| Playwright |
namecolumnspermissionssrc/schemas/src/schemas.tsusersSchemaUSERS_COLUMNSdeepspace/workeruseUseruseUsers'users'settingsSchemaCHANNELS_SCHEMAMESSAGES_SCHEMAREACTIONS_SCHEMAdeepspace/workerreferences/schemas.mdworkspace:*dir:*conv:*/ws/:roomIdPLATFORM_WORKERreferences/architecture.mdsrc/pages/(protected)/references/auth.md<html data-theme="...">index.html<title>slatereferences/uiux.mdsrc/pages/deepspacenode_modules/deepspace/features/npx deepspace add <feature>--listreferences/uiux.mdreferences/testing.mdsmoke.spec.tsapi.spec.tscollab.spec.tstscnpx deepspace deployreferences/uiux.mduseAuthuseQueryuseMutationsreferences/sdk-reference.mdconst { records, status } = useQuery<Item>('items', { where: { status: 'published' }, orderBy: 'createdAt' })
const { create, put, remove } = useMutations<Item>('items') // create returns Promise<string> (the new recordId — capture it)
const { isSignedIn, isLoaded } = useAuth() // primary auth check{ recordId, data: T, createdBy, createdAt, updatedAt }.datar.data.titler.titler.recordIdputremoveputPartial<T>{...existing, ...patch}put(id, { completed: true })createTreferences/sdk-reference.mdnode_modules/deepspace/dist/index.d.tsnode_modules/deepspace/dist/worker.d.tsreferences/server-actions.mdreferences/ai-chat.mdAppCronRoomuseCronMonitorreferences/cron.mdAppJobRoomuseJobsreferences/jobs.mduseSubscriptionuseCheckoutrequireSubscriptionreferences/payments.mduseGameRoomGameRoomreferences/sdk-reference.md"auto"runMigrationsmeterAimeterVectorizeUSAGE_EVENTSreferences/bindings.mdintegration.post(...)import { integration } from 'deepspace'
const result = await integration.post('openweathermap/geocoding', { q: city })
// Returns: { success: true, data: <endpoint-specific> } | { success: false, error: string }<integration>/<endpoint>geocode-cityweather-forecastnpx deepspace integrations listinfo <ep>integration.post(...)references/integrations.mdnpx deepspace loginnpx deepspace whoami--jsondevtestdeploywhoamiNot logged indevtestdeploy~/.deepspace/sessionNot logged intimeout Nsleep N && killtimeoutnpx deepspace whoamidevtestdeploy.dev.varsAPP_OWNER_JWTnpx deepspace testsmoke.spec.tsapi.spec.tscollab.spec.tsreferences/testing.md'deepspace/testing'src/worker.tsnpx deepspace deployreferences/uiux.mdnpx deepspace deploy # → <wrangler.name>.app.spacenamewrangler.tomldeploynpx deepspace login.dev.varsdevtestAUTH_JWT_PUBLIC_KEYAUTH_JWT_ISSUERAUTH_WORKER_URLAPI_WORKER_URLPLATFORM_WORKER_URLOWNER_USER_IDAPP_OWNER_JWTAPP_IDENTITY_TOKENALLOW_DEBUG_ROUTES# --- not managed by the SDK; preserved across dev/test runs ---APP_IDENTITY_TOKENnpx deepspace deploycaptureScreenshotreferences/payments.mdreferences/sdk-reference.mddevtestsecret_textdeployenv.MY_KEYwrangler secret put^[A-Za-z_][A-Za-z0-9_]*$RESERVED_BINDING_NAMES__DO_MANIFEST__references/bindings.md.dev.varsAPP_OWNER_JWTcat .dev.varsheadgrepReadgrep -l '^STRIPE_SECRET_KEY=' .dev.varsMY_KEY=… npx deepspace devps aux.dev.varsenv.MY_KEY.dev.vars.gitignore!git add -f .dev.varsgit statusexpect(env.STRIPE_SECRET_KEY).toBe('sk_live_…')KEY=value.dev.varsnpx deepspace devdeploysecret_textwrangler secret putRead| Reference | Read before |
|---|---|
| Reaching for any hook, type, or export beyond |
| Defining a collection, picking a permission rule, debugging "why can't this user see/edit X," wiring |
| Choosing the auth model (public / gated / mixed), adding |
| Editing |
| Adding privileged writes that bypass the caller's RBAC. |
| Adding a streamed chat UI with tool use over the app's records. |
| Adding scheduled tasks, building the admin cron monitor, testing cron via |
| Adding background-job handlers (AI generation, exports, renders), choosing client vs server enqueue, handling progress / cancellation / multi-tick checkpoints. |
| Declaring custom Cloudflare bindings (Vectorize / R2 / KV / D1 / Queues / AI / Browser / Hyperdrive / AE), |
| Calling external APIs (LLMs, search, media, social, finance, etc.). |
| Anything involving money, Stripe, billing, paywalls, subscriptions, pricing pages, "Upgrade" buttons, Pro / premium tiers, gating features behind a plan, one-time products, tips, donations, free trials, refunds, or cancellation. Never hand-roll Stripe in a DeepSpace app — declare in |
| Buying / attaching / managing a custom domain ( |
| Adding audio/video rooms — token mint, billing model, room lifecycle. |
| Calling Gmail / Calendar / Drive / Contacts — per-user billing, scope step-up, |
| Working on theme, home page, primitives, interaction polish, or "feels generic" feedback. Trigger especially when about to use |
| Writing or extending specs, applying the Step 8 checklist, building multi-user flows, route coverage, debugging flaky tests. |
| Building marketing / landing / splash pages, addressing "feels AI-generated" feedback, customizing the scaffolded |
_app.tsxToastProvidersrc/components/ui/deepspaceuseToastdeepspaceuseToast must be used within ToastProvider../components/uideepspacereferences/uiux.mdsrc/pages/src/features/<name>/foo-sitefoo-mainfoo-sitewrangler.tomlnamefoo-mainfoo-maingit init.wrangler/references/architecture.md/api/*wsRouteuserIduserNameuserEmailuserImageUrlrole/api/*X-User-IdX-App-Actionanon-<uuid>workspace:*dir:*conv:*tests/playwright.config.tsreuseExistingServer: truenpx deepspace kill--all--port 5174tests/playwright.config.tswebServer.portuse.baseURL