Architecture: decompose Rust ACP and DB god-modules into bounded domain modules
Problem
The Rust backend contains several giant files that act as convenience containers for multiple concerns instead of mapping cleanly to product domains.
The two biggest examples are:
packages/desktop/src-tauri/src/acp/client/cc_sdk_client.rs (~6717 lines)
packages/desktop/src-tauri/src/db/repository.rs (~3330 lines)
These files are evidence that important architectural seams are still implicit.
Why this is a deep problem
Large files are not automatically bad.
They become a smell when a single module mixes responsibilities that should evolve independently.
That is the case here:
- permissions evolve for different reasons than streaming
- hooks evolve for different reasons than question handling
- repositories for projects/settings/session metadata/skills/sql studio evolve for different reasons
When those concerns share a module:
- unrelated changes collide
- tests become coarse-grained
- ownership becomes fuzzy
- mental load spikes
- it becomes hard to define stable internal APIs
Evidence in the current codebase
cc_sdk_client.rs
This file contains, among other things:
- pending question state
- tool call ID tracking
- approval callback tracking
- permission handler implementation
- hook callback implementation
- main
ClaudeCcSdkClient implementation
- streaming bridge logic
AgentClient implementation
- large inline test section
Representative markers:
struct PendingQuestionState
struct ToolCallIdTracker
impl cc_sdk::CanUseTool for AcepePermissionHandler
struct AcepePermissionRequestHook
impl cc_sdk::HookCallback for AcepePermissionRequestHook
impl ClaudeCcSdkClient
async fn run_streaming_bridge(...)
impl AgentClient for ClaudeCcSdkClient
db/repository.rs
This file contains multiple repositories for different domains:
ProjectRepository
SettingsRepository
AppSettingsRepository
SessionReviewStateRepository
SessionProjectionSnapshotRepository
SessionTranscriptSnapshotRepository
SessionThreadSnapshotRepository
SessionJournalEventRepository
SessionMetadataRepository
SkillsRepository
DatabaseResetRepository
SqlStudioRepository
This is not one repository. It is a repository index disguised as a module.
Current shape
cc_sdk_client.rs
|
+--> permissions
+--> hooks
+--> question handling
+--> tool ID tracking
+--> stream bridging
+--> client lifecycle
+--> tests
repository.rs
|
+--> projects
+--> settings
+--> app settings
+--> review state
+--> snapshots
+--> journal events
+--> session metadata
+--> skills
+--> database reset
+--> SQL studio
GOD architecture target
The cleanest backend architecture should mirror stable product concepts.
acp/
session_lifecycle/
streaming/
permissions/
interactions/
tools/
providers/
db/
projects/
settings/
session_metadata/
session_journal/
snapshots/
skills/
sql_studio/
And the client-side ACP internals should look more like:
ClaudeCcSdkClient
|
+--> session runtime coordinator
+--> streaming adapter
+--> permission bridge
+--> interaction bridge
+--> projection/event dispatcher
where each box is a real module with a narrow contract.
What should exist after this work
1. ACP modules with explicit domain ownership
Suggested boundaries:
acp/client/claude/session_runtime.rs
acp/client/claude/streaming_bridge.rs
acp/client/claude/permission_bridge.rs
acp/client/claude/question_bridge.rs
acp/client/claude/tool_tracking.rs
2. Repository modules by aggregate/domain
Suggested boundaries:
db/repositories/projects.rs
db/repositories/settings.rs
db/repositories/session_metadata.rs
db/repositories/session_journal.rs
db/repositories/skills.rs
db/repositories/sql_studio.rs
3. Stable internal interfaces
Examples:
- streaming bridge emits canonical updates/events
- permission bridge owns permission-specific state
- question bridge owns question binding logic
- repositories expose domain-oriented methods without a catch-all mega module
Suggested implementation direction
- Split
cc_sdk_client.rs by responsibility, not by arbitrary line ranges.
- Move tests next to the extracted modules or to focused integration tests.
- Split
repository.rs into domain repositories with a shared support module only where necessary.
- Introduce module-level contracts that make dependencies directional and explicit.
- Keep thin facade modules if external call sites need a transitional import path.
Non-goals
- file splitting that keeps all hidden coupling intact
- moving code without clarifying API ownership
- creating a deep folder tree without meaningful boundaries
Acceptance criteria
cc_sdk_client.rs no longer owns permissions, hooks, streaming, tracking, and lifecycle in one file.
db/repository.rs is replaced by domain-scoped repository modules or reduced to a small index/facade.
- Each extracted module has a clear responsibility and corresponding tests.
- It becomes possible to work on permissions/streaming/repositories with much lower unrelated context load.
Why this matters strategically
Acepe's backend is becoming the control plane for agent execution, reviewability, and durable workflows. That requires backend modules that are structurally aligned with the product, not just organized around what happened to be convenient during growth.
Architecture: decompose Rust ACP and DB god-modules into bounded domain modules
Problem
The Rust backend contains several giant files that act as convenience containers for multiple concerns instead of mapping cleanly to product domains.
The two biggest examples are:
packages/desktop/src-tauri/src/acp/client/cc_sdk_client.rs(~6717 lines)packages/desktop/src-tauri/src/db/repository.rs(~3330 lines)These files are evidence that important architectural seams are still implicit.
Why this is a deep problem
Large files are not automatically bad.
They become a smell when a single module mixes responsibilities that should evolve independently.
That is the case here:
When those concerns share a module:
Evidence in the current codebase
cc_sdk_client.rsThis file contains, among other things:
ClaudeCcSdkClientimplementationAgentClientimplementationRepresentative markers:
struct PendingQuestionStatestruct ToolCallIdTrackerimpl cc_sdk::CanUseTool for AcepePermissionHandlerstruct AcepePermissionRequestHookimpl cc_sdk::HookCallback for AcepePermissionRequestHookimpl ClaudeCcSdkClientasync fn run_streaming_bridge(...)impl AgentClient for ClaudeCcSdkClientdb/repository.rsThis file contains multiple repositories for different domains:
ProjectRepositorySettingsRepositoryAppSettingsRepositorySessionReviewStateRepositorySessionProjectionSnapshotRepositorySessionTranscriptSnapshotRepositorySessionThreadSnapshotRepositorySessionJournalEventRepositorySessionMetadataRepositorySkillsRepositoryDatabaseResetRepositorySqlStudioRepositoryThis is not one repository. It is a repository index disguised as a module.
Current shape
GOD architecture target
The cleanest backend architecture should mirror stable product concepts.
And the client-side ACP internals should look more like:
where each box is a real module with a narrow contract.
What should exist after this work
1. ACP modules with explicit domain ownership
Suggested boundaries:
acp/client/claude/session_runtime.rsacp/client/claude/streaming_bridge.rsacp/client/claude/permission_bridge.rsacp/client/claude/question_bridge.rsacp/client/claude/tool_tracking.rs2. Repository modules by aggregate/domain
Suggested boundaries:
db/repositories/projects.rsdb/repositories/settings.rsdb/repositories/session_metadata.rsdb/repositories/session_journal.rsdb/repositories/skills.rsdb/repositories/sql_studio.rs3. Stable internal interfaces
Examples:
Suggested implementation direction
cc_sdk_client.rsby responsibility, not by arbitrary line ranges.repository.rsinto domain repositories with a shared support module only where necessary.Non-goals
Acceptance criteria
cc_sdk_client.rsno longer owns permissions, hooks, streaming, tracking, and lifecycle in one file.db/repository.rsis replaced by domain-scoped repository modules or reduced to a small index/facade.Why this matters strategically
Acepe's backend is becoming the control plane for agent execution, reviewability, and durable workflows. That requires backend modules that are structurally aligned with the product, not just organized around what happened to be convenient during growth.