콘텐츠로 이동

스트리밍 레코더

이 페이지는 CLAUDE.md의 구현 노트를 미러합니다. 서브시스템 변경 시 양쪽 다 업데이트하세요.

Enable Streaming이 켜지면 Cue는 백그라운드 비디오 캡처 파이프라인을 실행하고 몇 초마다 디지스트 모델에 입력합니다. 레코더는 외부 CLI (vendor/ocap-{macos,windows} 아래에 vendoring)로 ~10 fps에서 실행되는 서브프로세스입니다. ocap은 GStreamer + 하드웨어 H.265 인코딩(Apple Silicon / NVIDIA에서 거의 zero CPU)을 사용하고 다음을 씁니다:

  • <스트리밍 루트>/stream/chunk_<ts>.mkv — 비디오.
  • <스트리밍 루트>/stream/chunk_<ts>.mcap — 구조화된 키보드 / 마우스 / 윈도우 / 화면 이벤트.

파이프라인

sequenceDiagram
    participant Cue as Cue (parent)
    participant Rotator
    participant Ocap as ocap subprocess
    participant Pruner as pruner worker
    participant Evictor
    participant Digest as digest worker

    Cue->>Rotator: start()
    loop chunk_secs마다 (기본 30초)
        Rotator->>Ocap: spawn (ocap-macos / ocap-windows CLI)
        Ocap-->>Rotator: chunk_<ts>.mkv + chunk_<ts>.mcap
        Rotator->>Pruner: 닫힌 chunk에 대해 spawn
        Pruner->>Pruner: dhash + 이벤트 인지 키프레임 추출
        Pruner-->>Cue: keyframe_<ts>.jpg 파일들
    end
    loop 60초마다
        Evictor->>Evictor: window_secs (기본 15분) 밖 chunks/keyframes 제거
    end
    loop 디지스트 틱(5초)마다
        Digest->>Digest: 최근 MCAP 이벤트 + 키프레임 읽기
        Digest->>Digest: 최대 10 프레임 선택 + 이벤트 scrub
        Digest->>Digest: cue.llm.summarize_digest_with_policy 호출
        Digest->>Cue: digest.md 작성 + digests row 삽입
    end

ocap 위 Cue 스레드

스레드 역할
rotator streaming.chunk_secs (기본 30초) 마다 현재 ocap을 멈추고 새 chunk 시작. ocap이 예기치 않게 죽으면도. 회전 후 chunk별 pruner 서브프로세스 spawn.
pruner worker 닫힌 MKV를 owa.gstreamer.gst.mkv_reader로 읽고, 각 프레임 dhash. 이전 키프레임과 큰 차이 또는 실제 입력 이벤트(키 / 클릭 / 윈도우 변경)에 후행하는 프레임만 보존. 키프레임 디렉토리에 작은 JPEG 작성. GStreamer env가 부모로 누설되지 않도록 자체 서브프로세스 spawn.
evictor 60초마다 종료 시간이 streaming.window_secs (기본 15분)보다 오래된 chunk 파일 삭제. 같은 cutoff가 키프레임 JPEG에도 적용.
digest 최근 MCAP 메시지 읽기, 텍스트 PII scrub, 설정된 백엔드로 전송, digest.md 작성. 디지스트 파이프라인 참고.

ocap이 서브프로세스인 이유

GStreamer + 하드웨어 H.265 인코딩은 Cue 자체 Python과 in-process로 공존하기 어려움 — PyGObject가 GLib, GStreamer.framework dylib들을 끌어와 Cue 프로세스 상태와 충돌. 서브프로세스로 ocap을 띄우면 이를 회피하고 프라이버시 일시정지의 SIGKILL을 위한 깔끔한 프로세스 경계 제공.

서브프로세스는 ocap CLI (owa.ocap_macos.cli 또는 owa.ocap_windows.cli)로 실행 — Cue 자체는 GStreamer 레코더 모듈을 import하지 않음.

스냅샷 컨텍스트

핫키 경로는 recorder.snapshot_context(recent_secs, max_events)digest.md + 가장 최근 MCAP 이벤트 + 최대 3개 pruner 키프레임을 읽음. Opus는 핫키 경로에서 핫키 시점 캡처 지연 없이 "누적된 지식"을 받음.

스트리밍 루트 경로 (macOS)

스트림 + 키프레임 디렉토리는 ~/Library/Application Support/Cue/가 아니라 ~/Library/Caches/Cue/ 아래에 있음 — GStreamer filesink location=...이 공백을 견디지 못해서. Windows는 일반적인 %LOCALAPPDATA%\Cue 사용.

Vendoring

레코더는 vendor/ 아래 두 git 서브모듈로 존재:

  • vendor/ocap-macosowa.ocap_macos.recorder 제공. pyproject가 owa-env-desktop==0.6.5에 핀.
  • vendor/ocap-windowsowa.ocap_windows.recorder 제공.

둘 다 vendor/open-world-agents-private에 의존하여 owa-core, owa-msgs, owa-env-desktop, mcap-owa-support, owa-cli 가져옴. Cue 클론 후 첫 install 전에:

git submodule update --init --recursive

서브모듈 / 벤더링 참고.

프라이버시 상호작용

프라이버시 일시정지가 ocap을 즉시 SIGKILL (프라이버시 일시정지 에서 graceful shutdown을 안 쓰는 이유 참고). pruner / evictor / digest 스레드는 계속 실행되지만 새 chunk를 못 찾으니 자연스럽게 파이프라인이 비워짐. 일시정지 해제 시 새 ocap 세션 spawn.

더 보기