Auto-memory is normally stored outside the repo, keyed to the working directory's absolute path, so it doesn't follow a clone to a new machine. This snapshot travels with the repo instead, so Claude has the same project/feedback context when opened from a different machine (e.g. the Windows VM being set up for the extension-reaper-macos port). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
12 KiB
Carried-over session memory
This file is a portable dump of Claude's per-machine auto-memory for this
project (normally stored outside the repo, keyed to the absolute path of the
working directory — so it doesn't survive a clone to a new machine on its
own). This copy is checked into the repo so it travels with git clone/git pull instead of staying stuck on one machine.
Auto-generated 2026-07-22. May drift from live memory over time — treat as a snapshot, not a live sync.
How Paul wants to collaborate (feedback)
Confirm before changes
Always talk through the diagnosis/plan and get explicit confirmation before making code changes — do not implement on the first pass, even for what looks like a clear-cut bug.
- Stated explicitly (2026-07-06): "from here on out, always talk to me before we make changes." A standing rule, not one-off.
- Stating a plan and executing it in the same turn does not count as confirming — waiting for an actual reply is required, especially for open/free-choice sub-decisions (a button label, a variable name, which of several equally-valid options to pick) that come up mid-task.
- If Paul says something like "just do it" for a specific request, that authorizes that one instance, not a standing reversal of the rule.
Bullet-point replies
Explain diagnoses/what's-happening in short, clear bullet points — not paragraph prose.
- Said explicitly during iOS FocusToggleWidget color debugging: "I'm going to need you to start simplifying your discussions... respond to me in clear bullet points about what's actually happening."
- Recurrence: bullets with bold headers still drifted into multi-sentence paragraphs underneath. The failure mode isn't lack of bullets, it's bullets containing paragraph-length reasoning. One short sentence per bullet, no exceptions — split into more, shorter bullets instead of letting one run long.
- Second recurrence: when Paul states the correct technical answer himself, respond with a short confirmation ("yes, correct" + at most one clarifying detail) — don't re-explain it back to him in different words. Treat his own correct restatement as a signal the concept has landed.
ReaLearn is reference-only
plugin-reaper-relearn (vendored helgoboss/helgobox ReaLearn) is for
reading/insight only — never edit, patch, or extend it directly.
- Paul: "the realearn stuff is its own project and we dont mod it at all... if we need to read from it to gain some insight ok other than that no."
- All new proprietary REAPER integration work happens in
extension-reaper-macosinstead. - Useful reference patterns inside ReaLearn:
main/src/domain/targets/*.rstarget-plugin pattern,mouse_target.rsOS-level mouse emulation viaenigo,reaper-high/reaper-medium(reaper-rs) usage — studied, not depended on.
Ongoing project context
extension-reaper-macos / envelope automation pipeline
Paul is building extension-reaper-macos as his own proprietary, owned
compiled REAPER extension — not scoped to one feature.
- Language: C/C++ against the real Cockos SDK directly (Rust/reaper-rs was floated and explicitly dropped: "REAPER's actual native SDK... no wrapper layer, no crate dependency graph").
- Layout:
vendor/reaper-sdk/sdk/(unmodified headers from justinfrankel/reaper-sdk),vendor/reaper-sdk/WDL/(full justinfrankel/WDL checkout, header types only — nothing compiled/linked from it),src/main.cpp(entrypoint, ownsREAPERAPI_IMPLEMENT), one subfolder per module (hello/,tracking/,socket/). - Confirmed working 2026-07-15: bare-minimum skeleton built, installed, loads in REAPER, prints console confirmation.
- Since then: extended to read/write automation items (
D_BASELINEnudge,tracking.cpp), and a UDP socket listener (socket.cpp) wired to the desktop app so fader moves nudge the selected automation item's baseline live.
Origin feature: click an automation item on a REAPER envelope lane to
select it, then move a fader in the desktop app (eventually the tablet
remote) to raise/lower ALL envelope points in that item together — maps to
REAPER's own D_BASELINE property (same as ctrl-drag natively), not
per-point editing.
Design decisions:
- Mouse-emulation (replaying a physical Y-axis drag) was explicitly rejected in favor of calling REAPER's API directly.
- This extension owns its own socket listener rather than going through REAPER's OSC-control-surface config or ReaScript/Action-List-learn.
- Open question, unresolved: does this extension eventually replace the
existing OSC in/out to REAPER (track/preset name, transport, position via
osc_sender.py/osc_receiver.py), or live alongside it for things OSC can't reach? - Also undecided: relative (nudge) vs absolute fader mapping for baseline value.
Cross-platform build (this is the live thread — Windows port in progress):
- macOS:
.dylib,clang++ -dynamiclib -arch arm64viabuild.sh. Needs a real Mac — can't be reliably/legally cross-compiled from another host. Output now goes tobuild/macos/, copied to~/Library/Application Support/REAPER/UserPlugins/. - Windows: needs a
.dll.main.cpp/tracking.cppare portable as-is (pure REAPER SDK C++, andREAPER_PLUGIN_DLL_EXPORTis already_WIN32-aware in the vendored SDK header).socket.cppis the one file that needs a real port — it uses raw POSIX sockets (sys/socket.h/netinet/in.h/unistd.h/fcntl.h,recvfrom/fcntl/close) which don't exist on Windows; needs a Winsock2 path (WSAStartup/WSACleanup,closesocket,ioctlsocketinstead offcntl, linkws2_32). Also need a Windows-side build script (MSVCcl.exe /LDor MinGWg++ -shared) producing a.dll, copied to%APPDATA%\REAPER\UserPlugins\. - Dev environment: Paul is setting up a Windows ARM64 VM (Parallels, Apple Silicon host) rather than full x86 emulation (tried QEMU/UTM full x86 emulation first — extremely slow, no hardware acceleration for a foreign instruction set). ARM64 Windows runs natively/fast on Apple Silicon; x64 compiler + x64 REAPER run inside it via Windows' own built-in x64-on-ARM app emulation, which is fast enough for real dev work. REAPER also ships a native ARM64 Windows build if x64 ends up unnecessary.
- A self-hosted Gitea instance (separate box) was floated for CI: Linux
.sonatively there, Windows.dllviax86_64-w64-mingw32-g++cross-compile from that same Linux box — viable while the extension has no REAPER C++ virtual-class interfaces crossing the plugin boundary (re-check if things likePCM_source/ProjectStateContextget used, where the SDK's MSVC-ABI requirement actually bites).
Hardware CC binding backlog
Backlog for the hw_cc/hw_channel binding system in main.py,
faderwidget.py, focusfaderwidget.py, focustogglewidget.py:
- Assignment collision detection — no validation today for two widgets (faders/toggles/transports/preset_browsers/focus_faders/focus_toggles) being bound to the same hw_cc + hw_channel. Not yet designed — open question is where the check should live (Learn-time vs. preset-wide audit) and what UI signals it.
Raised 2026-07-06 after building JL Cooper touch-sense support (CH15/CH16 same-CC convention) and Focus widget Hardware/Feedback checkboxes — those made binding conflicts more likely without adding detection.
Planned features backlog (2026-06-29, ordered)
- Momentary on Toggle Widget — Mom/Tog mode on ToggleWidget, mirrors TransportWidget
- Add Rows — add new fader/toggle rows to layout at runtime
- Duplicate (Create New Gen ID) — duplicate a widget/row with a fresh generated ID
- Big Title — large display title element
- Enable/Disable Preset Browser Row
- Re-order Rows — drag or button-based row reordering
iOS remote client (companion project, same session lineage)
These entries came out of sessions rooted in this project directory but
concern remote-client-ios / virtual-controller-ios-app. Kept here since
that's where they were captured.
Tablet direction (confirmed)
The WebSocket + vanilla-JS web surface is the permanent direction for performance control — not TouchOSC, not a native app. POC validated the workflow: one-time arrange per preset, auto-switches with preset, instant JS load, works on any device browser.
Stack: PyQt6 app owns all routing/presets/MIDI/OSC; QWebSocketServer on
:8765; HTTP server on :8080 serving /client; vanilla JS client, no
frameworks; layout saved per preset UUID in presets.json under
"tablet_layout". Native app (Android/iOS) explicitly off the table unless
revisited.
iOS FaderWidget architecture (settled, do not revisit)
Rebuilt from scratch using raw touchesBegan/touchesMoved overrides
instead of UISlider or UIScrollView — UISlider needs precise thumb
targeting, UIScrollView's pan gesture recognizer fought a drag gesture
recognizer (touchesCancelled froze the fader after one increment). Raw
touch tracking fires at 120hz with zero latency and works anywhere on the
widget surface.
Key decisions:
- Value mapping:
value = (1 - pt.y / activeHeight) * 127, normalized againstbounds.height. - Dead zones: 90pt top/bottom (
padHeight = 90). - REL mode (default): drag relative to touch start, no value jump. ABS mode: touch position maps directly to value.
- Gradient fill:
CAGradientLayer, transparent black (bottom) to color at 45% alpha (top), grows upward with value. - Haptics:
UIImpactFeedbackGenerator(.medium)on hitting 0 or 127 (edge-detected vialastHapticValue). - Dedup via
lastSentValue. - Gesture fix:
addDragGesturesetscancelsTouchesInView = falseso pan doesn't steal touches;arrangeModeflag guards touch handlers during drag; pinch-to-resize removed for faders.
iOS remote backlog
Next up: review pass on the dest_id system — Paul flagged things to
go over, "kinda works, things to go over."
Shipped: remote_checkbox/dest_spin per widget (own grp_remote frame),
Bonjour discovery (desktop advertises _vcremote._tcp.local. via
zeroconf, iOS browses via NetServiceBrowser), Feedback widget (Channel
Focus-scoped, not the old global one), ToggleWidget off-state now uses
color.darkened(by: 0.6) instead of a hardcoded gray, pinch-to-resize +
grid-snap in arrange mode.
Remaining:
- Bonjour discovery bug — desktop-side confirmed correct (registers, resolves, correct IP, Local Network permission on, same Wi-Fi), but never resolves from a borrowed test iPad — possibly MDM/managed-device or router client isolation. Retest on Paul's own iPad before assuming the code is broken.
- Review pass on dest_id system (see "Next up" above).
- All-edge snap —
snapFramewritten but unused; call sites still usesnapValueon origin only. - Preset save bug — first/last presets not persisting.
- Model all iOS JSON transactions (outer envelope still raw
JSONSerialization). - Model all Python outgoing data — dataclasses in
ws_server.pybroadcasts. - Clean up
layoutarg —broadcast_presettakes it but doesn't send it. - Initial sync/ack handshake on connect.
- Disallow presets without UUID (enforce server-side before broadcast).
- Desktop activity ring — flash on desktop widget when it receives a value from iPad.
- No live color-sync broadcast (deprioritized) — color only travels
inside a full
"preset"snapshot, never standalone like label/value/feedback. Regressed at some point per Paul; not worth chasing until other things are done.