Files
cowork-local/docs/architecture/ADR-001-layered-architecture.md
T
f9f6bc01fd
CI / test (push) Canceled after 0s
Feature/delta team/epic r04 (#7)
## Summary

epic r04 - begin refactor

## Change Type

- [x] Cowork feature
- [ ] Bug fix
- [ ] Core AI contribution
- [ ] Test / hardening
- [ ] Performance
- [ ] Documentation

## Related Work

Cowork Task:

Core Repo: http://34.143.229.138/gitea-admin/fsg-ai-core-assets

Core AI Issue:

Core Task:

Related PR:

## Scope

What is intentionally included?

What is intentionally NOT included?

## Validation

- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual verification
- [ ] Regression check

Commands / evidence:

## Security Impact

Permission / credential / network / customer data impact:

## Compatibility

- [ ] No breaking change
- [ ] Breaking change documented

## Reviewer Notes

Anything Cowork reviewers should pay attention to.

---------

Co-authored-by: Anh Tran Nguyen Minh <anhtnm1@fpt.com>
Co-authored-by: Huong Le Thi Thien <huongltt35@fpt.com>
Co-authored-by: Nam Pham Dinh Thanh <nampdt@fpt.com>
Co-authored-by: Vu Dam Tuan <vudt15@fpt.com>
Co-authored-by: Hiep Ha Van <hiephv3@fpt.com>
Co-authored-by: Lam Hoang Van <lamhv7@fpt.com>
Reviewed-on: #7
Co-authored-by: Duy Le Huu <duylh19@fpt.com>
2026-08-31 05:15:13 +00:00

7.0 KiB

ADR-001: 4-Tier Clean Architecture for Desktop Local Application

  • Status: ACCEPTED / ENFORCED
  • Date: 2026-08-21
  • Deciders: Team Duy (Tech Lead & AI Runtime), Team Nam (Governance & Automation), Team Hoa (Workspace & Scheduling)
  • Target Project: Cowork Local (Cowork-Local BamBOO)

1. Context and Problem Statement

Cowork Local is a desktop application written in Python using PySide6 (Qt) and designed for local-first execution. Historically, the codebase suffered from architectural coupling across layers:

  1. God-Widget Problem: Monolithic UI widgets (e.g., ui/chat_panel.py >1,800 LOC, ui/co4e_tab.py >1,400 LOC) mixed UI rendering, network I/O, business rules, filesystem operations, and background worker lifecycle.
  2. Untestable Business Logic: Core algorithms (model routing, conversation turn management, schedule calculation) were tightly coupled to PySide6 widgets or QTimer, making unit testing in headless CI environments impossible without a graphical display server.
  3. Circular Dependencies & Global State Leaks: Uncontrolled module imports (model_pricing.py ↔ usage_tracker.py, agent_security.py ↔ agent_security_alert.py) and mutable global state (state.py::AppContext.active_project_id) caused race conditions in background task runs.

2. Decision: 4-Tier Clean Architecture

We enforce a strict 4-Tier Clean Architecture based on the Dependency Inversion Principle:

┌─────────────────────────────────────────────────────────────┐
│                      PRESENTATION                           │
│  (PySide6 Widgets, Dialogs, Qt Signals/Slots, View Models)   │
└──────────────────────────────┬──────────────────────────────┘
                               │ depends on
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                      APPLICATION                            │
│  (Use Case Services, Turn Orchestrators, Route Dispatchers) │
│             *** STRICTLY PURE PYTHON (0 Qt) ***             │
└──────────────────────────────┬──────────────────────────────┘
                               │ depends on
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                   DOMAIN & RUNTIME CORE                     │
│  (Entities, Value Objects, Domain Events, Tool Descriptors)  │
│             *** STRICTLY PURE PYTHON (0 Qt) ***             │
└──────────────────────────────▲──────────────────────────────┘
                               │ implemented by
┌──────────────────────────────┴──────────────────────────────┐
│                     INFRASTRUCTURE                          │
│  (LLM Providers, Keyring Secrets, Atomic Persistence, MCP)  │
└─────────────────────────────────────────────────────────────┘

3. Layer Definitions and Responsibilities

Tier 1: Presentation Layer (presentation/)

  • Responsibilities: UI component layout, user event capture, progress display, visual animations, confirmation dialog triggers.
  • Allowed Imports: PySide6.*, application.*, domain.*.
  • Forbidden: Direct database queries, raw LLM API calls, disk writes outside UI cache, executing tool commands directly.
  • Constraints: Every widget file must strictly be under 400 lines of code (LOC).

Tier 2: Application Layer (application/)

  • Responsibilities: Orchestrate single use cases (e.g. ConversationApplicationService, RoutingApplicationService, TaskApplicationService). Convert UI requests into domain requests, coordinate domain services with infrastructure adapters.
  • Allowed Imports: domain.*, infrastructure.* interfaces/contracts, standard Python libraries.
  • Forbidden: PySide6, PyQt5, PyQt6, ui.*, app.*.
  • Nature: 100% Pure Python. Must be executable and testable in headless CI environments without a display driver.

Tier 3: Domain Layer (domain/)

  • Responsibilities: Core domain models, frozen DTO snapshots (ConversationExecutionRequest), typed event streams (AgentEvent), descriptors (ToolDescriptor, ProviderDescriptor), deterministic calculation algorithms (ScheduleCalculator).
  • Allowed Imports: Standard Python library only (dataclasses, typing, enum, datetime, pathlib, abc).
  • Forbidden: PySide6, PyQt*, requests, sqlalchemy, filesystem mutations, OS network calls.
  • Nature: Completely isolated and zero-dependency core.

Tier 4: Infrastructure Layer (infrastructure/)

  • Responsibilities: Adapters for external systems (OpenAI/Anthropic/Ollama/FPT providers, OS Keyring via SecretStore, AtomicJsonFile persistence, MCP child processes, filesystem tools).
  • Allowed Imports: Third-party SDKs, OS libraries, domain.*.
  • Forbidden: presentation.*, PySide6.QtWidgets.

4. Architectural Rules and Non-Negotiable Invariants

  1. Zero Qt in Business Logic:
    • domain/ and application/ must never import PySide6 or PyQt*.
    • Verified via AST parser script scripts/check_imports.py.
  2. Immutable Request Snapshots:
    • Turns are initiated using immutable frozen dataclasses (ConversationExecutionRequest) to decouple runtime state from mutable UI state.
  3. Thread Safety and Signal Decoupling:
    • AI generation and tool calls run asynchronously in worker threads.
    • UI updates occur strictly on the Qt main thread by consuming AgentEvent streams through Qt Signal bridges.
  4. Single Responsibility and Modularity:
    • Production files must stay within 400 LOC.
  5. English In-Code Comments:
    • Every modified or created line/block must include concise English comments explaining design decisions and processing logic.

5. Consequences and Compliance

  • Positive:
    • Full testability: Unit tests run in milliseconds without GUI or network mocks.
    • Zero circular dependencies: Clear top-down data flow.
    • Resilience: UI crashes do not corrupt background tasks or files.
  • Verification:
    • Automated CI gate: python scripts/check_imports.py and python scripts/check_loc.py.