deepspace

Installation
SKILL.md

DeepSpace SDK

Build real-time collaborative apps on Cloudflare Workers in one package: SQLite-backed Durable Objects, RBAC, WebSocket subscriptions, Better Auth. Scaffolds with sensible defaults — generouted file-based routing, shadcn/ui primitives, Vite + Tailwind v4. Apps deploy to <name>.app.space.

This skill targets deepspace and create-deepspace v0.2.4 (latest published on npm at 04/29/2026; verify with npm view deepspace version if drift is suspected).

Quickstart — the development lifecycle

CLI commands, in order. Each step is rerunnable. dev and test both regenerate .dev.vars on every run — don't hand-edit it; let the CLI manage it.

# 1. Scaffold (no auth required — npm fetches create-deepspace via npx on demand)
npm create deepspace@latest <app-name>
cd <app-name>

# 2. One-time login — opens browser, polls up to 10 minutes
npx deepspace login
# 2a. Non-interactive alternative for CI / headless agents:
npx deepspace login --email <e> --password <p>

# 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

# 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

# 6. Install scaffold features
npx deepspace add --list           # discover available features (18 ship out of the box)
npx deepspace add --info <name>    # see what a feature installs
npx deepspace add <feature>        # install into current app

# 7. Deploy (subdomain comes from wrangler.toml's `name` field — rename there, not at deploy time)
npx deepspace deploy               # → <wrangler.name>.app.space

Login state is shared across all apps on the machine. One deepspace login covers dev, test-accounts, and deploy for any app. Re-login only when ~/.deepspace/session is wiped or the session expires. See "Login, test, deploy" below for non-obvious rules.

Scaffolding from a local SDK checkout (DeepSpace team only)

For testing unreleased SDK changes. End users should always use npm create deepspace@latest.

# Local SDK (for development — replace path with your local SDK root).
# Requires a built dist/ — run `pnpm build` in <local-sdk-path>/packages/deepspace first.
<local-sdk-path>/packages/create-deepspace/dist/index.js <app-name> --local <local-sdk-path>

Two imports

// Frontend (React)
import { RecordProvider, RecordScope, useQuery, useMutations, useAuth } from 'deepspace'

// Worker (Cloudflare Worker)
import { RecordRoom, verifyJwt, CHANNELS_SCHEMA } from 'deepspace/worker'

A third entry point — 'deepspace/testing' — exports a Playwright fixture for multi-user specs. See references/testing.md.

Project layout

The scaffold generates a Vite + Cloudflare-Worker app. Files you'll touch most often:

Path Purpose
worker.ts Hono app worker; __DO_MANIFEST__ declares 5 DO classes (AppRecordRoom, AppYjsRoom, AppCanvasRoom, AppPresenceRoom, AppCronRoom). Edit when adding new DO classes / WebSocket routes, customizing AppRecordRoom options, switching the AI chat model or tools, adding custom HTTP routes, or wiring cross-app proxies.
src/pages/_app.tsx Provider stack: ToastProvider → DeepSpaceAuthProvider → AuthBoot → RecordProvider → RecordScope. Extend, don't replace.
src/pages/ File-based routes via generouted. (protected)/ is the gated route group.
src/schemas.ts + src/schemas/ Collection schemas. Ships usersSchema + settingsSchema.
src/themes.ts + src/themes.css 15 theme presets; active one set on <html data-theme> in index.html.
src/styles.css Tailwind v4 entry; @theme block holds the slate baseline.
src/nav.ts Top-nav entries — add new pages here so Navigation.tsx picks them up.
src/constants.ts APP_NAME, SCOPE_ID = "app:${APP_NAME}", role re-exports.
src/actions/index.ts Server-action handlers.
src/cron.ts Scheduled tasks for AppCronRoom.
src/integrations.ts Per-integration billing config (developer vs user).
src/ai/tools.ts System prompt + read-only tools for /api/ai/chat.
tests/ Playwright smoke.spec.ts / api.spec.ts / collab.spec.ts + playwright.config.ts.

Build a new app

