아키텍처 개요¶
이 페이지는 CLAUDE.md의 구현 노트를 미러합니다. 서브시스템 변경 시
양쪽 다 업데이트하세요.
프로젝트 레이아웃¶
src/ 레이아웃 — 모든 패키지 코드는 src/cue/에 있습니다.
엔트리 포인트: python -m cue (dev) 또는 run.py (frozen 빌드).
src/cue/
├── main.py # 메뉴바 앱, 핫키, top-level 워커 spawn
├── popup_window.py # customtkinter 팝업 서브프로세스
├── settings_window.py # 설정 서브프로세스 (customtkinter)
├── settings_model.py # 설정 순수 로직 레이어 (stdlib only, unit-testable)
├── recorder.py # ocap 서브프로세스 래퍼 + rotator/evictor/digest 스레드
├── pruner.py # MKV → 키프레임 추출 (GStreamer env 위해 자체 서브프로세스)
├── ocap_launcher.py # 파이프라인 monkey-patch ocap CLI 래퍼
├── digest.py # 5초 디지스트 틱 — Haiku/Gemma 4 over 키프레임 + 이벤트
├── llm.py # DigestBackend Protocol + CloudVisionBackend + LocalVisionBackend
├── llama_server.py # 번들된 llama-server 서브프로세스 라이프사이클
├── local_models.py # 핀된 Gemma 4 매니페스트 + 재개 가능 다운로드
├── frame_select.py # anchor 보호 + dedupe 10프레임 selector
├── image_preprocess.py # 896 px JPEG q75 + EXIF/ICC strip
├── prompts.py # 모든 Claude 프롬프트의 단일 진실 공급원
├── memory.py # Opus가 최근 디지스트로 memory.md 재작성
├── suggest.py # 핫키 경로: Opus + memory + 최근 컨텍스트
├── pii.py # Presidio scrub() + scrub_strict()
├── pii_recognizers.py # Cue 전용 Presidio recognizer
├── privacy.py # PrivacyMonitor + PauseController
├── overlay.py # 빨간 테두리 오버레이 dispatcher
├── store.py # SQLite — sessions, digests, BLOCKED_APPS, backfill_scrub
├── config.py # CONFIG_DIR, get_api_key, streaming_config, privacy_config
├── fs.py # secure_dir / secure_file (POSIX chmod, Windows no-op) + Spotlight opt-out
├── capture.py # mss + Pillow 스크린샷 (cross-platform)
└── platform/
├── __init__.py # facade — `cue.platform`만 import, 직접 import 금지
├── macos.py # rumps tray, CGEventTap, AppleScript, Carbon, AX
├── windows.py # pystray tray, pynput, UIA, SetWinEventHook
├── overlay_macos.py # NSPanel per NSScreen, NSFloatingWindowLevel
└── overlay_windows.py # Tk Toplevel per monitor, WS_EX_LAYERED|TRANSPARENT
프로세스 모델¶
graph TB
subgraph "Cue 메인 프로세스 (메뉴바 / 트레이)"
Main[cue.main]
Hotkey[핫키 리스너<br/>CGEventTap / GlobalHotKeys]
Privacy[PrivacyMonitor + PauseController]
Recorder[recorder.py rotator/evictor/digest 스레드]
end
subgraph "서브프로세스"
Popup[popup_window<br/>customtkinter]
Settings[settings_window<br/>customtkinter]
Ocap[ocap-macos / ocap-windows<br/>GStreamer 파이프라인]
Pruner[pruner worker<br/>chunk별 MKV reader]
LlamaServer[llama-server<br/>localhost only, opt-in]
end
Main --> Hotkey
Main --> Privacy
Main --> Recorder
Hotkey -- "Shift+Space" --> Popup
Main -- "Preferences..." --> Settings
Recorder -- "spawn / SIGKILL" --> Ocap
Recorder -- "chunk별" --> Pruner
Recorder -- "5초 틱 → cue.llm" --> LlamaServer
메뉴바 프로세스가 핫키 리스너, 프라이버시 모니터, 레코더 스레드, 팝업/설정 서브프로세스 관리를 소유. 무겁거나 위험한 작업은 서브프로세스로 — ocap (GStreamer), pruner (MKV decode + dhash), llama-server (멀티모달 추론). 메뉴바는 작고 빠름 — Cue 워커에서 GUI 런 루프가 절대 막히지 않음.
데이터 디렉토리¶
단일 진실 공급원: cue.config.CONFIG_DIR. 다른 곳에 플랫폼 경로
정의 금지 — CONFIG_DIR import.
| 플랫폼 | 경로 |
|---|---|
| macOS | ~/Library/Application Support/Cue/ (data) + ~/Library/Caches/Cue/ (스트리밍, GStreamer 친화적) |
| Windows | %LOCALAPPDATA%\Cue\ |
파일별 표는 디스크에 저장되는 데이터 참고.
공유 모듈¶
두 플랫폼이 sys.platform 가드 없이 import하는 모듈:
| 모듈 | 역할 |
|---|---|
cue.capture |
mss + Pillow 스크린 캡처 (thread-safe). |
cue.fs |
secure_dir() / secure_file() 권한 + mark_not_indexed() (Spotlight / Search opt-out). |
cue.config |
CONFIG_DIR, get_api_key, streaming_enabled, streaming_config, privacy_config. |
cue.recorder |
start() / stop() / is_running() / snapshot_context() / recent_mcap_paths() + stop_for_pause / resume_after_pause. |
cue.pruner |
process_chunk() (자체 서브프로세스) + recent_keyframes() + evict_older_than() / evict_newer_than(). python -m cue.pruner 워커로도 실행. |
cue.digest |
핫키 경로용 read_digest() + 프라이버시 purge cascade용 evict_entries_newer_than(cutoff_ns). |
cue.privacy |
start() / stop() / toggle_manual() / is_paused() / reasons() / reason_label() / reload_browser_auth(). |
cue.overlay |
cue.platform.overlay_*로 dispatch하는 show() / hide(). |
cue.settings_model |
설정 순수 로직 레이어. stdlib-only, unit-testable. |
cue.settings_window |
설정 서브프로세스 엔트리 포인트. |
크로스플랫폼 원칙¶
Cue는 macOS 그리고 Windows 양쪽에서 동작. 모든 기능 / 수정 / 동작 변경은 두 플랫폼에 적용. PR 체크리스트는 크로스 플랫폼 규칙 참고.