🤖 feat: consolidate project memory in dream runs#3551
Conversation
Include project-scope memory in dream consolidation for single-project workspaces, track explicit project coverage records, and surface scope-aware status in the Memory tab. Validation: bun test src/node/services/memoryConsolidation.test.ts src/node/services/memoryConsolidationService.test.ts && make static-check --- _Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `$35.69`_ <!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=35.69 -->
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Launch sweep now uses project coverage as the debounce anchor when a recent legacy workspace-only record would otherwise suppress first project-memory coverage. Workspace debounce skips are filtered before spending launch sweep cap slots.\n\nValidation:\n- bun test src/node/services/memoryConsolidationService.test.ts --test-name-pattern "recent legacy workspace-only|launch cap"\n- bun test src/node/services/memoryConsolidationService.test.ts\n- make typecheck\n\n---\n\n_Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh`_\n\n<!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh --> Signed-off-by: Thomas Kosiewski <tk@coder.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Emit a dedicated consolidation-status invalidation after coverage sidecar writes, including successful no-op dream runs, and route it through memory subscriptions so open Memory tabs refetch footer status without relying on file mutations. Validation: - bun test src/node/services/memoryConsolidationService.test.ts src/node/orpc/router.memory.test.ts - make typecheck - bun test src/browser/features/RightSidebar/Memory/MemoryTab.test.tsx - make fmt-check - git diff --check
Use the repo-preferred ReadonlyArray type for consolidation project refs. Validation: bun test src/node/services/memoryConsolidation.test.ts src/node/services/memoryConsolidationService.test.ts src/node/orpc/router.memory.test.ts src/browser/features/RightSidebar/Memory/MemoryTab.test.tsx && make static-check --- _Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `$35.69`_ <!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=35.69 -->
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3555fc31ae
ℹ️ 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".
Treat recent project coverage as the debounce anchor when project memory is the only launch-sweep qualifier, so sibling workspaces do not duplicate provider runs within the debounce window. Validation: bun test src/node/services/memoryConsolidation.test.ts src/node/services/memoryConsolidationService.test.ts src/node/orpc/router.memory.test.ts src/browser/features/RightSidebar/Memory/MemoryTab.test.tsx && make static-check --- _Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `$38.29`_ <!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=38.29 -->
|
@codex review Please take another look after the project-only launch debounce fix. |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Config.findWorkspace now exposes stored project refs for consolidation identity checks, so update the exact-shape regression to include them. Validation: bun test src/node/config.test.ts -t 'preserves the config key' && bun test src/node/services/memoryConsolidation.test.ts src/node/services/memoryConsolidationService.test.ts src/node/orpc/router.memory.test.ts src/browser/features/RightSidebar/Memory/MemoryTab.test.tsx && make static-check --- _Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `$38.29`_ <!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=38.29 -->
|
@codex review Small follow-up for the unit CI failure: updated the Config.findWorkspace exact-shape test to include the newly exposed project refs. |
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Mock the experiment hook in MemoryTab tests instead of relying on persisted experiment state, preventing full-suite state contamination from hiding the consolidation footer. Validation: bun test src/browser/features/RightSidebar/Memory/MemoryTab.test.tsx && bun test src/node/config.test.ts -t 'preserves the config key' && bun test src/node/services/memoryConsolidation.test.ts src/node/services/memoryConsolidationService.test.ts src/node/orpc/router.memory.test.ts && make static-check --- _Generated with `mux` • Model: `openai:gpt-5.5` • Thinking: `xhigh` • Cost: `$38.29`_ <!-- mux-attribution: model=openai:gpt-5.5 thinking=xhigh costs=38.29 -->
|
@codex review Small follow-up for the MemoryTab unit CI failure: stabilized the test by mocking the experiment hook rather than depending on persisted experiment state. |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Summary
Consolidates host-local project memory in dream runs for single-project workspaces, while keeping project memory unavailable for multi-project workspaces. The Memory tab now shows separate workspace/project/global consolidation coverage, and launch sweeps dedupe shared project/global work without treating pre-upgrade workspace records as project coverage.
Background
Project memory is now host-local/private, so the dream agent can safely consolidate it without creating checkout diffs. The old consolidation pass still disabled project scope entirely and showed one workspace-local status timestamp, which became misleading once project memory is shared by sibling workspaces.
Implementation
/memories/project/...mutations only when a stable single-project identity is available; pinned project memories remain protected.workspaceRecord,projectRecord,globalRecord,projectAvailable).Deep review fixes
Ran
deep-review-workflowwith auto-fix enabled. It found and fixed:Validation
bun test src/node/services/memoryConsolidation.test.ts src/node/services/memoryConsolidationService.test.ts src/node/orpc/router.memory.test.ts src/browser/features/RightSidebar/Memory/MemoryTab.test.tsxmake static-checkRisks
Medium. This touches background consolidation orchestration, persisted sidecar upgrade semantics, and Memory-tab status subscriptions. Project memory remains disabled for multi-project workspaces, and old sidecars without
projectsare normalized rather than inferred as project coverage.📋 Implementation Plan
Plan: include project memory in dream consolidation
Goal
Update memory consolidation ("dream") so a run from a single-project workspace consolidates all relevant private memory scopes:
/memories/workspace/...for the current workspace/memories/project/...for the current project/memories/global/...shared across projectsThe recent
mainrefactor made project memory host-local/private (<muxHome>/memory/project/<project dir>/) instead of repo-backed, so consolidation can safely include it without creating checkout diffs. Multi-project workspaces should continue to exclude project memory because they have no single stable project identity.Current evidence
src/common/constants/memory.tsnow documents onlyglobal,project, andworkspace;projectis host-local/private and never committed.src/node/services/memoryService.tsresolves project memory fromctx.projectPathto<muxHome>/memory/project/<project dir>/and disables it whenprojectPath === ""or the workspace is multi-project.src/node/services/memoryConsolidationService.tsstill constructs dream runs withprojectPath: "", intentionally disabling project memory.src/node/services/memoryConsolidation.tsstill rejects consolidation mutations outsideworkspaceandglobal.workspaceId. That is not enough once project memory is included, because older workspace records predate project consolidation and sibling workspaces share one project memory store.Advisor-reviewed recommendation (product code estimate: ~130–190 net LoC)
Implement the narrow explicit-state version:
workspace + project + globalfor single-project workspaces.projectsmap so project coverage is tracked explicitly from the first version that actually covers project memory.This is slightly larger than copy-only, but avoids two correctness traps the advisor called out:
Phase 1 — Resolve project identity for consolidation
src/node/services/memoryConsolidationService.ts, e.g.resolveConsolidationProjectPath(foundWorkspace): string.Config.findWorkspace(workspaceId)as the source already available to this service.foundWorkspace.projectPath === MULTI_PROJECT_CONFIG_KEYas"".resolveMemoryProjectIdentityon thefindWorkspacereturn value; that helper expectsWorkspaceMetadata, not the config lookup shape.runLocked, setctx.projectPathto the resolved single-project identity or"".runtime: nullandcheckoutCwd: ""; project memory is host-local now, so the dream run must continue working with stopped runtimes/checkouts.Acceptance criteria
Phase 2 — Expand consolidation mutation rails and dream prompt
src/node/services/memoryConsolidation.ts, expand the guard whitelist fromworkspace | globaltoworkspace | project | globalonly whenctx.projectPath !== ""forprojectpaths.src/node/builtinAgents/dream.mdso the model is no longer told “project scope is protected”.make fmtin this repo regenerates the built-in agent content file).Acceptance criteria
/memories/project/...files within the existing mutation budget.Phase 3 — Persist explicit project coverage
ConsolidationSidecarFileSchemainMemoryConsolidationServicefrom:{ workspaces: Record<string, MemoryConsolidationRecord> }to:
{ workspaces: Record<string, MemoryConsolidationRecord>, projects?: Record<string, MemoryConsolidationRecord> }projectsto{}on load for backward compatibility/self-healing.workspaces[workspaceId] = recordas today;projectPath !== "", also saveprojects[projectPath] = recordin the same atomic read-modify-write cycle.Acceptance criteria
memory-consolidation.jsonfiles withoutprojectscontinue to load.Phase 4 — Update launch sweep selection and dedupe
Project memory is shared by all workspaces in the same project, so automatic launch sweeps should not consolidate the same project-only write once per sibling workspace.
workspaces[workspaceId]?.lastRunAt ?? 0;projects[projectPath]?.lastRunAt ?? 0;globalLastRunAtas today;projectLastRunAt/sidecar.projects[projectPath]equivalent for that project so later siblings in the same sweep are skipped for project-only writes.Acceptance criteria
Phase 5 — Structured status and UI wording
workspaceRecord: MemoryConsolidationRecord | nullprojectRecord: MemoryConsolidationRecord | nullglobalRecord: MemoryConsolidationRecord | nullprojectAvailable: booleanmemory.consolidationStatusto return that payload instead of a bare nullable record.getStatus(workspaceId)so router/UI code does not duplicate sidecar/project/global derivation.src/browser/features/Memory/MemoryBrowser.tsxto render compact scope-aware status in the footer.counter-numsfor changing numeric text if the layout shows counts/times prominently.src/browser/stories/mocks/orpc.tsandMemoryTab.stories.tsxso Storybook can render the expanded status shape.Acceptance criteria
Phase 6 — Tests
Add/update behavior-focused tests; avoid tautological string tests.
Backend tests:
src/node/services/memoryConsolidation.test.tsctx.projectPathis present.ctx.projectPath === "".src/node/services/memoryConsolidationService.test.tsprojectsself-heal/default correctly.consolidationStatusreturns structured payload and null project record when project is unavailable.UI/story tests:
Phase 7 — Dogfooding / quality gates
Quality gates between phases:
Dogfooding steps for implementation mode:
memoryandmemory-consolidationexperiments enabled.Validation commands:
bun test src/node/services/memoryConsolidation.test.ts src/node/services/memoryConsolidationService.test.ts bunx prettier --check src/common/orpc/schemas/memory.ts src/common/orpc/schemas/api.ts src/node/services/memoryConsolidation.ts src/node/services/memoryConsolidationService.ts src/browser/features/Memory/MemoryBrowser.tsx src/browser/stories/mocks/orpc.ts src/browser/features/RightSidebar/Memory/MemoryTab.stories.tsx bunx eslint src/common/orpc/schemas/memory.ts src/common/orpc/schemas/api.ts src/node/services/memoryConsolidation.ts src/node/services/memoryConsolidationService.ts src/browser/features/Memory/MemoryBrowser.tsx src/browser/stories/mocks/orpc.ts src/browser/features/RightSidebar/Memory/MemoryTab.stories.tsx make typecheckRisks / decisions
projectscoverage is required because old workspace records did not cover project memory. Do not infer project coverage from workspace records created before this change.Evidence and advice incorporated
projectssidecar/status middle path: smaller than a full per-scope history system, but more correct than copy-only or deriving project status from old workspace records.Generated with
mux• Model:openai:gpt-5.5• Thinking:xhigh• Cost:$38.29