CTO revamp: one persistent-memory agent thread (desktop + iOS)#702
Conversation
… workers/workflows removed Desktop + iOS CTO tab redesigned around a single long-living agent thread: - Smart memory (files-as-truth under .ade/cto/): curated MEMORY.md (always injected, cap-truncated only in injection), rolling thread-state.md flushed deterministically before compaction and model switches (async LLM upgrade), turn-end daily-log journal, saveMemory/searchMemory/readMemory operator tools, memory-rich reconstruction injection on start/compaction/switch. - Model switching never breaks the thread: same ADE session across providers, flush-before-teardown, identity modelPreferences synced both ways, foreign- lane CTO sessions rebind instead of orphaning; dead model-switch policy removed. - Legacy removed completely (incl. tests/docs): worker/hiring subsystem, Linear workflow engine (dispatch/sync/ingress/intake/routing/closeout/ outbound/flow-policy/templates), pipeline builder, Team/Workflows surfaces, ~45 dead IPC channels + 17 sync commands, dead `ade flow`/`ade cto` CLI. Kept Linear read/credential plumbing used by PRs, lane cards, chat attachments, and `ade linear`. - New desktop UI: no tabs — slim identity header + full-bleed thread + settings sheet (personality, work style, live model switch, editable memory panel, prompt preview); single-card onboarding. - iOS parity: brain tab icon matching desktop, inline single-thread tab, one-card setup (personality + work style), trimmed settings with memory section via new cto.getMemory sync command. - Docs rewritten: cto/README, linear-integration canonicalized, all worker/ workflow cross-references, public Mintlify pages + nav. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iOS work-style parity - ctoMemoryService owns the turn-journal line format (appendTurnJournal) using shared clipText; removed the test-only _localHourMinute export and the duplicate clip helper in agentChatService; trimmed unused service exports. - iOS CtoSetup: verbosity segmented order matches desktop (concise/adaptive/ detailed); preset descriptions mirror shared CTO_PERSONALITY_PRESETS verbatim. - Removed stale recentSubordinateActivity field from adeRpcServer test mock. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ocs parity drift - Consolidated cto/ suite: linearTokenRefresh tests folded into linearAuth (helper-of-parent), linearLiveStatusService tests folded into linearLaneCardService (Linear PR-reflection contract); 6 → 4 test files, all 84 cases green. - Added appendTurnJournal contract test (format, caps, blank-turn no-op). - TUI: removed dead /linear workflows|run|route|sync|ingress slash groups that pointed at deleted daemon tools; usage strings updated; tests replaced. - CLI: help text no longer advertises removed `ade cto` / linear workflow subcommands; stale routing comment fixed. - Docs: restored Source file map to linear-integration README; fixed 3 stale ARCHITECTURE.md tree comments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
@copilot review but do not make fixes |
📝 WalkthroughWalkthroughAdds durable CTO memory storage and threads it through CTO state, tools, chat, IPC, and runtime wiring. Removes worker-agent and Linear workflow/dispatcher/sync/ingress services, plus related CLI, RPC, and test surface updates. ChangesCTO Memory + Worker/Linear Pipeline Removal
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/desktop/src/main/services/ai/tools/ctoOperatorTools.ts (1)
1620-1638: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPass
ctoStateServiceinto the ADE RPC tool bridge
createCtoOperatorToolsalready acceptsctoStateService, andgetRecentEventsuses it forcto_sessionentries, butapps/ade-cli/src/adeRpcServer.ts:2355-2367only passesctoMemoryService. AddctoStateService: runtime.ctoStateService.🤖 Prompt for 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. In `@apps/desktop/src/main/services/ai/tools/ctoOperatorTools.ts` around lines 1620 - 1638, `getRecentEvents` in `createCtoOperatorTools` already reads from `deps.ctoStateService`, but the ADE RPC bridge is only wiring `ctoMemoryService`, so `cto_session` events are missing. Update the `createCtoOperatorTools` call in the ADE RPC server to pass `ctoStateService` from runtime alongside the existing deps, matching the `deps.ctoStateService` usage in the session log collection block.Source: Coding guidelines
🧹 Nitpick comments (2)
apps/ade-cli/src/adeRpcServer.ts (1)
2690-2692: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStale name:
CTO_LINEAR_SYNC_TOOL_SPECSno longer holds sync tools.Per the line-range change details, the sync/queue/ingress/flow-policy/routing tools were removed from this array, and it now appears to hold issue-query tools like
getLinearIssuePickerData/searchLinearIssues/getLinearIssueComments(per the test file's expectations). The_SYNC_name is now misleading for future readers.♻️ Suggested rename
-const CTO_LINEAR_SYNC_TOOL_SPECS = [...] +const CTO_LINEAR_ISSUE_TOOL_SPECS = [...](and update the reference at this call site accordingly)
🤖 Prompt for 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. In `@apps/ade-cli/src/adeRpcServer.ts` around lines 2690 - 2692, `CTO_LINEAR_SYNC_TOOL_SPECS` is now a misleading name because it no longer contains sync/queue/ingress/flow-policy/routing tools and instead groups Linear issue-query tools like `getLinearIssuePickerData`, `searchLinearIssues`, and `getLinearIssueComments`. Rename the constant to something that reflects its current contents, and update the `allVisibleTools` assembly in `adeRpcServer` to use the new symbol so the CTO tool list remains clear and accurate.apps/desktop/src/main/services/chat/agentChatService.test.ts (1)
4239-4293: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winEnsure
db.close()runs even if assertions fail.Both new tests open a real on-disk KV db (with migrations) via
createCtoServices()and only calldb.close()as the final line. If anexpect(...)earlier in the test throws, the db handle is never closed, leaking the sqlite connection/file for the rest of the run. Wrap the body intry { ... } finally { db.close(); }, or move the close into anafterEachkeyed off a per-test db reference.♻️ Suggested cleanup pattern
it("persists a CTO model switch back into identity model preferences (D3)", async () => { const { db, ctoStateService, ctoMemoryService } = await createCtoServices(); - const { service } = createService({ ctoStateService, ctoMemoryService }); - - const session = await service.ensureIdentitySession({ - identityKey: "cto", - laneId: "lane-1", - }); - - await service.updateSession({ - sessionId: session.id, - modelId: "opencode/openai/gpt-5.2", - }); - - const prefs = ctoStateService.getIdentity().modelPreferences; - expect(prefs.modelId).toBe("opencode/openai/gpt-5.2"); - expect(prefs.provider).toBe("opencode"); - - db.close(); + try { + const { service } = createService({ ctoStateService, ctoMemoryService }); + const session = await service.ensureIdentitySession({ + identityKey: "cto", + laneId: "lane-1", + }); + await service.updateSession({ + sessionId: session.id, + modelId: "opencode/openai/gpt-5.2", + }); + const prefs = ctoStateService.getIdentity().modelPreferences; + expect(prefs.modelId).toBe("opencode/openai/gpt-5.2"); + expect(prefs.provider).toBe("opencode"); + } finally { + db.close(); + } });🤖 Prompt for 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. In `@apps/desktop/src/main/services/chat/agentChatService.test.ts` around lines 4239 - 4293, The two CTO memory tests leak the real KV db handle if an assertion fails because `db.close()` is only called at the end of each `it` block. Update both tests in `agentChatService.test.ts` to ensure cleanup always runs by wrapping the test body in `try/finally` with `db.close()` in the `finally`, or by moving the cleanup into an `afterEach` tied to the `createCtoServices()` db reference. Keep the existing assertions around `createCtoServices`, `ensureIdentitySession`, `updateSession`, and `buildReconstructionContext`, but make the db teardown unconditional.
🤖 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 `@apps/ade-cli/src/bootstrap.ts`:
- Around line 1190-1192: The headless ADE bootstrap is not forwarding Linear
credentials into the sync runtime, so CTO Linear status checks can miss stored
tokens. Update the headless service wiring in bootstrap.ts where the sync
runtime is assembled to pass headlessLinearServices.linearCredentialService
alongside getLinearIssueTracker, matching the
createSyncService/createSyncRemoteCommandService path. Verify the CTO Linear
status flow (cto.getLinearConnectionStatus and quick view) uses the same
credential source in both headless mode and the desktop socket-backed ADE RPC
path.
In `@apps/ade-cli/src/cli.ts`:
- Around line 9766-9769: Update the fallback error message in buildLinearPlan so
it matches the वास्तविक supported linear subcommands. In the CliUsageError
thrown for unknown subcommands, remove the unsupported `projects` entry and add
the implemented commands currently missing from the list, especially
`picker-data`/`picker` and `search-issues`/`search`. Keep the message aligned
with the actual branches in buildLinearPlan so users are only advertised
commands handled by the `sub` switch logic.
In `@apps/desktop/src/main/services/ai/tools/ctoOperatorTools.ts`:
- Around line 1993-2000: The `saveMemory` flow in `ctoOperatorTools.ts`
currently writes any fact through `deps.ctoMemoryService.appendMemoryFact`,
which can leak credentials into `MEMORY.md`. Add a secret-detection guard in the
`execute` path before calling `appendMemoryFact`, and reject/return an error
when the input looks like credentials or other secrets. Keep the check close to
the `saveMemory` tool implementation so plaintext memory writes are blocked
unless the fact is clearly non-sensitive.
- Around line 2034-2040: The readMemory tool is omitting daily log data even
though ctoMemoryService.getSnapshot() returns it. Update the readMemory response
to include dailyLog and dailyLogDate alongside memory, threadState, and
updatedAt so the tool can read the recent daily memory stream. Use the
getSnapshot() call in ctoOperatorTools to locate the return shape and preserve
the existing fields while adding the missing ones.
In `@apps/desktop/src/main/services/cto/ctoMemoryService.ts`:
- Around line 98-199: Add a secret-detection guard before any CTO memory write
in ctoMemoryService so sensitive content is not persisted to `.ade/cto/*.md`.
Update the write paths used by writeMemory, appendMemoryFact, writeThreadState,
appendDailyEntry, and appendTurnJournal to reject or reroute content containing
API keys, tokens, passwords, or private keys, using the existing encrypted
secret store instead of plaintext files. Keep the check close to the file-write
boundary so all callers are covered consistently.
- Around line 150-157: The trimming logic in ctoMemoryService’s saveMemory flow
only removes older entries while facts.length > 1, so a single oversized fact
can still exceed MEMORY_FILE_MAX_BYTES. Update the render/write path to handle
the one-fact case explicitly: if the newest fact alone is too large, either clip
that fact’s content or reject it before calling writeTextAtomic. Keep the
existing byte-cap loop, but add the single-fact fallback around render(facts) so
MEMORY.md always stays within the limit.
In `@apps/desktop/src/main/services/cto/ctoStateService.ts`:
- Around line 131-132: Add an explicit no-secrets rule to the persistent-memory
guidance in ctoStateService so the instructions for
saveMemory/searchMemory/readMemory clearly forbid storing API keys, tokens,
passwords, private keys, or other credentials in plaintext project files. Update
the guidance text near the existing durable-facts bullets to state that secrets
must not be saved to `.ade/cto/` and should use the encrypted store instead,
keeping the wording concise and consistent with the surrounding ctoStateService
memory policy.
---
Outside diff comments:
In `@apps/desktop/src/main/services/ai/tools/ctoOperatorTools.ts`:
- Around line 1620-1638: `getRecentEvents` in `createCtoOperatorTools` already
reads from `deps.ctoStateService`, but the ADE RPC bridge is only wiring
`ctoMemoryService`, so `cto_session` events are missing. Update the
`createCtoOperatorTools` call in the ADE RPC server to pass `ctoStateService`
from runtime alongside the existing deps, matching the `deps.ctoStateService`
usage in the session log collection block.
---
Nitpick comments:
In `@apps/ade-cli/src/adeRpcServer.ts`:
- Around line 2690-2692: `CTO_LINEAR_SYNC_TOOL_SPECS` is now a misleading name
because it no longer contains sync/queue/ingress/flow-policy/routing tools and
instead groups Linear issue-query tools like `getLinearIssuePickerData`,
`searchLinearIssues`, and `getLinearIssueComments`. Rename the constant to
something that reflects its current contents, and update the `allVisibleTools`
assembly in `adeRpcServer` to use the new symbol so the CTO tool list remains
clear and accurate.
In `@apps/desktop/src/main/services/chat/agentChatService.test.ts`:
- Around line 4239-4293: The two CTO memory tests leak the real KV db handle if
an assertion fails because `db.close()` is only called at the end of each `it`
block. Update both tests in `agentChatService.test.ts` to ensure cleanup always
runs by wrapping the test body in `try/finally` with `db.close()` in the
`finally`, or by moving the cleanup into an `afterEach` tied to the
`createCtoServices()` db reference. Keep the existing assertions around
`createCtoServices`, `ensureIdentitySession`, `updateSession`, and
`buildReconstructionContext`, but make the db teardown unconditional.
🪄 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: CHILL
Plan: Pro
Run ID: 5d4d447c-c2f8-4d24-ab83-acdb232b5390
⛔ Files ignored due to path filters (33)
apps/ios/ADE.xcodeproj/project.pbxprojis excluded by!**/*.xcodeproj/project.pbxprojdocs.jsonis excluded by!docs.jsondocs/ARCHITECTURE.mdis excluded by!docs/**docs/PRD.mdis excluded by!docs/**docs/README.mdis excluded by!docs/**docs/features/agents/README.mdis excluded by!docs/**docs/features/agents/identity-and-personas.mdis excluded by!docs/**docs/features/agents/tool-registration.mdis excluded by!docs/**docs/features/automations/README.mdis excluded by!docs/**docs/features/automations/guardrails.mdis excluded by!docs/**docs/features/automations/triggers-and-actions.mdis excluded by!docs/**docs/features/chat/README.mdis excluded by!docs/**docs/features/chat/agent-routing.mdis excluded by!docs/**docs/features/chat/composer-and-ui.mdis excluded by!docs/**docs/features/chat/tool-system.mdis excluded by!docs/**docs/features/computer-use/README.mdis excluded by!docs/**docs/features/computer-use/artifact-broker.mdis excluded by!docs/**docs/features/cto/README.mdis excluded by!docs/**docs/features/cto/linear-integration.mdis excluded by!docs/**docs/features/cto/onboarding.mdis excluded by!docs/**docs/features/cto/pipeline-builder.mdis excluded by!docs/**docs/features/cto/workers.mdis excluded by!docs/**docs/features/history/README.mdis excluded by!docs/**docs/features/history/recording-and-export.mdis excluded by!docs/**docs/features/linear-integration/README.mdis excluded by!docs/**docs/features/linear-integration/dispatch-and-sync.mdis excluded by!docs/**docs/features/linear-integration/workflow-presets.mdis excluded by!docs/**docs/features/onboarding-and-settings/README.mdis excluded by!docs/**docs/features/sync-and-multi-device/README.mdis excluded by!docs/**docs/features/sync-and-multi-device/ios-companion.mdis excluded by!docs/**docs/features/sync-and-multi-device/remote-commands.mdis excluded by!docs/**key-concepts.mdxis excluded by!*.mdxwelcome.mdxis excluded by!*.mdx
📒 Files selected for processing (137)
apps/ade-cli/src/adeRpcServer.test.tsapps/ade-cli/src/adeRpcServer.tsapps/ade-cli/src/bootstrap.tsapps/ade-cli/src/cli.test.tsapps/ade-cli/src/cli.tsapps/ade-cli/src/headlessLinearServices.test.tsapps/ade-cli/src/headlessLinearServices.tsapps/ade-cli/src/services/sync/syncHostService.tsapps/ade-cli/src/services/sync/syncRemoteCommandService.tsapps/ade-cli/src/services/sync/syncService.tsapps/ade-cli/src/tuiClient/__tests__/commands.test.tsapps/ade-cli/src/tuiClient/commands.tsapps/ade-cli/src/tuiClient/linearCommands.tsapps/desktop/src/main/main.tsapps/desktop/src/main/services/adeActions/registry.test.tsapps/desktop/src/main/services/adeActions/registry.tsapps/desktop/src/main/services/ai/tools/ctoOperatorTools.test.tsapps/desktop/src/main/services/ai/tools/ctoOperatorTools.tsapps/desktop/src/main/services/automations/automationService.tsapps/desktop/src/main/services/chat/agentChatService.test.tsapps/desktop/src/main/services/chat/agentChatService.tsapps/desktop/src/main/services/chat/identitySessionPolicy.test.tsapps/desktop/src/main/services/chat/identitySessionPolicy.tsapps/desktop/src/main/services/cto/ctoMemoryService.test.tsapps/desktop/src/main/services/cto/ctoMemoryService.tsapps/desktop/src/main/services/cto/ctoPromptContent.tsapps/desktop/src/main/services/cto/ctoState.test.tsapps/desktop/src/main/services/cto/ctoStateService.tsapps/desktop/src/main/services/cto/ctoWorkerLifecycle.test.tsapps/desktop/src/main/services/cto/flowPolicyService.tsapps/desktop/src/main/services/cto/linearAuth.test.tsapps/desktop/src/main/services/cto/linearCloseoutService.tsapps/desktop/src/main/services/cto/linearDispatcherRunStore.tsapps/desktop/src/main/services/cto/linearDispatcherService.tsapps/desktop/src/main/services/cto/linearIngressService.tsapps/desktop/src/main/services/cto/linearIntake.test.tsapps/desktop/src/main/services/cto/linearIntakeService.tsapps/desktop/src/main/services/cto/linearLaneCardService.test.tsapps/desktop/src/main/services/cto/linearLiveStatusService.test.tsapps/desktop/src/main/services/cto/linearOutboundService.tsapps/desktop/src/main/services/cto/linearRoutingService.tsapps/desktop/src/main/services/cto/linearSync.test.tsapps/desktop/src/main/services/cto/linearSyncService.tsapps/desktop/src/main/services/cto/linearTemplateService.tsapps/desktop/src/main/services/cto/linearTokenRefresh.test.tsapps/desktop/src/main/services/cto/linearWorkflowFileService.tsapps/desktop/src/main/services/cto/workerAdapterRuntimeService.tsapps/desktop/src/main/services/cto/workerAgentService.tsapps/desktop/src/main/services/cto/workerBudgetService.tsapps/desktop/src/main/services/cto/workerHeartbeatService.tsapps/desktop/src/main/services/cto/workerRevisionService.tsapps/desktop/src/main/services/cto/workerTaskSessionService.tsapps/desktop/src/main/services/ipc/registerIpc.tsapps/desktop/src/main/services/lanes/laneService.tsapps/desktop/src/main/services/projects/adeProjectService.tsapps/desktop/src/main/services/sync/syncRemoteCommandService.test.tsapps/desktop/src/preload/global.d.tsapps/desktop/src/preload/preload.test.tsapps/desktop/src/preload/preload.tsapps/desktop/src/renderer/browserMock.tsapps/desktop/src/renderer/components/app/AppShell.tsxapps/desktop/src/renderer/components/app/TabNav.tsxapps/desktop/src/renderer/components/chat/AgentChatPane.test.tsxapps/desktop/src/renderer/components/chat/AgentChatPane.tsxapps/desktop/src/renderer/components/cto/AgentSidebar.tsxapps/desktop/src/renderer/components/cto/CtoMemoryPanel.tsxapps/desktop/src/renderer/components/cto/CtoOnboardingCard.tsxapps/desktop/src/renderer/components/cto/CtoPage.tsxapps/desktop/src/renderer/components/cto/CtoSettingsPanel.tsxapps/desktop/src/renderer/components/cto/IdentityEditor.tsxapps/desktop/src/renderer/components/cto/LinearSyncPanel.tsxapps/desktop/src/renderer/components/cto/OnboardingBanner.tsxapps/desktop/src/renderer/components/cto/OnboardingWizard.tsxapps/desktop/src/renderer/components/cto/Segmented.tsxapps/desktop/src/renderer/components/cto/TeamPanel.tsxapps/desktop/src/renderer/components/cto/WorkerActivityFeed.tsxapps/desktop/src/renderer/components/cto/WorkerCreationWizard.tsxapps/desktop/src/renderer/components/cto/ctoUi.test.tsxapps/desktop/src/renderer/components/cto/personalityTheme.tsapps/desktop/src/renderer/components/cto/pipeline/CloseoutCard.tsxapps/desktop/src/renderer/components/cto/pipeline/OperationsSidebar.tsxapps/desktop/src/renderer/components/cto/pipeline/PipelineCanvas.tsxapps/desktop/src/renderer/components/cto/pipeline/PipelineVisualization.tsxapps/desktop/src/renderer/components/cto/pipeline/StageCard.tsxapps/desktop/src/renderer/components/cto/pipeline/StageConfigPanel.tsxapps/desktop/src/renderer/components/cto/pipeline/StageConnector.tsxapps/desktop/src/renderer/components/cto/pipeline/TriggerCard.tsxapps/desktop/src/renderer/components/cto/pipeline/WorkflowListSidebar.tsxapps/desktop/src/renderer/components/cto/pipeline/config/AdvancedConfig.tsxapps/desktop/src/renderer/components/cto/pipeline/config/CloseoutConfig.tsxapps/desktop/src/renderer/components/cto/pipeline/config/ExecutionConfig.tsxapps/desktop/src/renderer/components/cto/pipeline/config/PlanConfig.tsxapps/desktop/src/renderer/components/cto/pipeline/config/TriggerConfig.tsxapps/desktop/src/renderer/components/cto/pipeline/pipeline.test.tsapps/desktop/src/renderer/components/cto/pipeline/pipelineHelpers.tsapps/desktop/src/renderer/components/cto/pipeline/pipelineLabels.tsapps/desktop/src/renderer/components/cto/pipeline/shared/VisualSelector.tsxapps/desktop/src/renderer/components/cto/shared/AgentStatusBadge.tsxapps/desktop/src/renderer/components/cto/shared/ConnectionStatusDot.tsxapps/desktop/src/renderer/components/cto/shared/designTokens.tsapps/desktop/src/renderer/components/cto/useCtoModelOptions.tsapps/desktop/src/renderer/components/history/eventTaxonomy.tsapps/desktop/src/renderer/components/history/historyActivitySources.test.tsapps/desktop/src/renderer/components/history/historyActivitySources.tsapps/desktop/src/shared/chatModelSwitching.test.tsapps/desktop/src/shared/chatModelSwitching.tsapps/desktop/src/shared/ipc.tsapps/desktop/src/shared/linearWorkflowPresets.test.tsapps/desktop/src/shared/linearWorkflowPresets.tsapps/desktop/src/shared/types/agents.tsapps/desktop/src/shared/types/chat.tsapps/desktop/src/shared/types/cto.tsapps/desktop/src/shared/types/index.tsapps/desktop/src/shared/types/linearSync.tsapps/desktop/src/shared/types/sync.tsapps/desktop/src/shared/workerRuntimeNoise.tsapps/ios/ADE/App/ContentView.swiftapps/ios/ADE/Models/RemoteModels.swiftapps/ios/ADE/Services/SyncService.swiftapps/ios/ADE/Views/Cto/CtoIdentityEditor.swiftapps/ios/ADE/Views/Cto/CtoRootScreen.swiftapps/ios/ADE/Views/Cto/CtoSessionDestinationView.swiftapps/ios/ADE/Views/Cto/CtoSettingsScreen.swiftapps/ios/ADE/Views/Cto/CtoSetup.swiftapps/ios/ADE/Views/Cto/CtoSharedHelpers.swiftapps/ios/ADE/Views/Cto/CtoTabShell.swiftapps/ios/ADE/Views/Cto/CtoTeamScreen.swiftapps/ios/ADE/Views/Cto/CtoWorkerDetailScreen.swiftapps/ios/ADE/Views/Cto/CtoWorkflowsScreen.swiftapps/ios/ADETests/ADETests.swiftchat/capabilities.mdxcto/overview.mdxcto/setup.mdxcto/workers.mdxintegrations/linear.mdxtools/automations.mdxtools/history.mdx
💤 Files with no reviewable changes (29)
- apps/desktop/src/main/services/cto/linearLiveStatusService.test.ts
- apps/desktop/src/main/services/cto/flowPolicyService.ts
- apps/desktop/src/main/services/cto/linearTokenRefresh.test.ts
- apps/desktop/src/main/services/cto/linearDispatcherService.ts
- apps/desktop/src/main/services/cto/linearRoutingService.ts
- apps/desktop/src/main/services/cto/linearOutboundService.ts
- apps/desktop/src/main/services/cto/linearIntakeService.ts
- apps/desktop/src/main/services/cto/workerRevisionService.ts
- apps/desktop/src/main/services/cto/linearIngressService.ts
- apps/desktop/src/main/services/cto/linearWorkflowFileService.ts
- apps/desktop/src/main/services/cto/linearSyncService.ts
- apps/desktop/src/main/services/cto/workerAgentService.ts
- apps/desktop/src/main/services/cto/linearIntake.test.ts
- apps/desktop/src/main/services/cto/workerTaskSessionService.ts
- apps/desktop/src/main/services/cto/linearDispatcherRunStore.ts
- apps/desktop/src/main/services/cto/workerAdapterRuntimeService.ts
- apps/desktop/src/main/services/cto/linearTemplateService.ts
- apps/desktop/src/main/services/cto/ctoWorkerLifecycle.test.ts
- apps/desktop/src/main/services/cto/workerBudgetService.ts
- apps/desktop/src/main/services/cto/ctoPromptContent.ts
- apps/desktop/src/main/services/cto/workerHeartbeatService.ts
- apps/desktop/src/main/services/lanes/laneService.ts
- apps/desktop/src/main/services/cto/linearCloseoutService.ts
- apps/desktop/src/main/services/projects/adeProjectService.ts
- apps/ade-cli/src/cli.test.ts
- apps/ade-cli/src/headlessLinearServices.test.ts
- apps/desktop/src/main/services/automations/automationService.ts
- apps/desktop/src/main/services/adeActions/registry.ts
- apps/ade-cli/src/headlessLinearServices.ts
| inputSchema: z.object({ | ||
| fact: z.string().trim().min(1).describe("A single durable fact to remember."), | ||
| }), | ||
| execute: async ({ fact }) => { | ||
| if (!deps.ctoMemoryService) return { success: false, error: "Memory service is not available." }; | ||
| try { | ||
| const result = deps.ctoMemoryService.appendMemoryFact(fact); | ||
| return { success: true, saved: result.saved, fact: result.fact, file: "MEMORY.md" }; |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Reject secrets before writing to plaintext memory.
saveMemory persists arbitrary facts into MEMORY.md; add a guard so credentials are not stored outside the encrypted secret store.
Suggested patch
execute: async ({ fact }) => {
if (!deps.ctoMemoryService) return { success: false, error: "Memory service is not available." };
try {
+ if (/\b(api[_ -]?key|access[_ -]?token|password|secret|private key|credential)\b/i.test(fact)) {
+ return {
+ success: false,
+ error: "Do not store secrets in persistent memory; use ADE's encrypted secret storage instead.",
+ };
+ }
const result = deps.ctoMemoryService.appendMemoryFact(fact);
return { success: true, saved: result.saved, fact: result.fact, file: "MEMORY.md" };As per coding guidelines, "**: Do not store secrets in plaintext project files when an encrypted store already exists".
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| inputSchema: z.object({ | |
| fact: z.string().trim().min(1).describe("A single durable fact to remember."), | |
| }), | |
| execute: async ({ fact }) => { | |
| if (!deps.ctoMemoryService) return { success: false, error: "Memory service is not available." }; | |
| try { | |
| const result = deps.ctoMemoryService.appendMemoryFact(fact); | |
| return { success: true, saved: result.saved, fact: result.fact, file: "MEMORY.md" }; | |
| inputSchema: z.object({ | |
| fact: z.string().trim().min(1).describe("A single durable fact to remember."), | |
| }), | |
| execute: async ({ fact }) => { | |
| if (!deps.ctoMemoryService) return { success: false, error: "Memory service is not available." }; | |
| try { | |
| if (/\b(api[_ -]?key|access[_ -]?token|password|secret|private key|credential)\b/i.test(fact)) { | |
| return { | |
| success: false, | |
| error: "Do not store secrets in persistent memory; use ADE's encrypted secret storage instead.", | |
| }; | |
| } | |
| const result = deps.ctoMemoryService.appendMemoryFact(fact); | |
| return { success: true, saved: result.saved, fact: result.fact, file: "MEMORY.md" }; |
🤖 Prompt for 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.
In `@apps/desktop/src/main/services/ai/tools/ctoOperatorTools.ts` around lines
1993 - 2000, The `saveMemory` flow in `ctoOperatorTools.ts` currently writes any
fact through `deps.ctoMemoryService.appendMemoryFact`, which can leak
credentials into `MEMORY.md`. Add a secret-detection guard in the `execute` path
before calling `appendMemoryFact`, and reject/return an error when the input
looks like credentials or other secrets. Keep the check close to the
`saveMemory` tool implementation so plaintext memory writes are blocked unless
the fact is clearly non-sensitive.
Source: Coding guidelines
- Merge origin/main (conflict in ios-companion.md resolved: main's newer Work/PRs rows + this branch's CTO row). - Secret hygiene for CTO memory: redactSecrets applied at every ctoMemoryService write path (writeMemory/appendMemoryFact/writeThreadState/ appendDailyEntry, covering appendTurnJournal); single facts clipped to 2000 chars so one oversized saveMemory cannot evict the whole file; memory guidance prompt now forbids storing secrets; regression test added. - readMemory tool returns dailyLog/dailyLogDate alongside memory/thread state. - Headless sync runtime forwards linearCredentialService so cto.getLinearConnectionStatus reports stored credentials on remote hosts. - `ade linear` unknown-subcommand error lists the real supported subcommands. - Fix duplicate type import from the test consolidation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e16fdaefe
ℹ️ 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".
| getMemory: async (): Promise<CtoMemorySnapshot> => | ||
| ipcRenderer.invoke(IPC.ctoGetMemory, {}), | ||
| updateMemory: async (args: CtoUpdateMemoryArgs): Promise<CtoMemorySnapshot> => | ||
| ipcRenderer.invoke(IPC.ctoUpdateMemory, args), | ||
| searchMemory: async (args: CtoSearchMemoryArgs): Promise<CtoSearchMemoryResult> => |
There was a problem hiding this comment.
Route CTO memory calls through the project runtime
When the renderer is bound to a socket-backed local/remote project runtime, these direct ipcRenderer.invoke calls bypass the same callProjectRuntimeActionOr path used by adjacent CTO state methods. In that context the Memory settings panel will read/write the Electron host AppContext instead of the bound project, or fail with “CTO memory service is not available,” so project-specific memory cannot be viewed or edited from remote/runtime-backed desktops.
Useful? React with 👍 / 👎.
| var isOnboardingComplete: Bool { | ||
| onboardingState?.isComplete ?? false |
There was a problem hiding this comment.
Treat dismissed CTO onboarding as unblocked on iOS
If a user clicks the desktop “Set up later” path, the stored onboarding state has dismissedAt but no completedAt or identity step; desktop explicitly treats that as non-blocking, but this iOS helper returns false and CtoRootScreen gates the whole tab on it. Those users are forced back into setup on iOS and cannot open the CTO chat/settings until they complete setup, even though they already dismissed onboarding on desktop.
Useful? React with 👍 / 👎.
…smissed setup - New cto_memory action domain (getSnapshot/updateMemory/searchMemory) in the shared adeActions registry; preload memory methods now use callProjectRuntimeActionOr like the rest of the CTO surface, so runtime-backed and remote-bound desktops read/write the bound project's memory instead of the Electron host context (Codex P2 + Greptile P1). - iOS: dismissed-but-not-completed setup no longer blocks the CTO tab (isOnboardingBlocking mirrors desktop's needsOnboarding gate); added a "Set up later" skip to the setup card for desktop parity; regression test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e167068e70
ℹ️ 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".
| "setAgentStatus", | ||
| "triggerWakeup", | ||
| ], | ||
| cto_memory: ["getSnapshot", "searchMemory", "updateMemory"], |
There was a problem hiding this comment.
Gate CTO memory writes behind the CTO role
When a non-CTO ADE action caller invokes run_ade_action for cto_memory.updateMemory, this allowlist exposes the mutating method, but ADE_ACTION_CTO_ONLY above does not include cto_memory, so the role guard in the RPC action path never runs. That lets any agent/external caller with ADE action access overwrite the persistent .ade/cto/MEMORY.md, which is injected into the CTO across sessions and model switches; the mutating memory method should be marked CTO-only before it is exposed.
Useful? React with 👍 / 👎.
| if (managed.session.identityKey === "cto" && modelChanged) { | ||
| persistCtoModelPreference(managed, descriptor.id); |
There was a problem hiding this comment.
Persist reasoning-only CTO model changes
When the CTO Settings reasoning picker changes only the reasoning tier for the current model, updateSession receives the same modelId, so modelChanged is false even though the session's reasoningEffort is updated earlier in this branch. This new persistence hook is therefore skipped, leaving ctoStateService's modelPreferences.reasoningEffort stale; future new/reconciled CTO sessions can fall back to the old effort despite the user changing it in Settings.
Useful? React with 👍 / 👎.
…soning-only changes - cto_memory.updateMemory added to ADE_ACTION_CTO_ONLY so non-CTO ADE-action callers cannot overwrite the CTO's injected durable memory (Codex P1). - MEMORY.md byte-cap eviction no longer destroys facts: oldest facts move to append-only .ade/cto/memory-archive.md, remain searchable via searchMemory, and saveMemory reports the eviction to the model (Greptile P1). - Reasoning-only CTO tier changes now persist into identity modelPreferences (both the same-model and reasoning-only updateSession branches) so ensured sessions do not resurrect a stale effort (Codex P2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex review |
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@apps/desktop/src/main/services/adeActions/registry.ts`:
- Around line 1202-1204: The updateMemory handler currently converts an omitted
memory payload into an empty string and writes it directly, which can overwrite
MEMORY.md with blank content. Update the updateMemory logic in registry.ts so it
rejects missing or empty args?.memory instead of defaulting to "", or route the
write through the archive-preserving path used by ctoMemoryService to avoid
losing evicted facts. Refer to updateMemory and
ctoMemoryService.writeMemory/getSnapshot when making the change.
🪄 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: CHILL
Plan: Pro
Run ID: e5e30e16-0207-4de2-a780-d3aef4cd3a49
⛔ Files ignored due to path filters (4)
apps/ios/ADE.xcodeproj/project.pbxprojis excluded by!**/*.xcodeproj/project.pbxprojdocs/features/sync-and-multi-device/README.mdis excluded by!docs/**docs/features/sync-and-multi-device/ios-companion.mdis excluded by!docs/**docs/features/sync-and-multi-device/remote-commands.mdis excluded by!docs/**
📒 Files selected for processing (18)
apps/ade-cli/src/bootstrap.tsapps/ade-cli/src/cli.tsapps/ade-cli/src/services/sync/syncHostService.tsapps/desktop/src/main/services/adeActions/registry.tsapps/desktop/src/main/services/ai/tools/ctoOperatorTools.tsapps/desktop/src/main/services/chat/agentChatService.tsapps/desktop/src/main/services/cto/ctoMemoryService.test.tsapps/desktop/src/main/services/cto/ctoMemoryService.tsapps/desktop/src/main/services/cto/ctoStateService.tsapps/desktop/src/main/services/cto/linearLaneCardService.test.tsapps/desktop/src/preload/preload.tsapps/desktop/src/shared/types/cto.tsapps/desktop/src/shared/types/sync.tsapps/ios/ADE/Models/RemoteModels.swiftapps/ios/ADE/Services/SyncService.swiftapps/ios/ADE/Views/Cto/CtoRootScreen.swiftapps/ios/ADE/Views/Cto/CtoSetup.swiftapps/ios/ADETests/ADETests.swift
💤 Files with no reviewable changes (1)
- apps/desktop/src/main/services/cto/linearLaneCardService.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- apps/ade-cli/src/services/sync/syncHostService.ts
- apps/ade-cli/src/cli.ts
- apps/desktop/src/main/services/cto/ctoMemoryService.ts
- apps/ade-cli/src/bootstrap.ts
- apps/desktop/src/main/services/ai/tools/ctoOperatorTools.ts
- apps/desktop/src/main/services/cto/ctoStateService.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ff17699083
ℹ️ 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".
| await updateSession({ | ||
| sessionId: managed.session.id, | ||
| modelId: desiredModelId, | ||
| reasoningEffort: managed.session.reasoningEffort ?? null, | ||
| }); |
There was a problem hiding this comment.
Apply stored reasoning when reconciling CTO model
When the CTO model preferences are changed while a persistent CTO session already exists but is not the live renderer session (for example after a reload or from the iOS/settings path), this reconciliation path is what applies the saved preference on the next ensureSession. It passes the old managed.session.reasoningEffort into updateSession, and the whole block only runs when the model id differs, so reasoning-only preference changes are ignored and model+reasoning changes can start the new model with the stale tier.
Useful? React with 👍 / 👎.
…ct, reconcile reasoning - searchMemory scans durable facts first (MEMORY.md → thread-state → archive) before daily journal lines, so archived facts can't be starved out of the result budget by high-volume journals (Greptile P1). - updateMemory (IPC + action domain) requires an explicit string; a missing field can no longer blank MEMORY.md, and a deliberate clearing rewrite archives the replaced content (shared archiveMemoryContent helper, also used by the eviction path) (CodeRabbit Major). - ensureIdentitySession reconciliation honors identity reasoningEffort too: reasoning-only preference changes move the ensured session instead of resurrecting the stale tier (Codex P2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2709b58351
ℹ️ 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".
| if (rows.length < limit) scan("thread-state.md", null, readThreadState()); | ||
| if (rows.length < limit) scan("memory-archive.md", null, readFileOrEmpty(memoryArchivePath)); |
There was a problem hiding this comment.
Prioritize archived facts before thread-state matches
When MEMORY.md has evicted durable facts into memory-archive.md, a broad query can still lose those facts because thread-state.md is scanned before the archive and the scan stops once the default limit is filled. In a session whose thread summary has 20 matching lines, searchMemory() returns no archived durable facts even though the eviction path tells callers they remain searchable; scan the archive before transient thread/daily state or reserve budget for it.
Useful? React with 👍 / 👎.
Durable facts (current + archived) take the search budget before the rolling thread summary and daily journals, closing the last lookup-starvation edge case (Codex P2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| updateMemory: async (args: CtoUpdateMemoryArgs): Promise<CtoMemorySnapshot> => | ||
| callProjectRuntimeActionOr("cto_memory", "updateMemory", { args }, () => | ||
| ipcRenderer.invoke(IPC.ctoUpdateMemory, args), | ||
| ), | ||
| ensureAgentSession: async ( | ||
| args: CtoEnsureAgentSessionArgs, | ||
| ): Promise<AgentChatSession> => | ||
| callProjectRuntimeActionOr( | ||
| "chat", | ||
| "ensureAgentIdentitySession", | ||
| { args }, | ||
| () => ipcRenderer.invoke(IPC.ctoEnsureAgentSession, args), | ||
| ), | ||
| getBudgetSnapshot: async ( | ||
| args: CtoGetBudgetSnapshotArgs = {}, | ||
| ): Promise<AgentBudgetSnapshot> => | ||
| callProjectRuntimeActionOr( | ||
| "worker_agent", | ||
| "getBudgetSnapshot", | ||
| { args }, | ||
| () => ipcRenderer.invoke(IPC.ctoGetBudgetSnapshot, args), | ||
| ), | ||
| triggerAgentWakeup: async ( | ||
| args: CtoTriggerAgentWakeupArgs, | ||
| ): Promise<CtoTriggerAgentWakeupResult> => | ||
| callProjectRuntimeActionOr( | ||
| "worker_agent", | ||
| "triggerWakeup", | ||
| { args }, | ||
| () => ipcRenderer.invoke(IPC.ctoTriggerAgentWakeup, args), | ||
| ), | ||
| listAgentRuns: async ( | ||
| args: CtoListAgentRunsArgs = {}, | ||
| ): Promise<WorkerAgentRun[]> => | ||
| callProjectRuntimeActionOr( | ||
| "worker_agent", | ||
| "listAgentRuns", | ||
| { args }, | ||
| () => ipcRenderer.invoke(IPC.ctoListAgentRuns, args), | ||
| ), | ||
| listAgentSessionLogs: async ( | ||
| args: CtoListAgentSessionLogsArgs, | ||
| ): Promise<AgentSessionLogEntry[]> => | ||
| callProjectRuntimeActionOr( | ||
| "worker_agent", | ||
| "listSessionLogs", | ||
| { argsList: [args.agentId, args.limit ?? 40] }, | ||
| () => ipcRenderer.invoke(IPC.ctoListAgentSessionLogs, args), | ||
| searchMemory: async (args: CtoSearchMemoryArgs): Promise<CtoSearchMemoryResult> => | ||
| callProjectRuntimeActionOr("cto_memory", "searchMemory", { args }, () => | ||
| ipcRenderer.invoke(IPC.ctoSearchMemory, args), |
There was a problem hiding this comment.
Memory payload wrapped
callProjectRuntimeActionOr sends its request fields as the run_ade_action payload, so passing { args } invokes cto_memory.updateMemory with { args: { memory } } instead of { memory }. The registry rejects saves with updateMemory requires a string memory field, and searchMemory searches an empty query for bound runtimes. Pass the memory/search fields directly in args.
Artifacts
Repro: focused Vitest test for wrapped CTO memory payloads
- Contains supporting evidence from the run (text/typescript; charset=utf-8).
Repro: verbose Vitest output showing wrapped payloads, rejected update, and empty-query search
- Keeps the command output available without making the summary code-heavy.
Ran code and verified through T-Rex
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/preload/preload.ts
Line: 8221-8227
Comment:
**Memory payload wrapped**
`callProjectRuntimeActionOr` sends its request fields as the `run_ade_action` payload, so passing `{ args }` invokes `cto_memory.updateMemory` with `{ args: { memory } }` instead of `{ memory }`. The registry rejects saves with `updateMemory requires a string memory field`, and `searchMemory` searches an empty query for bound runtimes. Pass the memory/search fields directly in `args`.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
False positive — the payload is not wrapped in the real pipeline. callProjectRuntimeActionOr({ args }) puts the fields on request.args; the runtime bridge forwards the request untouched (runtimeBridge.ts localRuntimeCallAction), the connection pools send arguments: { domain, action, args: request.args } (localRuntimeConnectionPool.ts:995), and run_ade_action unwraps with safeObject(toolArgs.args) and invokes the domain method with that object directly (adeRpcServer.ts:3203-3206). So cto_memory.updateMemory receives { memory }, not { args: { memory } } — the same envelope project_secret.set and ai.getStatus have used in production. The repro harness appears to have invoked the domain method with the whole request envelope rather than going through the dispatcher.
There was a problem hiding this comment.
You're right, and I've verified the pipeline you described. The { args } wrapping in callProjectRuntimeActionOr is the established convention across the entire codebase — the third parameter becomes the full run_ade_action request body, and adeRpcServer.ts unwraps it at safeObject(toolArgs.args) before dispatching to the domain method. The T-Rex repro called the domain registry method directly rather than going through the run_ade_action dispatcher, so it saw { args: { memory } } instead of the correctly-unwrapped { memory }. That's a test harness artifact, not a real bug.
Withdrawing this comment. Sorry for the noise.
What this does
Rebuilds the CTO tab around a single long-living agent thread with a smart, provider-agnostic memory system, and removes the legacy workers/hiring and Linear-workflow subsystems entirely.
Smart memory (files as truth, under
.ade/cto/)MEMORY.md— curated durable facts, always injected (injection capped; disk never truncated), editable in Settings, written by the CTO via newsaveMemory/searchMemory/readMemoryoperator tools.thread-state.md— rolling thread summary, flushed deterministically before compaction and before any model/provider switch (async LLM upgrade never blocks).HH:MM — intent → outcome), no LLM.Model switching never breaks the thread
modelPreferencesand the live session stay in sync both directions; foreign-lane CTO sessions rebind instead of silently orphaning the transcript; deadChatModelSwitchPolicyplumbing removed.Legacy removed completely (code, tests, docs)
ade cto/ade flow/ade linear workflows|sync|ingressCLI + TUI surfaces.ade linearissue bridge.UI
braintab icon (matches desktop), inline single-thread tab, one-card setup, trimmed settings with a Memory section via newcto.getMemorysync command.Validation
xcodebuildBUILD SUCCEEDED; /quality dual-review (0 Blocker/High) and /test consolidation both run.🤖 Generated with Claude Code
Summary by CodeRabbit
Greptile Summary
This PR rebuilds the CTO experience around one persistent agent thread with durable memory. The main changes are:
.ade/cto/memory files for durable facts, thread state, and daily turn logs.Confidence Score: 4/5
Mostly safe to merge after fixing the bound-runtime memory bridge bug.
The core memory service and chat lifecycle wiring are coherent, and the earlier memory eviction/search issues are addressed. Confidence is limited by one contained bug where desktop memory saves and searches send the wrong payload shape through runtime bindings.
apps/desktop/src/preload/preload.ts
What T-Rex did
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant User participant Desktop as Desktop CTO UI participant Preload as preload.cto bridge participant Runtime as Project runtime actions participant Memory as ctoMemoryService participant Chat as CTO agent thread participant iOS as iOS Sync client User->>Desktop: Edit/read CTO settings Desktop->>Preload: getMemory/updateMemory/searchMemory Preload->>Runtime: cto_memory action when bound Runtime->>Memory: getSnapshot/writeMemory/searchMemory Memory-->>Runtime: snapshot/search rows Runtime-->>Preload: result Preload-->>Desktop: memory state Chat->>Memory: writeThreadState before compaction/model switch Chat->>Memory: appendTurnJournal after completed turn iOS->>Runtime: cto.getMemory Runtime->>Memory: getSnapshot Memory-->>iOS: CtoMemory snapshot%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant User participant Desktop as Desktop CTO UI participant Preload as preload.cto bridge participant Runtime as Project runtime actions participant Memory as ctoMemoryService participant Chat as CTO agent thread participant iOS as iOS Sync client User->>Desktop: Edit/read CTO settings Desktop->>Preload: getMemory/updateMemory/searchMemory Preload->>Runtime: cto_memory action when bound Runtime->>Memory: getSnapshot/writeMemory/searchMemory Memory-->>Runtime: snapshot/search rows Runtime-->>Preload: result Preload-->>Desktop: memory state Chat->>Memory: writeThreadState before compaction/model switch Chat->>Memory: appendTurnJournal after completed turn iOS->>Runtime: cto.getMemory Runtime->>Memory: getSnapshot Memory-->>iOS: CtoMemory snapshotComments Outside Diff (1)
apps/desktop/src/main/services/chat/agentChatService.ts, line 7643-7670 (link)ctoMemoryService.buildMemoryContextSections()is not used when rebuildingpendingReconstructionContext, so facts saved throughsaveMemoryor Settings are persisted but not included after session start, compaction, or provider reset. The only CTO-specific context added here is identity, state reconstruction, continuity summary, and transcript tail; durableMEMORY.mdis omitted unless the model explicitly callsreadMemory.Prompt To Fix With AI
Prompt To Fix All With AI
Reviews (6): Last reviewed commit: "ship: search archive ahead of transient ..." | Re-trigger Greptile