Skip to content

fix: reset ClawKeep when the ClawBox AI account changes - #177

Merged
KrasimirKralev merged 2 commits into
betafrom
fix/clawkeep-account-reset
Jun 9, 2026
Merged

KrasimirKralev merged 2 commits into
betafrom
fix/clawkeep-account-reset

Conversation

@KrasimirKralev

@KrasimirKralev KrasimirKralev commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Problem

ClawKeep pairs independently of the ClawBox AI account — it has its own claw_ token that the portal resolves to an account and a cloud-storage prefix. So after switching ClawBox AI accounts:

  • ClawKeep kept backing up to the old account's storage (verified on-device), and
  • the dashboard kept showing the old account's stats (size / snapshot count / last backup).

Fix

  • ai-models/configure — detect an account switch (the clawai_token changing from a previously-stored one) and unpair ClawKeep so it re-pairs against the current account. The token is opaque (no embedded account id), so a changed token is the only available signal. Also clears the old account's stats (clearStats) as an offline-safe wipe.
  • clawkeep — add unpairLocal() (shared by the unpair route + the account-change reset so they stay in lockstep) and syncStateFromCloud(), which seeds state.json from the account's real cloud snapshots on pair — so a re-authenticated account shows its existing backups immediately instead of 0 B / never until the next local backup.
  • clawkeep/pair/poll — sync cloud state right after writing the new token.
  • setup/reset — a factory reset now also wipes ~/.clawkeep, so it can't leave the device paired to the previous account either.
  • ClawKeepApp — poll status on a single variable-cadence timer (3s during a backup, 10s otherwise) so an already-open window reflects the server-side unpair without a manual click.

