Skip to content

[RELEASE] feat(sync): deferred-sync mode for auto-provisioned (KiloClaw) users#906

Merged
vivekchand merged 1 commit intomainfrom
feat/deferred-sync-gate
May 7, 2026
Merged

[RELEASE] feat(sync): deferred-sync mode for auto-provisioned (KiloClaw) users#906
vivekchand merged 1 commit intomainfrom
feat/deferred-sync-gate

Conversation

@vivekchand
Copy link
Copy Markdown
Owner

Summary

Lets the cloud tell the OSS daemon "heartbeats yes, everything else no" without the trial-expired UX. KiloClaw auto-provisions ClawMetry on every new instance via `/api/register`, but we don't want session / event / log / memory data flowing to the cloud until the user explicitly clicks "View Observability" — privacy + compute story is much better when 99% of inert KiloClaw boxes never sync content.

The gate: cloud responds to `/ingest/heartbeat` with `{sync_allowed: false, reason: "intent_pending"}`. This commit teaches the daemon that this is a deferred state, not a trial-expired state, so the log message is friendly instead of an upgrade nag.

Changes

  • `clawmetry/sync.py` — `_update_trial_state` reads `resp.reason`. `intent_pending` → "Cloud sync deferred — waiting for the user to open their dashboard." `intent_started` (or any free-tier transition to allowed) → "Cloud sync activated — uploads resumed."
  • Gates `sync_sessions_recent` and `sync_claude_cli_sessions` on `_sync_allowed()`. They were the only two upload paths missing the existing gate, so deferred/paused state is now airtight.

Why this and not a separate config flag?

The `_TRIAL_STATE` machinery is already polled on every heartbeat response, already gates every upload, and already supports the exact transition ("sync_allowed flips → uploads resume, no daemon restart") we need for KiloClaw. Adding `reason` is a one-field tweak; a parallel mechanism would be duplicative.

Sequencing

Cloud-side change that emits `reason="intent_pending"` lives in `clawmetry-cloud/feat/deferred-sync-kiloclaw` and must merge + deploy before this is meaningful for KiloClaw users. This OSS PR is safe to ship independently — old cloud (no `reason` field) → daemon falls through the existing trial-expired branch (current behavior, no regression).

Test plan

vivekchand pushed a commit to vivekchand/cloud that referenced this pull request May 7, 2026
Previously the sync daemon was spawned on the user's first "View
Observability" click — which produced two real bugs the E2E test caught:
(a) a spawn-on-click race that left users staring at a "Run: clawmetry
connect" red banner during cold-start, and (b) the dashboard sometimes
rendered "Node not found" because the nodes table hadn't been populated
by a heartbeat yet.

New shape:

- Bootstrap registers with source='kiloclaw' (the cloud-side companion
  PR uses this to mark the user account as deferred-sync) and spawns
  the daemon at instance boot. The daemon heartbeats every 60s — that's
  enough for the dashboard to render correctly the moment the user
  clicks View Observability — but uploads ZERO content (sessions,
  events, logs, memory) because the cloud's /ingest/heartbeat returns
  sync_allowed=false, reason='intent_pending' until the user has
  signalled intent.

- POST /_kilo/clawmetry-start-sync no longer spawns anything (the
  daemon is already running). Instead it reads api_key from
  /root/.clawmetry/config.json and POSTs to the cloud's new
  /api/cloud/intent-start endpoint, which flips users.sync_intent_at.
  The daemon's next heartbeat (~60s) sees sync_allowed=true and
  uploads resume.

Why this matters:

- No spawn-on-click race — daemon is always there, only the data flow
  is gated. Eliminates the "Run: clawmetry connect" misleading banner
  for KiloClaw users.
- Privacy + cost: 99% of inert KiloClaw boxes never sync any content,
  only metadata-only heartbeats. Real engagement signal too — we
  literally know which users opened their dashboard.
- "We get to know this user really wants to use ClawMetry" — the
  intent flag IS that signal.

This PR depends on:
- vivekchand/clawmetry-cloud#635 (cloud-side gate + intent-start endpoint)
- vivekchand/clawmetry#906 (OSS daemon recognises reason='intent_pending')

Both must merge + deploy before this is meaningful for KiloClaw users.
This PR is safe to ship before them — the daemon will heartbeat, the
cloud will accept it (with no special response), and uploads will
proceed as before. Once cloud is deployed, deferred mode kicks in.
…sync mode

Before this change, the daemon treated every sync_allowed=false response as
an expired trial and logged a misleading "Upgrade to Pro" warning. With the
new KiloClaw integration, the cloud may also tell the daemon it's in
deferred-sync mode — heartbeats accepted, no other uploads — until the user
clicks "View Observability" in their KiloClaw dashboard. Surface that as a
distinct, friendly log line so the daemon's behavior is comprehensible to
both KiloClaw users (auto-provisioned, will engage later) and trial-expired
users (existing copy still applies).

Also gates two previously ungated startup-sync paths (sync_sessions_recent,
sync_claude_cli_sessions) on _sync_allowed(), so deferred / paused sync is
airtight: zero session / event / log / memory data leaves the machine until
the cloud explicitly says yes.

Cloud-side change that emits reason='intent_pending' is in
clawmetry-cloud/feat/deferred-sync-kiloclaw — required before this change
takes effect for new KiloClaw users.
@vivekchand vivekchand force-pushed the feat/deferred-sync-gate branch from 04c51be to 7c1de83 Compare May 7, 2026 19:42
@vivekchand vivekchand merged commit ce363e8 into main May 7, 2026
10 checks passed
@vivekchand vivekchand deleted the feat/deferred-sync-gate branch May 7, 2026 19:46
@vivekchand vivekchand changed the title feat(sync): deferred-sync mode for auto-provisioned (KiloClaw) users [RELEASE] feat(sync): deferred-sync mode for auto-provisioned (KiloClaw) users May 7, 2026
vivekchand added a commit that referenced this pull request May 7, 2026
…sync (#907)

The deferred-sync gate that #906 added (cloud responds with
reason='intent_pending' for KiloClaw users until they click View
Observability) reuses _sync_allowed() — extend the docstring so a
reader notices that this isn't only about trial-expired users.

Co-authored-by: vivekchand <vivek@clawmetry.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