Local Development
Local Development Runtime & Multi-Worker Architecture (LOCAL_DEVELOPMENT.md)
1. Executive Summary & Foundational Local DX Invariants
SiteSwarm is engineered so developers and parallel AI agents operating in isolated Git worktrees (wt) can build, run, and verify multiple client applications and platform services completely offline without cloud dependencies, API tokens, or port collisions:
- The Offline Development Invariant: Running local development servers and test suites must succeed 100% offline without live internet connectivity or Cloudflare API tokens.
- The Zero-Collision Worktree Invariant: Concurrent worktrees negotiate available ports dynamically with the host OS kernel (
scripts/dev-runner.ts), eliminatingEADDRINUSEconflicts across parallel sessions. - The Deterministic Local State Invariant: Local Cloudflare D1 SQLite databases (
.wrangler/state/v3/d1) can be reset and seeded deterministically from versioned schema and seed fixtures in seconds.
flowchart TD DevRunner["Fleet Dev Runner (scripts/dev-runner.ts)\n(Dynamic OS Kernel Port Negotiation)"] --> Apps["Client Apps (apps/*)\nAstro + Miniflare workerd Platform Proxy"] DevRunner --> Services["Platform Services (services/*)\nCritique, Inquiries, Cache Purge"] Apps --> LocalD1["Local D1 SQLite State (.wrangler/state/v3/d1)\n(Deterministic Schemas + Seed Fixtures)"] Services --> LocalD1 Apps <-->|"Loopback HTTP / Binding Emulation"| Services2. Tooling That Empowers Local Development
Local developer experience is powered by custom platform tooling designed specifically for multi-worker monorepo development:
2.1 Fleet Dev Runner (scripts/dev-runner.ts / pnpm run dev)
- Interactive Multi-App Runner: Provides an interactive terminal UI for selecting and booting any combination of client applications (
apps/*) and platform services (services/*). - Dynamic Port Allocation: Rather than hardcoding fixed port numbers (e.g.
3000,8787), the runner probes preferred base ports and falls back to dynamic, kernel-assigned ephemeral ports when busy. - Port Registry (
.swarm/ports.json): Active port mappings are written to a git-ignored file (.swarm/ports.json) and injected into child processes viaPORTandPUBLIC_SITE_URLenvironment variables.
2.2 Local State Initializer (scripts/setup-local.ts / pnpm run setup:local)
- Deterministic SQLite Setup: Automatically applies database migrations across all D1-enabled services (e.g.
services/critique/migrations/,apps/*-cms/migrations/) into.wrangler/state/v3/d1. - Seed Fixtures: Seeds deterministic local test data so applications start with valid, realistic content immediately upon first run.
- Credential Inheritance: Syncs local configuration files (
.dev.vars,.env) across new worktrees via.worktreeincluderules without checking secrets into Git.
2.3 Astro Platform Proxy (Miniflare / workerd)
- Client Astro applications utilize
@astrojs/cloudflare’s local platform proxy. This boots Cloudflare’s open-source C++ Miniflare / workerd runtime directly on the developer’s machine, providing real edge isolate behavior and local D1/R2 binding emulation.
3. Practices for Standing Up Multiple Services and Workers
When developing features that span client applications and backing platform services:
- Targeted Subsystem Booting:
- Developers can run single client apps via targeted filters:
pnpm --filter=@siteswarm/<app> run dev. - When a client app is run in isolation without running backing platform services, client code utilizes graceful local fallback adapters (mock implementations or offline dummy keys) so UI development is never blocked.
- Developers can run single client apps via targeted filters:
- Coordinated Multi-Worker Development:
- When end-to-end integration is required (e.g. testing pinned defect submission from a client app into the critique platform service), developers boot both subsystems via
pnpm run dev. - The runner starts all selected isolates concurrently, ensuring each obtains a distinct port.
- When end-to-end integration is required (e.g. testing pinned defect submission from a client app into the critique platform service), developers boot both subsystems via
- Hermetic Test Isolation:
- Tooling and unit tests never assume a fixed running dev server; integration tests spin up ephemeral local servers on dynamic ports or inject in-memory mocks.
4. Connection Paradigms: Process Management (IPC) vs. Networking
SiteSwarm distinguishes cleanly between process lifecycle coordination and service communication:
4.1 Process Management with IPC
- Supervisor Hierarchy:
scripts/dev-runner.tsacts as the root supervisor process managing child worker processes (astro dev,wrangler dev). - IPC Signaling: The supervisor uses Node.js Inter-Process Communication (IPC) and standard OS signals (
SIGINT,SIGTERM) to coordinate clean shutdowns, pipe log output into a unified terminal multiplexer, and propagate configuration reload events.
4.2 Inter-Worker Communication: Loopback Networking & Binding Emulation
- Local Dev Loopback HTTP: Because Cloudflare Workers Service Bindings represent an in-memory isolate boundary in production, local development bridges cross-worker calls via loopback HTTP over dynamically assigned localhost ports.
- Port Discovery via Registry: When
apps/bakerycallsservices/critique, the client reads the active critique service port from.swarm/ports.jsonor uses injected environment variables, ensuring zero port clash across parallel developer sessions. - Miniflare Service Binding Emulation: In advanced setups, Miniflare can directly bind sibling worker isolates within a shared local runtime process, mirroring Cloudflare’s production Service Binding semantics without TCP overhead.
5. Zero-Secret Hygiene & Environment Security
- Git-Ignored Local Secrets: Local development secrets reside strictly in
.dev.vars(for Workers) and.env(for Node tooling). These files are globally git-ignored. - Tracked Example Templates: Tracked
.dev.vars.exampleand.env.exampletemplates contain only safe dummy placeholders and documentation comments. - Zero API Keys in Tests: All workspace tests pass hermetically with zero secrets present (
RULES.md).
Decisions Intentionally Deferred
- Automated cloud-to-local state synchronization (pulling production D1 snapshots to local development) is intentionally deferred to protect customer privacy and avoid accidental data exposure.