Skip to content

fix(sync-banner): name the runtimes we actually sync, not a hardcoded OpenClaw - #5010

Merged
vivekchand merged 1 commit into
mainfrom
fix/sync-banner-names-real-runtimes
Aug 19, 2026
Merged

fix(sync-banner): name the runtimes we actually sync, not a hardcoded OpenClaw#5010
vivekchand merged 1 commit into
mainfrom
fix/sync-banner-names-real-runtimes

Conversation

@vivekchand

Copy link
Copy Markdown
Owner

The bug

The first-install sync banner shipped a hardcoded string in banners.html:

Syncing your OpenClaw workspace

Nothing ever rewrote it. So the banner asserted OpenClaw on every machine, including the majority that only run Claude Code / Codex / Cursor and have never installed OpenClaw. During onboarding, an unfamiliar product name scrolling past reads as "this thing is confused about my setup," which is the opposite of what a first-install banner is for.

The fix

The banner now names what it is actually syncing:

detected title
nothing / unknown Syncing your AI agents
1 Syncing your Claude Code data
2 Syncing Claude Code and Cursor
3+ Syncing Claude Code, Cursor and 2 more

/api/sync-progress grows a runtimes: [{id, label}] list and _cmSyncScopeTitle builds the title from it. The list is added by the dashboard, not the daemon, so this needs no daemon release to take effect. The template's static default is now runtime-neutral, because it renders before any detection has landed.

Two things the implementation has to get right

Honesty. A runtime is only named when it has sessions on disk, the same rule _detect_runtimes_for_heartbeat already applies. Presence alone is a phantom: the Cursor IDE creates its state dir whether or not the agent was ever run, and naming that would just be a different lie in place of the old one.

Cost. Detection globs session dirs and measured ~3.3s on a busy machine, while the banner polls every 15s. So it never runs inline: the handler serves a 60s cache and a daemon thread refreshes it. The first request returns [] (neutral title) and the next poll has the names. That was a deliberate trade, a generic-but-true title beats stalling the banner for three seconds.

Detection merges three sources because no single one is complete:

  • the OSS adapter registry (OpenClaw/NemoClaw), with a direct-instantiation fallback since registration happens at app creation and can be empty
  • _detect_runtimes_lite (free, always present)
  • _detect_family_runtimes (more accurate, but it imports from clawmetry_pro, so it returns nothing in OSS)

Verification

  • 8 guard tests in tests/test_sync_banner_names_real_runtimes.py, covering the template copy, the JS fallback, the render wiring, both endpoint branches (200 and cold-install 404), the non-blocking contract, the 0-session phantom rule, and the thread-failure path.
  • All 8 fail against the pre-fix tree and pass with the fix. Checked by reverting the three source files to origin/main and re-running.
  • Endpoint on this machine returns [openclaw, claude_code, codex, qwen_code].
  • Browser screenshot of the rendered banner reading Syncing OpenClaw, Claude Code and 2 more.
  • tests/test_sync_progress_sticky.py, test_adapters.py, test_adapter_registry_override.py still green (25 passed).

Note for reviewers

detect_config() has a latent bug this surfaced but does not fix: its args=None path builds a bare argparse.Namespace and then AttributeErrors on args.log_dir. The CLI always passes a full Namespace so it never fires in production. The test fixture works around it rather than widening this PR's scope.

🤖 Generated with Claude Code

… OpenClaw

The first-install sync banner shipped the literal string "Syncing your
OpenClaw workspace" in banners.html. Nothing ever rewrote it, so the banner
asserted OpenClaw on every machine, including the majority that only run
Claude Code / Codex / Cursor and have never installed OpenClaw. A user
watching an unfamiliar product name scroll past during onboarding reasonably
reads it as "this thing is confused about my setup."

The banner now names what it is really syncing:

  0 / unknown   Syncing your AI agents
  1             Syncing your Claude Code data
  2             Syncing Claude Code and Cursor
  3+            Syncing Claude Code, Cursor and 2 more

/api/sync-progress grows a `runtimes: [{id, label}]` list (added by the
dashboard, not the daemon, so no daemon release is needed) and
_cmSyncScopeTitle builds the title from it. The static default in the
template is now runtime-neutral, since it renders before detection lands.

Two things the implementation has to get right:

- Honesty. A runtime is only named when it has sessions ON DISK, the same
  rule _detect_runtimes_for_heartbeat already applies. Presence alone is a
  phantom: the Cursor IDE creates its state dir whether or not the agent was
  ever run, and naming that would just be a different lie.
- Cost. Detection globs session dirs and measured ~3.3s on a busy machine,
  and the banner polls every 15s. So it never runs inline: the handler
  serves a 60s cache and a daemon thread refreshes it. The very first
  request returns [] (neutral title) and the next poll has the names.

Detection merges three sources because no single one is complete: the OSS
adapter registry (OpenClaw/NemoClaw, with a direct-instantiation fallback
since registration happens at app creation), _detect_runtimes_lite (free,
always present), and _detect_family_runtimes (more accurate, but it imports
from clawmetry_pro so it returns nothing in OSS).