Steps run in dependency order. Each links its deep-dive reference; load that reference only when you reach the step.

  1. Scaffold — see Quickstart.
  2. Schemas — define collections with name, columns, permissions. Add to src/schemas/, register in src/schemas.ts alongside usersSchema + settingsSchema (never replace those). For messaging, also add CHANNELS_SCHEMA / MESSAGES_SCHEMA / REACTIONS_SCHEMA from deepspace/worker. → references/schemas.md
  3. Cross-app data sharing? — if the app needs to read/write workspace:*, dir:*, or conv:* scopes shared across DeepSpace apps (e.g., the email-handle workspace, cross-app inbox), the scaffolded /ws/:roomId handler routes everything to the local DO and won't see shared data. Add the PLATFORM_WORKER proxy edit. → references/architecture.md § Cross-app shared scopes. Skip otherwise.
  4. Auth model — pick public, gated, or mixed (the default; gated routes drop into src/pages/(protected)/). → references/auth.md
  5. Theme — pick a preset on <html data-theme="..."> in index.html, update <title>/favicon. Don't ship the default slate.references/uiux.md §2
  6. Pages and features — pages in src/pages/. 18 ready features in .deepspace/features/; install with npx deepspace add <feature> (use --list to enumerate). → references/uiux.md for UI primitives.
  7. Tests — extend smoke.spec.ts / api.spec.ts / collab.spec.ts per the Step 8 checklist in references/testing.md.
  8. Deploynpx deepspace deploy. Pre-deploy checklist: home replaced, theme picked, browser-default primitives removed, toasts wired to mutations. → references/uiux.md §5

For maintenance work on an existing app, jump straight to the relevant reference.

Frontend hooks

The three hooks every app uses. For everything else (messaging, directory, R2, Yjs, presence, canvas, cron monitor, theme, env), see references/sdk-reference.md.