Three-mechanism design (intentional)

  1. clearStats wipe on switch — the offline safety net: if syncStateFromCloud can't reach the portal on re-pair, the device still shows a clean slate, never the old account's numbers.
  2. syncStateFromCloud on pair — the steady-state correct value (the new account's real cloud backups).
  3. ClawKeepApp poll — transport: makes an already-open window observe the change.

Testing

  • New unit tests in configure.test.ts: unpairs on token change (with { clearStats: true }), does not unpair on unchanged token or first-time setup.
  • Verified end-to-end on a Jetson device: switching accounts unpaired ClawKeep (confirmed via journalctl + the token file being cleared), backups then went to the new account's storage, and clawkeep snapshotssyncStateFromCloud correctly populated the dashboard with the account's existing backups.
  • clawkeep-persistence, clawkeep-schedule, and configure test suites pass.

Summary by CodeRabbit

  • New Features

    • Enhanced account-switch safety for ClawKeep: unpairing from previous account when changing providers to prevent backup associations with old accounts.
    • Cloud backup state now syncs immediately after re-authentication, allowing the dashboard to display existing backups right away.
  • Improvements

    • Dashboard polling optimized: slower refresh rate (10s) when idle, faster (3s) during active backups.
    • Factory reset now completely removes ClawKeep data alongside other app data.

ClawKeep pairs independently of the ClawBox AI account — its own claw_ token
resolves on the portal to an account and a cloud-storage prefix. So after
switching ClawBox AI accounts the device kept backing up to the OLD account's
storage, and the dashboard kept showing the old account's stats.

- ai-models/configure: detect an account switch (the clawai token changing
  from a previously-stored one) and unpair ClawKeep so it re-pairs against the
  current account. The token is opaque (no account id), so a changed token is
  the only available signal. Also clears the old account's stats as an
  offline-safe wipe.
- clawkeep: add unpairLocal() — shared by the unpair route and the
  account-change reset so the two stay in lockstep — and syncStateFromCloud(),
  which seeds state.json from the account's real cloud snapshots on pair, so a
  re-authenticated account shows its existing backups immediately instead of
  "0 B / never" until the next local backup.
- clawkeep/pair/poll: sync cloud state right after writing the new token.
- setup/reset: a factory reset now also wipes ~/.clawkeep, so it can't leave
  the device paired to the previous account either.
- ClawKeepApp: poll status on a single variable-cadence timer so an already-open
  window reflects the server-side unpair without a manual click.
@KrasimirKralev
KrasimirKralev requested a review from a team as a code owner June 8, 2026 21:37
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@KrasimirKralev, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 39 minutes and 50 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a56dd623-6c80-44ab-8239-f5ef3e467a19

📥 Commits

Reviewing files that changed from the base of the PR and between d043d17 and ff32853.

📒 Files selected for processing (3)
  • src/app/setup-api/ai-models/configure/route.ts
  • src/components/ClawKeepApp.tsx
  • src/lib/clawkeep.ts
📝 Walkthrough

Walkthrough

This PR adds ClawKeep account-switch safety and cloud state synchronization. When a ClawBox AI token changes during reconfiguration, the app detects the change and unpairs ClawKeep with full stat reset to prevent backups from remaining associated with the old account. The changes also consolidate unpair/reset logic into library APIs, sync cloud snapshots after re-pairing, integrate ClawKeep cleanup into factory reset, and adapt dashboard polling to backup status.

Changes

ClawKeep Account Switch Safety and State Sync

Layer / File(s) Summary
ClawKeep library – unpair and sync APIs
src/lib/clawkeep.ts
Introduces unpairLocal() to atomically delete the pairing token and conditionally reset state, syncStateFromCloud() to seed state.json from cloud snapshot metadata, and refactors state persistence via an internal writeStateFile() helper for atomic temp-file-plus-rename writes.
ClawBox AI token-change account switch safety
src/app/setup-api/ai-models/configure/route.ts, src/tests/routes/ai-models/configure.test.ts
Configure route reads the previously stored ClawBox AI token before reconfiguration, detects token changes after configuration, and calls unpairLocal({ clearStats: true }) to clean up backups associated with the old account. Test setup and three new test cases validate token-change, token-unchanged, and first-setup scenarios.
ClawKeep pairing and unpairing route consolidation
src/app/setup-api/clawkeep/pair/poll/route.ts, src/app/setup-api/clawkeep/unpair/route.ts
Pair/poll route syncs cloud snapshots into state immediately after token save via syncStateFromCloud(). Unpair route simplifies from separate deleteToken() + resetRunningState() calls to a single unpairLocal() invocation.
Factory reset and polling behavior updates
src/app/setup-api/setup/reset/route.ts, src/components/ClawKeepApp.tsx
Factory reset now deletes the ClawKeep data directory, treating deletion failure as reset failure. Dashboard polling dynamically adapts refresh interval from 3s during active backup to 10s otherwise.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ID-Robots/clawbox#139: Both PRs modify the clawai provider configuration handler in src/app/setup-api/ai-models/configure/route.ts—this PR adds ClawKeep unpair safety on token switch, while that PR adds a background catalog refresh.

Suggested reviewers

  • yalexx

Poem

🐰 A rabbit hops through cloudy states,
Unpairing backups at the gates,
When tokens switch, the old must fade—
Fresh syncs bloom where new ones played.
Polling faster when work's afoot,
Then rests again, refreshed and good! 🌱

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The linked issue (#39) concerns Local AI state stabilization and provider setup, while the PR focuses on ClawKeep account-switching behavior. The PR does not address the core objectives of #39. Verify that this PR is linked to the correct issue, or confirm whether ClawKeep account-switch handling is a sub-objective of #39 that was not clearly documented.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: resetting ClawKeep when the ClawBox AI account changes, which is the primary fix in this PR.
Description check ✅ Passed The PR description comprehensively covers the problem, fix, design rationale, and testing. It follows the template structure with clear sections and explains the three-mechanism design.
Out of Scope Changes check ✅ Passed All changes are tightly scoped to ClawKeep account-switching: detecting token changes, unpairing, syncing cloud state, and polling UI updates. The factory reset change is a natural extension of account cleanup.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/clawkeep-account-reset

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

CI Summary

✅ Tests

  • Result: passed
  • View run
  • Coverage: statements 69.08%, branches 58.86%, functions 63.81%, lines 71.12%

✅ E2E

✅ E2E Install

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/setup-api/ai-models/configure/route.ts`:
- Around line 432-439: The code is currently swallowing errors from getAll(),
causing previousClawaiToken to default to empty and skipping the account-switch
unpair guard; change this so a failing getAll() does not "fail open": remove the
blanket .catch(() => ({})) or replace it with explicit error handling that
aborts the request (or returns an error response) when getAll() rejects, and
ensure previousClawaiToken is read only after a successful getAll() call; adjust
the logic in the isClawAI/account-switch detection (references: getAll,
previousClawaiToken, CLAWBOX_AI_TOKEN_CONFIG_KEY, and the isClawAI block) so an
error from getAll() prevents proceeding rather than defaulting to an empty
token.

In `@src/components/ClawKeepApp.tsx`:
- Around line 217-223: The polling useEffect in ClawKeepApp (the effect using
status, refresh, intervalMs and id) can start new refresh() calls before prior
ones finish; replace the setInterval approach with a single-flight loop: use an
async polling function that checks an in-flight boolean (e.g., isFetching) to
avoid concurrent calls, use setTimeout for adaptive scheduling (3s vs 10s via
isBackupRunning(status)) rather than setInterval, and add a per-request
timeout/abort (wrap refresh() with an AbortController or a timeout promise) plus
try/catch to ensure errors clear isFetching and schedule the next run; update
cleanup to cancel pending timeout/abort when unmounted or status/refresh change.

In `@src/lib/clawkeep.ts`:
- Around line 378-383: writeStateFile currently writes to a fixed temp file
`${STATE_PATH}.tmp`, causing rename races between concurrent callers; change
writeStateFile to write to a per-call unique temp file (e.g. include process id
+ timestamp or a random suffix) before renaming to STATE_PATH, keep the same
file mode (0o600), perform the atomic fs.rename from that unique temp to
STATE_PATH, and ensure any temporary file is cleaned up on error; refer to
writeStateFile and STATE_PATH to locate and update the logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7107c631-76ea-4a6b-9aaf-6919e9a3cd8c

📥 Commits

Reviewing files that changed from the base of the PR and between bfbc2fe and d043d17.

📒 Files selected for processing (7)
  • src/app/setup-api/ai-models/configure/route.ts
  • src/app/setup-api/clawkeep/pair/poll/route.ts
  • src/app/setup-api/clawkeep/unpair/route.ts
  • src/app/setup-api/setup/reset/route.ts
  • src/components/ClawKeepApp.tsx
  • src/lib/clawkeep.ts
  • src/tests/routes/ai-models/configure.test.ts

Comment thread src/app/setup-api/ai-models/configure/route.ts Outdated
Comment thread src/components/ClawKeepApp.tsx
Comment thread src/lib/clawkeep.ts
- configure: don't fail open when reading the prior clawai_token — abort the ClawBox AI save with 503 if getAll() throws, instead of defaulting to "" and silently skipping the account-switch unpair guard.
- ClawKeepApp: skip a poll tick while the previous refresh is still in flight so a slow fetch can't stack concurrent requests on the Jetson.
- clawkeep: give writeStateFile a per-call temp name (pid + counter) so concurrent writers can't clobber each other's temp before the atomic rename.
@KrasimirKralev
KrasimirKralev merged commit 9e835ae into beta Jun 9, 2026
8 of 9 checks passed
@KrasimirKralev KrasimirKralev mentioned this pull request Jun 9, 2026
@KrasimirKralev
KrasimirKralev deleted the fix/clawkeep-account-reset branch July 4, 2026 17:42
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