Demo dataset is now opt-in — fresh installs ship empty#9
Merged
Conversation
Up through Phase 9 the dev seed ran on every server start in
non-production mode and the CLI didn't set NODE_ENV, so every
clawcontrol-start ended with the Nova SaaS Co fixtures loaded. That's
wrong for users — production deployments shouldn't auto-populate
fictional org / agents / tasks / goals.
Fix:
• bin/clawcontrol.js sets NODE_ENV=production when spawning the
bundled server (unless the caller has already set it). Cold
installs land on an empty dashboard. Contributors running via
`pnpm start` / tsx watch still get the auto-seed.
• packages/server/src/db/seed.ts gains clearDemo() and hasDemo().
SEED_IDS is the canonical list of stable IDs the seed inserts;
clearDemo deletes only those rows, so user-created data is
preserved. Counts the rows present *before* deletion to give an
honest report (some FKs cascade — direct DELETE.changes
under-counts).
• packages/server/src/routes/system.ts:
GET /api/system/info demo_loaded + per-table counts
POST /api/system/load-demo idempotent (already_loaded:true on
second call)
POST /api/system/clear-demo idempotent inverse
• bin/clawcontrol.js gains the demo subcommand:
clawcontrol demo load
clawcontrol demo --clear remove
clawcontrol demo --status loaded? + counts table
• Settings page gets a Demo dataset card with per-table count
chips, Load demo data button (disabled when already loaded), and
Clear demo with confirmation.
• api-client gets api.system.{info,loadDemo,clearDemo}.
Tests:
packages/server/tests/system.test.ts (6 cases) covers the full
lifecycle: empty DB info → load → counts match the brief
(1 org / 7 agents / 15 goals / 10 tasks / etc.) → second load is a
no-op → clear removes only seed IDs → user-created agent survives a
clear → clear on empty DB is a no-op.
Docs:
USER_GUIDE.md gains a "10. Demo dataset" section, the CLI reference
table picks up demo / --status / --clear, the table of contents is
renumbered. README's quickstart calls out that fresh installs are
empty and how to opt in.
Verified end-to-end on a cold ~/.clawcontrol/:
• clawcontrol start → empty dashboard, /api/agents = []
• clawcontrol demo --status → "not loaded", all counts 0
• clawcontrol demo → "demo dataset loaded"
• /api/agents → 7 agents
• clawcontrol demo (again) → "already loaded"
• clawcontrol demo --clear → "removed 70 demo rows" (correct
sum across 9 tables)
• /api/agents → []
Tests: 34 server (was 28) + 15 UI = 49 passing. Typecheck clean.
Addresses four asks: a setup guide on first install, a properly
configurable OpenClaw gateway, agents that stay in sync with OpenClaw,
and a gateway that can re-establish on demand.
Schema
Migration v3 adds agents.sync_status ('pending' | 'synced' | 'failed'),
last_synced_at, sync_error. Existing rows default to 'pending' so
every agent gets pushed to OpenClaw on the next reconnect.
OpenClaw client
• reconnectNow(newUrl?) resets the backoff counter and triggers an
immediate connect — exposed for the UI's "Reconnect now" button and
the gateway-URL change endpoint.
• setUrl(url) hot-swaps the gateway URL without a server restart.
• syncAgent(agent) and deleteAgent(id) push agent definitions over
the WS — the missing inverse of the existing inbound agent.* events.
• Closing a CONNECTING socket no longer leaks an unhandled 'error'
event (previously crashed the server when a PATCH triggered an
immediate reconnect — caught during the cold-boot smoke).
Agent ↔ OpenClaw sync (openclaw/agent-sync.ts)
Single chokepoint. The agents route calls pushAgent(id) after every
create / update / clone and pushAgentDeletion(id) on delete. The
helper marks the row 'synced' on success, 'pending' (with a reason in
sync_error) when OpenClaw is offline, 'failed' when the push raised.
startAutoSync() subscribes to openclaw-client state changes and runs
syncAllPending() the moment the gateway flips to 'connected'.
System endpoints (routes/system.ts)
GET /api/system/openclaw-config — current + live URL + state
PATCH /api/system/openclaw-config — write config.json + reconnect
POST /api/system/openclaw-reconnect — kick the client now
POST /api/system/sync-all — re-push pending/failed agents
GET /api/system/onboarding — { completed, completed_at }
POST /api/system/onboarding/complete — flip the flag in system_config
DELETE /api/system/onboarding — clear the flag (re-run wizard)
POST /api/agents/:id/sync — manual single-agent push
UI surfaces
• OfflineBanner gains a "Reconnect now" button alongside Run Doctor.
• Settings → "OpenClaw gateway" card: editable URL, live state chip,
Save & reconnect, Reconnect now, Re-sync agents. Drift indicator
when the live URL has diverged from config.
• New /welcome page (4 steps: hello → connect to OpenClaw with live
test → choose starting state [demo / first agent / skip] → done).
Layout checks /api/system/onboarding on mount and redirects to
/welcome the first time. Fail-open if the probe errors so a flaky
server never wedges the user out.
Bug fixes
• Both the openclaw-client and the Doctor's gateway probe used to
leak a "WebSocket was closed before the connection was established"
error after closing a CONNECTING socket — Node treated it as
unhandled because removeAllListeners() ran first. Now we install a
no-op error handler before close().
• backup-service path drift fix from the previous commit confirmed
against the new test setup.
Tests (44 passing, was 34)
packages/server/tests/sync-onboarding.test.ts (9 cases) covers the
new endpoints: openclaw-config GET / PATCH (with URL-scheme
validation), reconnect, sync-all on empty + after agent create
(verifies sync_status 'pending' when OpenClaw is offline), manual
/agents/:id/sync, onboarding flag lifecycle (start uncompleted,
POST flips, DELETE clears).
Test harness now installs a real openclaw-client per test (pointed at
a random unused port so reconnect attempts no-op safely) and
resets the singleton in cleanup.
Docs
USER_GUIDE.md: §2 split into "CLI wizard" + "In-app onboarding" with
the 4-step UI walkthrough and the curl recipe for re-running it.
§3 picks up "Settings → OpenClaw gateway" with the three new buttons
and the agent sync_status semantics.
Verified end-to-end on a fresh ~/.clawcontrol/:
• clawcontrol start → server up, dashboard redirects to /welcome.
• /api/system/onboarding → { completed: false }
• /api/system/openclaw-config → live state + URL
• PATCH gateway URL → saves + reconnects (no crash)
• POST openclaw-reconnect → state: connecting
• POST sync-all on empty DB → 0/0/0
• Create agent → sync_status: pending,
sync_error: "OpenClaw offline
— queued for reconnect"
• POST onboarding/complete → next refresh lands on /
Resolved conflicts by keeping PR's content (main was reverted via PR #7). Preserves full implementation: README, CLI, tests, docs, LICENSE, CI workflows.
pnpm/action-setup@v4 now rejects having both 'version: 9' and the package.json 'packageManager' field. Use packageManager only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Up through Phase 9 the dev seed ran on every server start in non-production mode and the CLI didn't set NODE_ENV, so every clawcontrol-start ended with the Nova SaaS Co fixtures loaded. That's wrong for users — production deployments shouldn't auto-populate fictional org / agents / tasks / goals.
Fix:
• bin/clawcontrol.js sets NODE_ENV=production when spawning the
bundled server (unless the caller has already set it). Cold
installs land on an empty dashboard. Contributors running via
pnpm start/ tsx watch still get the auto-seed.• packages/server/src/db/seed.ts gains clearDemo() and hasDemo().
SEED_IDS is the canonical list of stable IDs the seed inserts;
clearDemo deletes only those rows, so user-created data is
preserved. Counts the rows present before deletion to give an
honest report (some FKs cascade — direct DELETE.changes
under-counts).
• packages/server/src/routes/system.ts:
GET /api/system/info demo_loaded + per-table counts
POST /api/system/load-demo idempotent (already_loaded:true on
second call)
POST /api/system/clear-demo idempotent inverse
• bin/clawcontrol.js gains the demo subcommand:
clawcontrol demo load
clawcontrol demo --clear remove
clawcontrol demo --status loaded? + counts table
• Settings page gets a Demo dataset card with per-table count
chips, Load demo data button (disabled when already loaded), and
Clear demo with confirmation.
• api-client gets api.system.{info,loadDemo,clearDemo}.
Tests:
packages/server/tests/system.test.ts (6 cases) covers the full
lifecycle: empty DB info → load → counts match the brief
(1 org / 7 agents / 15 goals / 10 tasks / etc.) → second load is a
no-op → clear removes only seed IDs → user-created agent survives a
clear → clear on empty DB is a no-op.
Docs:
USER_GUIDE.md gains a "10. Demo dataset" section, the CLI reference
table picks up demo / --status / --clear, the table of contents is
renumbered. README's quickstart calls out that fresh installs are
empty and how to opt in.
Verified end-to-end on a cold ~/.clawcontrol/:
• clawcontrol start → empty dashboard, /api/agents = []
• clawcontrol demo --status → "not loaded", all counts 0
• clawcontrol demo → "demo dataset loaded"
• /api/agents → 7 agents
• clawcontrol demo (again) → "already loaded"
• clawcontrol demo --clear → "removed 70 demo rows" (correct
sum across 9 tables)
• /api/agents → []
Tests: 34 server (was 28) + 15 UI = 49 passing. Typecheck clean.