const { 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

Each record is an envelope{ recordId, data: T, createdBy, createdAt, updatedAt }. User fields live under .data (r.data.title, never r.title). Pass r.recordId to put / remove.

For exact type signatures, read node_modules/deepspace/dist/index.d.ts (frontend) or node_modules/deepspace/dist/worker.d.ts (worker). Do not guess hook names or argument shapes.

Worker-side extensions

Three independent surfaces. Load only what you need:

  • Server actions (privileged writes that bypass caller RBAC) → references/server-actions.md
  • AI chat (streamed Claude / OpenAI / Cerebras with read-only tool use) → references/ai-chat.md
  • Cron (scheduled tasks via AppCronRoom + useCronMonitor) → references/cron.md

Skip all three for apps that only need client hooks and integration.post(...).

Integrations

Call external APIs through the api-worker proxy:

import { integration } from 'deepspace'
const result = await integration.post('openweathermap/geocoding', { q: city })
// Returns: { success: true, data: {...} } or { success: false, error: "..." }

Endpoint names are two segments: <integration>/<endpoint>. Don't guess — names like geocode-city or weather-forecast aren't real and return 404 at runtime. Verify in assets/integrations/index.yaml before calling.

Auth-gate any UI that calls integration.post(...). Default billing is owner-pays. The api-worker accepts anonymous callers, so a public endpoint silently bills the owner for every visitor (or bot) hit. Wrap calling components in useAuth().isSignedIn.

Any integration.post(...) call requires an api.spec.ts extension that POSTs to /api/integrations/<endpoint> and asserts success: true with the data shape the UI consumes. This catches wrong endpoint names — the most common integration-heavy-app failure. See references/integrations.md and the Step 8 checklist in references/testing.md.

Login, test, deploy

Login (npx deepspace login)

The first run of dev/test/deploy requires a stored session at ~/.deepspace/session. If absent, the command exits with Not logged in. Run \deepspace login` first.` Five hard rules:

  1. Pause and tell the user. Login opens a browser tab (GitHub/Google OAuth) on their machine and polls up to 10 minutes. They need to be at the keyboard.
  2. For CI / headless agent runs, use npx deepspace login --email <e> --password <p> instead — the non-interactive path bypasses OAuth polling entirely. Only valid when test-account credentials already exist; do not invent credentials or ask the user to share their personal password.
  3. Run interactive login without an artificial time bound. Do not wrap in timeout N, sleep N && kill, or any cutoff — those terminate OAuth before completion and leave no session. (timeout isn't installed on macOS by default; don't reach for it.) Run in foreground or a true background process.
  4. Wait for ~/.deepspace/session to exist before retrying dev / test / deploy. Re-running while login is still polling produces the same error — that's expected order, not a bug.
  5. Never copy .dev.vars from a sibling app. APP_OWNER_JWT is minted against that app's wrangler name; borrowing causes silent auth mismatches. dev and test regenerate the file on every run — let the CLI own it.

Test (npx deepspace test)

Tests are the primary way to verify code changes. The scaffolded specs (smoke.spec.ts / api.spec.ts / collab.spec.ts) are starting points — extend them per the Step 8 checklist in references/testing.md. The full extension table, debug-from-failures rule, route coverage, multi-user patterns, and the 'deepspace/testing' fixture all live in that file.

One rule stays here because it bites first-time runs: run tests only after a runtime-affecting code change (src/, worker.ts, etc.). Skip them for conversation, planning, reading, or pure documentation edits — don't run as a ritual.

Deploy (npx deepspace deploy)

On an initial build, run the pre-deploy checklist in references/uiux.md §5 first. On follow-up deploys with those already verified, just run the command:

npx deepspace deploy   # → <wrangler.name>.app.space

The subdomain is the name field in wrangler.toml. Edit it there if you want a different deploy target — deploy does not accept a name override. Re-run npx deepspace login if the session has expired.

References

Each reference declares its own "Load when …" trigger at the top. Index:

Reference Load when
references/sdk-reference.md Looking up any hook, type, or export — the canonical index of every public surface (frontend, worker, testing).
references/schemas.md Defining a collection, picking a permission rule, debugging "why can't this user see/edit X," wiring visibilityField / collaboratorsField.
references/auth.md Choosing the auth model (public / gated / mixed), adding <AuthGate>, customizing the sign-in fallback.
references/architecture.md Editing worker.ts, adding cross-app shared scopes (workspace:* / dir:* / conv:*), wiring platformWorkerFetch.
references/server-actions.md Adding privileged writes that bypass the caller's RBAC.
references/ai-chat.md Adding a streamed chat UI with tool use over the app's records.
references/cron.md Adding scheduled tasks, building the admin cron monitor, testing cron via trigger.
references/integrations.md Calling external APIs (LLMs, search, media, social, finance, etc.).
references/integrations/livekit.md Adding audio/video rooms — token mint, billing model, room lifecycle.
references/integrations/google-oauth.md Calling Gmail / Calendar / Drive — per-user billing, scope step-up, requiresOAuth retry, test mocks.
references/uiux.md Working on theme, home page, primitives, interaction polish, or "feels generic" feedback. Trigger especially when about to use <select> / window.confirm / window.alert / window.prompt.
references/testing.md Writing or extending specs, applying the Step 8 checklist, building multi-user flows, route coverage, debugging flaky tests.
references/landing-design.md Building marketing / landing / splash pages, addressing "feels AI-generated" feedback, customizing the scaffolded landing feature.

Gotchas

The four cross-cutting traps that don't have a natural reference home. Domain-specific gotchas live in their topical reference (auth, schemas, integrations, architecture, testing).

  • useAuth().isSignedIn, not useUser()isSignedIn is session-based and updates immediately. useUser() loads async and causes a flash of "not signed in" state. (More auth gotchas in references/auth.md.)
  • Scaffold's local UI primitives shadow the SDK_app.tsx wraps the tree in ToastProvider from src/components/ui/, not from deepspace. Importing useToast (or any locally-shadowed primitive) from deepspace throws useToast must be used within ToastProvider at runtime — the React contexts don't match. Import from ../components/ui, not from deepspace. Full explanation in references/uiux.md § "Critical import rule."
  • Page files belong in src/pages/ — generouted scans only this directory. Putting pages in src/features/<name>/ results in 404s even if nav links exist.
  • Port 5173 may be held by a parallel sessiontests/playwright.config.ts ships with reuseExistingServer: true, so a sibling session's Vite on 5173 is picked up and your tests run against its app. Do not kill the other session's process. If you need your own dev server, use --port 5174 (or 5175, 5176, …) and edit tests/playwright.config.ts so webServer.port and use.baseURL both match before running tests.
Installs
8
First Seen
Apr 8, 2026