Developer Workflow
Scope: The day-to-day loop, expressed as operator/developer use cases: bring the stack up, build the workspace pieces, deploy data in order, run the suites, and produce evidence that what you changed actually works. SurrealQL hard-constraint detail lives with the data-plane documents — this guide links there rather than repeating it. Audience: operator + developer. Status: As of 2026-11-09. Sources (cited inline): the operating guide (environment, cloud-VM notes, BFF sections, mandates); the root workspace scripts; the runtime and engine package scripts; the full deploy script; the smoke and verification scripts.
1. Use case: bring the stack up
Actor: a developer with a fresh checkout. Goal: a healthy local platform — data store, both BFFs, and the console — ready for verification.
Precondition: the working directory is the repository root on the current branch; the deprecated separate worktree is not used (source: operating-guide working-directory rule).
| Platform | Data store | Runtime BFF (:3030) | Engine BFF (:3031) | Console (:10300) |
|---|---|---|---|---|
| Windows (PowerShell) | http://127.0.0.1:8000, root/root, namespace and database per the operating guide, persistent file store (source: operating guide environment) | cd apps/agent-bff && DEV_SKIP_AUTH=1 SURREAL_URL=http://127.0.0.1:8000 node src/index.js | cd apps/truth-bff && NODE_ENV=development DEV_SKIP_AUTH=1 TRUTH_GRAPH_SKIP_TRANSIT_TRAIL=1 TRUTH_GRAPH_SKIP_VAULT_GUARD=1 PORT=3031 SURREAL_URL=http://127.0.0.1:8000 SURREAL_NS=africa SURREAL_DB=community_os node dist/index.js | cd apps/sovereign-console && npm run dev |
| Linux VM (Cursor Cloud) | Binary preinstalled; start with the persistent-file invocation below | Same command; boots even with no schema/messaging; the health endpoint reports degraded when messaging is absent — the HTTP API is fully up | Same; dev calls use the dev_<user> bearer + a dev vault scope; graph mutations need the transit-trail skip flag | Same; binds the local name only, so use the local-name address, not a numeric loopback |
# Linux VM — data store (persistent file store)
surreal start --user root --pass root --bind 127.0.0.1:8000 rocksdb:/workspace/scratch/surreal-data
- Messaging, cache, and identity providers are optional locally. Both BFFs tolerate their absence and degrade with warnings; authentication is bypassed with the dev skip flag (source: operating-guide cloud notes). Live data rides the messaging key-value store.
- One-command start:
node start-dev.jsfrom the repository root spawns the engine, the runtime tier (slightly delayed, wired to the engine's address with a dev vault scope and enqueue execution mode), and the mobile web app. If the engine's built output is missing it tells you to build first (see Section 2). The cloud-VM notes document the same bring-up as start commands (source: cloud notes). - Dev-start script family: Windows and Linux each have their own script variants — per-tier starters for the agent, engine, data store, integrations, and mesh proxies, plus an all-in-one desktop variant and deploy/seed/test wrappers. There is no single "start-all" entrypoint; pick the starter for the tier you are touching (source: script inventory).
- The edge API (:3040) is not started locally. It is a stateless edge tier (authentication, tenants, vault health) that needs a public data endpoint when deployed; a local loopback store is not reachable from the edge (source: tier split).
Ports at a glance: data store :8000, runtime BFF :3030, engine :3031, edge :3040, console :10300, messaging :4222, mobile web :8081, compliance mTLS gateway :8181 (source: operating guide; start script).
2. Use case: build the workspace pieces
Actor: the same developer, before starting the TypeScript tiers. Goal: every local library the engine and console import exists as built output.
Why this step exists: the engine and the console depend on local TypeScript libraries that must be compiled to their distribution folders before either tier runs (source: cloud notes).
# Build every workspace package
npm run build --workspaces
# Type-check the engine tier without emitting (CI-equivalent lint)
cd apps/truth-bff && npx tsc --noEmit
# Build the engine tier itself
cd apps/truth-bff && npm run build
# Start / watch the engine tier
cd apps/truth-bff && npm run start
cd apps/truth-bff && npm run dev
What to expect:
- One shared UI library carries pre-existing type errors but still emits usable output — its build is guarded so the failure does not block the workspace build (source: cloud notes).
- The engine resolves one identity client through the hoisted root node modules rather than its own direct dependency; it works as long as the root install ran (source: cloud notes).
- Three previously broken setup issues are fixed — do not re-introduce workarounds: a corrected library path in the engine's package description, a corrected require path for a health kit in the engine entry point, and the console blank-page fix (a stray token removed from a workflow-designer page). The console fix means the landing and login screens now mount (source: cloud notes).
- Repo-root workspace scripts also provide
dev(all workspaces),test(all workspaces that define one),lint(all workspaces that define one), and Playwright end-to-end tests (source: root package scripts).
3. Use case: deploy schema, then seed configuration, then boot
Actor: an operator preparing a real environment or a full local demo. Goal: data shapes first, configuration second, services last — in that order, every time.
Step 1 — schema first. The full deploy the Windows world uses:
# PowerShell (Windows)
database\deploy.ps1
On the Linux VM the full deploy is PowerShell-only, so replicate the truth-graph deploy by hand: for each of the 23 truth-graph strata in order, import the file, then re-apply the same SQL over HTTP — imports can silently drop function bodies, so the HTTP re-apply is not optional (source: cloud notes; truth-graph deploy script).
Step 2 — seed the key-value configuration. Runtime services never read configuration files from disk; only the offline seeder does. It publishes the datasets into the messaging key-value store:
node scripts/seed-nats-kv-declarative.mjs
Targeted seeders publish the same way for single buckets (source: declarative-first mandate — runtime must never read lookup/template files from the filesystem).
Step 3 — validate the dataset contracts where a validator exists:
node scripts/validate-dispatch-openapi.mjs
Step 4 — boot the BFFs per Section 1 (or the one-command start). Graph functions are then available under the truth tier with explicit traversal directions (outgoing, incoming, or both) (source: operating-guide key functions).
Step 5 — smoke last (Section 5).
4. Use case: run the tests (what each suite proves)
Actor: a developer proving a change. Goal: pick the cheapest suite that proves the thing you touched.
| Suite | Command | What it proves |
|---|---|---|
| Runtime tier — full | node --test "tests/*.test.js" (from the agent tier directory) | The whole HTTP and route surface, including the API-description parity contracts. |
| Runtime tier — quick | node --test tests/pipeline-engine.test.js | The workflow/pipeline engine (168 of 171 in a prior run; the remainder need extra schema functions). |
| Runtime tier — vertical cluster | node --test src/tests/materra-app.test.js src/tests/materra-composable-template-routes.test.js (13 files total in the cluster) | The agriculture vertical end to end. |
| Runtime tier — capability clusters | node --test tests/lease-gap-c09-consume.test.js tests/service-access-gap-c09.test.js tests/service-subscription-billing.test.js (gap cluster); node --test tests/bi-routes.test.js tests/bi-analytics-routes.test.js (analytics); node --test tests/kutuma-mesh-routes.test.js tests/kutuma-webhook.test.js (notifications); the two jobs-platform suites (jobs) | That each capability vertical still behaves after refactors. |
| Claims description cover | node --test tests/claims-processing-openapi.test.js | All 23 required paths exist in the published description — the contract cannot drift. |
| Entities description cover | node --test tests/entity-lifelong-openapi.test.js | 38 paths plus the source-mirror check (every live route is documented). |
| Engine unit tests | npm test (from the engine directory; runs the vitest suite) | ~169 unit tests pass; ~78 integration tests need the full schema deployed and a free engine port — stop the dev server first or the run fails to bind. |
| Type check | npx tsc --noEmit (from the engine directory) | CI-equivalent lint; no eslint is installed anywhere, so the type check plus workspace lint is the gate. |
| Workspace lint | npm run lint --workspaces --if-present | No-op for most packages; the type check is the real gate. |
Each row's command is verbatim from its package's script definitions or the operating-guide test notes (source: agent-tier scripts; engine scripts; cloud notes). When a suite's expected count is quoted from an older inventory, re-run it — counts age; the command does not.
5. Use case: produce live evidence (smokes and verifiers)
Actor: an operator who needs to show, not tell. Goal: a running service, a scripted pass, and a clean console — on a port that does not disturb the live stack.
- Commerce proof:
scripts\run-commerce-dev-smokes.ps1 -BffUrl http://127.0.0.1:3030 -RequireBff(source: operating-guide commerce deploy notes). - Agent proof:
scripts\run-agent-dev-smokes.ps1 -BffUrl http://127.0.0.1:3030(source: operating guide). - Health proof:
scripts\run-afiyalink-health-dev-smokes.ps1(source: operating guide). - Contract proof:
node scripts/run-uoe-api-contracts.mjs --require-bff(source: root workspace scripts). - Dispatch proof:
scripts\run-dispatch-openapi-smoke.ps1wrapping the offline validator (source: dispatch smoke test). - Live verifiers (where they exist): e.g. the headless jobs-platform verification script proves 9 of 9 gates, the solver gateway 5 of 5, and the declarative workflow/prompt templates 3 of 3 and 4 of 4 respectively (source: operating-guide vertical verification suites).
Evidence habits that keep proof honest:
- Temp ports for smokes, so a smoke run never fights the live :3030; the dev-start flow itself recycles stale listeners (source: operating-guide dev-start notes).
- Readiness, not presence. A process listening is not a platform: check the readiness probe reports the database connected; when messaging is absent the health endpoint reports degraded but the HTTP API is up — that is the normal shape (source: cloud notes; ready probe).
- Fix the run, not the test. A smoke script that asserts invented numbers is a fake test — flag it and rewrite it against a real engine; never code to satisfy a smoke-screen test (source: ban-on-fake-tests mandate).
6. Conventions the loop depends on
- Fail closed. Infrastructure failures return an error or refusal — never a synthetic success (source: fail-closed mandate).
- Zero synthetic payloads. No invented coordinates, suppliers, organization ids, or generated lists to satisfy a downstream contract; contract mismatches return a client error (source: synthetic-payloads mandate).
- Declarative first. Lookups, templates, scenarios, and thresholds live in the messaging key-value store or in workflow-engine / protocol-gateway YAML; runtime file reads of datasets are forbidden outside the seeder (source: declarative-first mandates).
- No bespoke stores. Entities map into the canonical primitives; anything unmappable stops for review (source: zero-bespoke-tables mandate).
- No hardcoded card values. Dashboards render live data or an honest empty state (source: no-hardcoded-metrics mandate).
- TypeScript for new code; plain JavaScript only where declaration is genuinely impractical (source: operating-guide key decisions).
- Events over polling. Background work flows through durable outbox records; sweep endpoints are dev recovery only (source: operating-guide key decisions).
- No vendor names in public descriptions (see the spec index) (source: product map; cover tests).
7. Minimal bring-up checklist (respects the deploy order)
- Build the workspace pieces (Section 2) — before the engine or console.
- Start the data store for your platform (Section 1); confirm readiness.
- Deploy schema (Section 3, Step 1).
- Seed the key-value store (Section 3, Step 2).
- Boot the BFFs (Section 1) or the one-command start.
- Cheapest proof first: the description-cover tests (Section 4), then the temp-port smokes (Section 5), then the engine type check and unit tests.
- Confirm the health and readiness endpoints; accept "degraded" health when messaging is intentionally absent.
8. Common failure digests (pointers, not detail)
Full tables live with the data-plane and transport documents; the symptoms below are what to grep for in review.
- Over-fetch then filter in JavaScript — push the predicate into the query instead (the messaging relay fixed exactly this class of bug by moving its subject filter into the query) (source: relay fix).
- Bare literals for string arguments — identifier-like strings must be emitted quoted, never as bare record literals (source: route-side safe-emission helpers).
- Temporal-function arithmetic — subtract durations, not integers; always cast timestamps to text explicitly (source: hard-constraint table).
- Import silently dropped functions — re-apply the same SQL over HTTP after import (source: cloud notes).
- Engine port clash — stop the dev server before running the integration tests; the run fails to bind otherwise (source: cloud notes).
- Runtime file reads — no service may read dataset/template files from disk; only the offline seeder may (source: declarative-first mandate).
9. Working-directory and tooling rules
- Repository root, current branch. All changes land in the root; the deprecated separate worktree receives nothing (source: working-directory rule).
- Dedicated tools over shell; parallelize independent calls; file edits go through the edit tool (source: harness communication rules).