Verified: 8 guard tests, all 8 red against the pre-fix tree; endpoint
returns the real list on this machine; browser screenshot of the rendered
banner reading "Syncing OpenClaw, Claude Code and 2 more".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@8090-software-factory

Copy link
Copy Markdown

✅ Drift Bot (ClawMetry): no drift detected

Drift Bot analyzed the changed files against this project's blueprints and requirements and found no drift.

@github-actions

Copy link
Copy Markdown
Contributor

Visual diff

Comparing ec3403ba92c9 (head) against the PR base branch.

32 of 66 comparison(s) flagged (>1% pixel diff).

View Before After Diff
desktop overview ⚠️ before after diff · 100.00%
desktop flow before after diff · 0.10%
desktop brain before after diff · 0.00%
desktop usage before after diff · 0.00%
desktop crons ⚠️ before after diff · 2.96%
desktop memory before after diff · 0.02%
desktop security before after diff · 0.00%
desktop subagents before after diff · 0.00%
desktop transcripts before after diff · 0.07%
desktop logs before after diff · 0.02%
desktop skills before after diff · 0.01%
desktop models ⚠️ before after diff · 2.90%
desktop approvals ⚠️ before after diff · 3.71%
desktop alerts before after diff · 0.00%
desktop notifications ⚠️ before after diff · 3.00%
desktop limits before after diff · 0.02%
desktop clusters before after diff · 0.01%
desktop history before after diff · 0.00%
desktop channels ⚠️ before after diff · 1.54%
desktop dives ⚠️ before after diff · 2.11%
desktop harness ⚠️ before after diff · 4.04%
desktop inventory before after diff · 0.01%
desktop nemoclaw before after diff · 0.01%
desktop policy before after diff · 0.01%
desktop selfevolve before after diff · 0.33%
desktop swimlane before after diff · 0.01%
desktop tool-catalog before after diff · 0.26%
desktop tracing before after diff · 0.58%
desktop turn-anatomy before after diff · 0.26%
desktop version-impact ⚠️ before after diff · 1.63%
desktop context-economics before after diff · 0.26%
desktop agents ⚠️ before after diff · 2.54%
desktop evals before after diff · 0.00%
mobile overview before after diff · 0.31%
mobile flow ⚠️ before after diff · 100.00%
mobile brain ⚠️ before after diff · 100.00%
mobile usage ⚠️ before after diff · 100.00%
mobile crons ⚠️ before after diff · 100.00%
mobile memory ⚠️ before after diff · 100.00%
mobile security ⚠️ before after diff · 100.00%
mobile subagents before after diff · 0.51%
mobile transcripts ⚠️ before after diff · 1.84%
mobile logs ⚠️ before after diff · 100.00%
mobile skills ⚠️ before after diff · 100.00%
mobile models ⚠️ before after diff · 3.62%
mobile approvals before after diff · 0.01%
mobile alerts before after diff · 0.00%
mobile notifications ⚠️ before after diff · 100.00%
mobile limits ⚠️ before after diff · 2.04%
mobile clusters before after diff · 0.02%
mobile history before after diff · 0.35%
mobile channels ⚠️ before after diff · 100.00%
mobile dives ⚠️ before after diff · 1.98%
mobile harness before after diff · 0.60%
mobile inventory ⚠️ before after diff · 1.98%
mobile nemoclaw ⚠️ before after diff · 100.00%
mobile policy ⚠️ before after diff · 1.90%
mobile selfevolve before after diff · 0.01%
mobile swimlane ⚠️ before after diff · 100.00%
mobile tool-catalog ⚠️ before after diff · 1.90%
mobile tracing before after diff · 0.04%
mobile turn-anatomy before after diff · 0.01%
mobile version-impact ⚠️ before after diff · 100.00%
mobile context-economics ⚠️ before after diff · 100.00%
mobile agents before after diff · 0.07%
mobile evals ⚠️ before after diff · 100.00%

Folder: ec3403ba92c9. Full PNGs also attached as a workflow artefact.

Generated by visual-diff bot. Pixel diffs >1% flagged; eyeball the table before merging. This check is non-blocking — fail = bot bug, not a code problem.

@vivekchand
vivekchand merged commit 8dc40f9 into main Aug 19, 2026
32 checks passed
@vivekchand
vivekchand deleted the fix/sync-banner-names-real-runtimes branch August 19, 2026 22:31
vivekchand added a commit that referenced this pull request Aug 20, 2026
…5010)

Ships the fix for the hardcoded "Syncing your OpenClaw workspace" banner
title to PyPI and the fleet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
vivekchand added a commit that referenced this pull request Aug 21, 2026
…5010) (#5012)

Sync banner now accurately names all 12 runtimes it syncs instead of generic text. Includes #5010 fixes.

Co-Authored-By: vivekchand <vivekchand19@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant