Skip to content

feat: copy legacy OpenAdapt recording system into openadapt-capture#9

Merged
abrichr merged 4 commits intomainfrom
fix/recording-performance
Feb 17, 2026
Merged

feat: copy legacy OpenAdapt recording system into openadapt-capture#9
abrichr merged 4 commits intomainfrom
fix/recording-performance

Conversation

@abrichr
Copy link
Member

@abrichr abrichr commented Feb 16, 2026

Summary

  • Full legacy recording migration: Replace vibe-coded recording internals with proven legacy OpenAdapt code (multi-process writers, action-gated video, SQLAlchemy storage, stop sequences, SIGINT handling)
  • New SQLAlchemy database layer: Per-capture recording.db with models for Recording, ActionEvent, Screenshot, WindowEvent, PerformanceStat, MemoryStat
  • Bug fixes: Reset stop_sequence_detected on re-entry, session leak in CaptureSession.load(), mouse_pressed=None handling, disabled event filtering
  • New Action properties: dx, dy, button for scroll/drag/click events
  • Performance tests: 6 integration tests with pynput synthetic input (Windows-only)
  • Updated docs: README and CLAUDE.md reflect new architecture

New modules (copied from legacy, import paths adapted)

Module Purpose
db/models.py SQLAlchemy ORM models
db/crud.py Batch insert functions
extensions/synchronized_queue.py Multiprocessing queue wrapper
utils.py Timestamps, screenshots, monitor dims
window/ Platform-specific active window capture
plotting.py Performance stat visualization

Test plan

  • 118 unit/integration tests pass (macOS)
  • 6 performance tests properly skip on macOS (designed for Windows)
  • Test full recording pipeline on Windows VM
  • Verify capture share send works end-to-end

Generated with Claude Code

@abrichr abrichr force-pushed the fix/recording-performance branch 2 times, most recently from b6f5a4d to f9f6a46 Compare February 16, 2026 21:53
- Action-gated video capture: only encode frames when actions occur
  (~1-5 fps) instead of every screenshot (24fps). This is the core
  reason legacy OpenAdapt was smooth — not just separate processes.
  Matches legacy RECORD_FULL_VIDEO=False default behavior.
- Video encoding in separate multiprocessing.Process (avoids GIL)
- Screenshots via mss (2-4x faster than PIL.ImageGrab on Windows)
- SIGINT ignored in worker process (main handles Ctrl+C)
- Non-daemon process ensures video finalization on shutdown
- First frame forced as key frame for seekability
- Fix wormhole FileNotFoundError on Windows (searches Scripts/ dir)

Legacy patterns matched:
- prev_screen_event buffering → _prev_screen_frame
- prev_saved_screen_timestamp dedup → _prev_saved_screen_timestamp
- RECORD_FULL_VIDEO option → record_full_video parameter
- SIG_IGN in worker processes
- mss with CAPTUREBLT=0 on Windows

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@abrichr abrichr force-pushed the fix/recording-performance branch from f9f6a46 to f251b2b Compare February 16, 2026 21:58
Replace vibe-coded recording internals with proven legacy OpenAdapt code,
adapted only for per-capture databases and import paths.

New modules (copied from legacy):
- db/models.py: SQLAlchemy models (Recording, ActionEvent, Screenshot,
  WindowEvent, PerformanceStat, MemoryStat)
- db/crud.py: batch insert functions, post_process_events
- extensions/synchronized_queue.py: multiprocessing queue wrapper
- utils.py: timestamps, screenshots, monitor dims
- window/: platform-specific active window capture
- plotting.py: performance stat visualization

Updated modules:
- recorder.py: full legacy record() with multi-process writers,
  action-gated video, stop sequences, SIGINT handling
- capture.py: reads from SQLAlchemy DB, fixes session leak,
  mouse_pressed=None handling, disabled event filtering,
  adds dx/dy/button properties to Action
- config.py: all legacy recording config values
- video.py: legacy functional API wrappers
- cli.py: wired to new recorder
- pyproject.toml: added sqlalchemy, loguru, psutil, tqdm deps

Bug fixes:
- Reset stop_sequence_detected on re-entry (Recorder reuse)
- Close session on error in CaptureSession.load()
- Skip click events with mouse_pressed=None
- Filter disabled events in raw_events()

Tests: 118 passed + 6 performance tests (Windows-only)
Docs: updated README.md and CLAUDE.md to match new architecture

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@abrichr abrichr changed the title fix: improve recording performance and wormhole sharing feat: copy legacy OpenAdapt recording system into openadapt-capture Feb 16, 2026
abrichr and others added 2 commits February 16, 2026 18:53
- Wrap Recorder import in try/except in __init__.py and test files
- Skip Recorder tests when pynput unavailable (no display server)
- Fix all ruff I001 import sorting violations
- Remove unused imports and variables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Browser bridge tests hang indefinitely on headless CI due to async
websocket fixtures. Add pytest-timeout and a 10-minute job timeout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@abrichr abrichr merged commit d359011 into main Feb 17, 2026
4 checks passed
@abrichr abrichr deleted the fix/recording-performance branch February 17, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant