Conversation
A project's id is a slug computed once at creation and never changes on rename, by design — but agent-facing context only exposed the stable id, so a renamed project could look like a different one to an agent. - berdctl info context now also returns active_project_name alongside the existing stable active_project_id. - Document id immutability at its definition (uniqueProjectSlug) and in AGENTS.md. - Add findProjectByWorkingDirectory and use it in berdctl project create to warn (without blocking) when a new project's working directory already belongs to another active project.
morgmart
left a comment
There was a problem hiding this comment.
🤖 Automated code review
REQUEST_CHANGES: the new active_project_name can be null or stale because info context resolves it only from the renderer's local project cache rather than current project data. The supplied GitHub evidence is structurally valid and all reported checks for the exact head SHA passed. A product decision is also needed on whether duplicate working directories are a project-wide rule or an agent-only warning.
Deterministic publication result: 1 blocking and 0 non-blocking inline finding(s) publishable; 0 duplicate(s) suppressed; 0 blocking screenshot-evidence requirement(s) in this review body.
| const voiceBeforeRefresh = useVoiceConversationStore.getState(); | ||
| const nativeVoiceStatus = await getVoiceConversationStatus(); | ||
| const voiceAfterRefresh = useVoiceConversationStore.getState(); | ||
| const activeProjectName = context.activeProjectId |
There was a problem hiding this comment.
🤖 P1 · Resolve the current project name (blocking)
The new field is derived only from useProjectStore.getState().projects. That store starts from an optional localStorage seed and may be empty before projects load or stale after another writer renames the project, so a valid active project ID can be paired with null or an old display name. This defeats the field's stated purpose of disambiguating stable IDs after rename.
User effect: Agents can still mistake the active project for a different project, or use an outdated project name, even though the command now promises the current display name.
Recommended fix: Resolve the active project through the existing current-data project loader before reading its name, while preserving the captured active project ID for a consistent response; return null only when there is no active project or the current project genuinely cannot be found.
Test: Add discriminating command tests where the store is initially empty and where it contains a stale name while the backend returns the renamed project; assert that the result uses the backend's current name and keeps the same stable ID.
There was a problem hiding this comment.
🤖 Addressed in c75a215. info context now captures the active project ID before the async read, then resolves its name directly from one current backend snapshot containing active and archived projects. It returns null only when there is no active ID or that ID is genuinely absent from current data; it no longer relies on the renderer cache.
Added command-level regressions for stale cached names, an empty initial store, archived active projects, and no active project. These assert the stable ID is preserved and the returned name is current.
morgmart
left a comment
There was a problem hiding this comment.
🤖 Automated code review
REQUEST_CHANGES: resolving the supplemental active project name can now fail the entire info context command when the project backend is temporarily unavailable, hiding context that is already known locally. The prior stale-name issue is fixed at this head and is not repeated. Supplied GitHub evidence is structurally valid, and all reported checks for the exact head SHA passed. A product decision remains on whether duplicate working directories are a project-wide rule or agent-only guidance.
Deterministic publication result: 1 blocking and 0 non-blocking inline finding(s) publishable; 0 duplicate(s) suppressed; 0 blocking screenshot-evidence requirement(s) in this review body.
| const [nativeVoiceStatus, activeProject] = await Promise.all([ | ||
| getVoiceConversationStatus(), | ||
| activeProjectId | ||
| ? findCurrentProjectForBerdctl(activeProjectId) |
There was a problem hiding this comment.
🤖 P1 · Keep context available on lookup failure (blocking)
The new project-name lookup runs inside the same Promise.all as the established voice-status read. findCurrentProjectForBerdctl converts a project backend failure into a CommandError, so a temporary failure in this supplemental lookup rejects the whole command instead of returning the view, session ID, stable project ID, voice state, and version that were already available.
User effect: Agents lose all app context during a temporary project read failure, even though Berd still knows what view, session, and project the person is using.
Recommended fix: Treat only the project-name refresh as best effort: preserve the captured stable project ID and return a null or otherwise explicitly unavailable name when that lookup fails, without swallowing failures from the command's established context sources.
Test: Add a command test where an active project ID exists and the project backend rejects; assert that info context still succeeds with the captured view, session ID, and project ID while the project name uses the documented unavailable fallback.
morgmart
left a comment
There was a problem hiding this comment.
🤖 Automated code review
COMMENT: the duplicate-directory warning reports only the first conflict even though one create request can attach several conflicting directories, leaving the agent without a complete account of the split-history risk. Both prior blocking findings are fixed at this head. Supplied GitHub evidence is structurally valid; the macOS Rust check failed while the other reported checks passed, so required checks still govern merge readiness. A product decision remains on whether duplicate working directories are a project-wide rule or agent-only guidance.
Deterministic publication result: 0 blocking and 1 non-blocking inline finding(s) publishable; 0 duplicate(s) suppressed; 0 blocking screenshot-evidence requirement(s) in this review body.
| dir, | ||
| homeDir ?? undefined, | ||
| ); | ||
| if (match) { |
There was a problem hiding this comment.
🤖 P2 · Report every duplicate directory (non-blocking)
The command accepts multiple working_dir values but stops scanning after the first matching project. The returned warning therefore omits any additional directories already attached to other active projects, even though each omitted conflict carries the same risk the warning is intended to expose.
User effect: An agent can believe it has seen the full conflict and continue with a project that still splits related chats and history across other existing projects.
Recommended fix: Collect every conflicting directory and project before creation and return all conflicts, preferably in a structured result that agents can inspect reliably.
Test: Add a command test with multiple requested directories that conflict with different active projects and assert that every conflict is returned.
morgmart
left a comment
There was a problem hiding this comment.
🤖 Automated code review
COMMENT: no publishable changed-line findings remain in the exact comparison. The three prior review issues are fixed at this head: project names use current backend data, lookup failure preserves known context, and every duplicate working-directory conflict is returned structurally. Supplied GitHub evidence is structurally valid; the Windows Rust check is still in progress while all other reported checks passed, so required checks continue to govern merge readiness. A product decision remains on whether duplicate working directories are a project-wide rule or agent-only guidance.
Deterministic publication result: 0 blocking and 0 non-blocking inline finding(s) publishable; 0 duplicate(s) suppressed; 0 blocking screenshot-evidence requirement(s) in this review body.
Summary
A project's
idis a slug computed once from its display name at creation (uniqueProjectSlug). Renaming a project only changes the display name — the id itself never changes, by design, since sessions andberdctlreferences are keyed on it. That design choice was undocumented and caused two problems:berdctl info contextonly exposed the stable id, so an agent could mistake a renamed project for a different one; and nothing warned when a new project's working directory already belonged to another active project, a likely source of split chat history across duplicate projects.This adds
active_project_namealongside the existingactive_project_idinberdctl info context, documents id immutability at its source and inAGENTS.md, and adds a non-blockingwarningtoberdctl project createwhen a working directory duplicates an existing active project.Related issue
Refs BOT-1571 (Linear)
Testing
Added tests for
getContext's new field, the newfindProjectByWorkingDirectoryhelper, the create-duplicate warning, and an assertion that the source name stays fixed on rename.cargo test -p berdctl(52/52) andjust checkboth pass; regenerated the berdctl contract since command help text changed.Generated with Goose