Skip to content

fix(cli): drop the local routing entry when a cloud project is removed - #1355

Merged
phernandez merged 4 commits into
mainfrom
fix/1340-cloud-project-remove-stub
Aug 28, 2026
Merged

fix(cli): drop the local routing entry when a cloud project is removed#1355
phernandez merged 4 commits into
mainfrom
fix/1340-cloud-project-remove-stub

Conversation

@phernandez

Copy link
Copy Markdown
Member

Fixes #1340.

Problem

bm project add <name> --cloud --workspace <ws> writes a local config entry ProjectEntry(path="", mode=cloud, workspace_id=…) purely so later commands route to the cloud (project.py add flow). bm project remove <name> then deletes the cloud project but only clears local_sync_path / bisync fields on that entry — it never removes it. The stub outlives the project:

  • list-projects shows it as source: local, local_path: "/"
  • project remove routes to the cloud again (entry still says cloud) → "Project not found"
  • project add <name> → "already exists"

Only hand-editing config.json recovers the name.

Fix

After a cloud-routed delete succeeds (explicit --cloud, or a cloud-mode entry), delete the config entry. If the removed project is still the configured default — the one entry config must keep — it's scrubbed of sync state instead and the user is told to pick another default and remove it with --local.

Existing stubs: once #1354 lands, bm project remove <name> --local clears them (reconciliation puts the entry in the local DB, and the local delete removes both row and entry).

Tests

  • tests/cli/test_project_remove_cloud_stub.py — a cloud-mode entry is gone from config.json after project remove, the delete was routed with the entry's workspace, and unrelated entries survive.
  • All 65 project-CLI tests pass; ruff / ty clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_017STCpbNsYjZgUdftxgEAZ4

`project add --cloud` writes a cloud-mode config entry (path "", workspace
id) so later commands route to the cloud. `project remove` deleted the
cloud project but only scrubbed sync fields from that entry, so the stub
outlived the project: list-projects kept reporting it as a local project
at "/", a second `remove` routed to the cloud again and got "not found",
and `add` refused the name as taken with no way out short of editing
config.json.

Remove the entry after a cloud-routed delete succeeds. The default
project is the one entry config must keep, so it is only scrubbed of
sync state and the user is told how to retire it.

Fixes #1340

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017STCpbNsYjZgUdftxgEAZ4
Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-28T22:35:33.302931Z 27fa2f7 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dfdd3d7d68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/basic_memory/cli/commands/project.py Outdated
Comment thread src/basic_memory/cli/commands/project.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dfdd3d7d68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/basic_memory/cli/commands/project.py Outdated
Comment thread src/basic_memory/cli/commands/project.py Outdated
Comment thread src/basic_memory/cli/commands/project.py Outdated
…sync state on any cloud route

Codex review on the first cut found four gaps:

- `--cloud` is a routing override, not proof the local entry is a cloud
  stub: a same-named local project removed with `--cloud` lost its
  config entry while its database row and files stayed. Only entries
  whose stored mode is cloud are removed now.
- Local sync path and bisync-state cleanup were gated on the raw
  `--cloud` flag, so an auto-routed remove of a cloud-mode entry with a
  sync path deleted the entry (and with it the only record of that
  path) but left `bisync-state/<name>` behind, which would let a
  recreated name skip `--resync` against a stale baseline. Cleanup now
  follows the route the delete actually takes.
- The config key was looked up by exact name, so removing `My Research`
  as `my-research` deleted the cloud project but kept the stub. The
  lookup is permalink-aware now, matching ConfigManager.remove_project.

Tests cover each case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017STCpbNsYjZgUdftxgEAZ4
Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b3a6954880

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/basic_memory/cli/commands/project.py
Comment thread src/basic_memory/cli/commands/project.py
…nfig removal on --local

Codex round two on #1355: bisync state lives under the canonical config
name, so removing `My Research` as `my-research` probed the wrong
directory and left the old baseline for a recreated project to reuse;
and an explicit --local hands the delete to the local service, which
already removes the config entry, so the CLI-side removal raised
KeyError after a successful delete. Carry the canonical name through
cleanup and leave config to the local service on --local.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017STCpbNsYjZgUdftxgEAZ4
Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bcea8fdbd0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/basic_memory/cli/commands/project.py Outdated
Codex round three on #1355: if the cloud delete succeeded but a local
rmtree (sync directory, bisync state) raised, the outer handler ran
before the config entry was removed — the remote project was gone and
the stub survived, recreating the stuck state. Persist the config
retirement immediately after the delete, then do the filesystem cleanup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017STCpbNsYjZgUdftxgEAZ4
Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 27fa2f7b40

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@phernandez
phernandez merged commit 6cb5f23 into main Aug 28, 2026
27 checks passed
phernandez added a commit that referenced this pull request Aug 28, 2026
…nfig removal on --local

Codex round two on #1355: bisync state lives under the canonical config
name, so removing `My Research` as `my-research` probed the wrong
directory and left the old baseline for a recreated project to reuse;
and an explicit --local hands the delete to the local service, which
already removes the config entry, so the CLI-side removal raised
KeyError after a successful delete. Carry the canonical name through
cleanup and leave config to the local service on --local.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017STCpbNsYjZgUdftxgEAZ4
Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez
phernandez deleted the fix/1340-cloud-project-remove-stub branch August 28, 2026 23:01
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.

Removing a cloud project leaves an undeletable local stub that list-projects still returns

1 participant