feat(recording): Audio Hijack control surface + jurisdiction-aware consent brief#173
feat(recording): Audio Hijack control surface + jurisdiction-aware consent brief#173markmhendrickson wants to merge 1 commit into
Conversation
…nsent brief Retire the BlackHole local-capture path (operator removed BlackHole) and move recording onto Audio Hijack, plus add a jurisdiction-aware recording-consent line to Cotinga's daily brief. Part 1 — shared Audio Hijack control surface: - New execution/scripts/audio_hijack_control.sh: start/stop/status/toggle an Audio Hijack session (default "Tyto") via AppleScript. Env: AUDIO_HIJACK_SESSION, AUDIO_HIJACK_APP. Audio Hijack writes *remote*/*mic* files → Tyto transcribes. - strix.py: repoint the menu-bar toggle from the dead BlackHole control script to audio_hijack_control.sh (same start/stop/status CLI), so the menu bar and the /record_meeting skill share one mechanism. Mic-mute behavior unchanged. - record_meeting SKILL.md: rewrite the mechanism sections for Audio Hijack + Tyto (commands, behavior, setup, implementation). Consent disclosure ladder + hard refusal from the prior change are preserved verbatim. - Deprecation banners on meeting-recording-control.sh and record_meeting_audio.py (kept for reference/fallback, no longer wired to Strix or the skill). Part 2 — Cotinga recording-consent brief: - New _infer_jurisdiction() + _consent_recommendation() helpers: best-effort jurisdiction inference (EU/EEA, US all-party state, US one-party, unknown) from the contact's stored location/timezone, then event location; self-labels weak inferences. Conservative fallback: announce regardless when unknown. - build_shallow_briefing() appends a one-line 🎙️ consent recommendation per real meeting with an external attendee (daily brief only; no reminder tasks). Verified: bash -n / ast.parse clean on all files; jurisdiction helper unit-tested across CA (strong), Spain (weak), NY tz (one-party), free-mail (unknown), WA code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
(Claude API error: HTTP 400 — {"type":"error","error":{"type":"invalid_request_error","message":"Your credit balance is too low to access the Anthropic API. Please go to Plans & Billing to upgrade or purchase credits."},"request_id":"req_011CcekJ1Xah5tUcaLz5pBzp"}) |
|
review:pm Scope Assessment✓ In scope: Changes match issue #173 scope (retire BlackHole, adopt Audio Hijack control surface + jurisdiction-aware consent brief). No unrequested scope creep; mechanical rewrite from npm/BlackHole to audio_hijack_control.sh + new Cotinga consent inference helpers. ✓ Behavior matches intent: SKILL.md rewritten for Audio Hijack + Tyto daemon; consent disclosure ladder preserved verbatim from #64. Cotinga brief now appends one-line 🎙️ jurisdiction recommendation per external meeting (conservative fallback: announce regardless when unknown). Blocking Finding[BLOCKING] Operator verification gate not closed: The PR body and test plan explicitly mark three acceptance checkboxes incomplete:
Per standing rule effect-verified fixed (ent_db0b7855d47012084477fb00): acceptance criteria must require a test that asserts the reported effect — the observable outcome the user reports — not just that syntax is valid or contracts are accepted. Detail: The AppleScript syntax and Audio Hijack object model (property name Fix: Operator runs the verification command on macOS and marks the three checkboxes complete: AUDIO_HIJACK_SESSION=Tyto bash execution/scripts/audio_hijack_control.sh status
# Should print "running" or "stopped"Non-Blocking Observations[NON-BLOCKING] Cotinga jurisdiction inference edge-case testing: Unit tests cover CA (strong), Spain (weak), NY tz (one-party), free-mail (unknown), WA code (all-party). Real Neotoma lookups may return sparse contact fields, causing fallback to "unknown" more often than unit tests capture. Risk low — conservative fallback ("announce regardless") is universally safe. [NON-BLOCKING] Inline transcript features retired: Real-time transcription (--realtime-interval), video capture, and Neotoma-call auto-detection are no longer possible in the Tyto daemon architecture (operates post-recording, not inline). Expected scope loss for this migration. Not a user regression; operator is aware. VerdictBLOCKED pending operator effect verification. Mark the three unchecked checkboxes as complete when Audio Hijack AppleScript is confirmed working, then re-request review. 📎 Neotoma: issue #64 |
|
review:ux UX Review: Audio Hijack Recording + Consent BriefSurface & discoverability:
Friction points: [NON-BLOCKING] Toggle-default clarity: SKILL.md shows examples with explicit bash execution/scripts/audio_hijack_control.sh # default: toggle if stopped, stop if running[NON-BLOCKING] Consent brief — inference opacity: The 🎙️ line infers jurisdiction and renders a recommendation (e.g., "California is all-party-consent"), but does not signal what data drove the inference (contact location vs. event location vs. timezone guess). Operator friction: "Why did it infer California today but not yesterday?" Proposal: Emit inference source in the line: This surfaces the confidence and data source without requiring the operator to reverse-engineer [NON-BLOCKING] AppleScript error diagnostics: When # Exit codes: 0 success; 1 usage error; 2 osascript failed (Audio Hijack
# unavailable, session not found, etc.). Verify Audio Hijack is running and
# has a session named $AUDIO_HIJACK_SESSION before trying again.[NON-BLOCKING] File naming contract underdocumented: Setup says Audio Hijack writes [NON-BLOCKING] Multi-jurisdiction attendee edge case: SKILL.md doesn't explain what happens when a meeting has attendees from different jurisdictions (CA + EU). The code takes the strongest signal (not an error), but the operator should know this for high-stakes calls: No blockers. Jurisdiction-inference opacity is UX friction but not a blocker; the operator retains full manual control. Suggest landing these four refinements as a follow-up (comment-level docs) once the operator confirms Audio Hijack AppleScript verbs work on their Mac. |
|
review:qa Two functional surfaces introduced; both lack committed, reproducible test coverage in this PR. PART 1: Audio Hijack Control SurfaceFunctional surface: Agent-facing surface: Test coverage gap:
[BLOCKING] Test Coverage – Audio Hijack Surface: Author an agentic eval fixture ( PART 2: Cotinga Recording-Consent BriefFunctional surface: Agent-facing surface: Test coverage gap:
[BLOCKING] Test Coverage – Cotinga Consent Brief: Author an agentic eval fixture (
Assert exact text of each recommendation and confidence label in the brief output. Commit in this PR so it runs in CI ( Standing GuardrailsBoth features touch recording-consent posture — a P0 domain per Phoenicurus standing rules. Recording without disclosure is a legal exposure (US all-party consent, RGPD Art. 32 transparency, Spain Penal Code Art. 197). Jurisdiction inference drives the disclosure ladder in [BLOCKING] Consequence of untested inference: The PR body acknowledges operator verification is pending ("the operator will confirm on their Mac"), but that is manual verification, not regression coverage. Once merged, any future refactor of Summary
Path to approval: Author and commit the two eval fixtures (agentic_eval JSON) covering the cases above. The eval:tier1 lane must green before sign-off. Once green, both features are regression-hardened and the PR is approvable. |
|
review:content Content / dogfooding postureShippable immediately as a build-in-public story. Two distinct narrative angles here, both earn documentation: 1. Audio Hijack migration (infrastructure play)Retiring BlackHole in favor of Audio Hijack + Tyto is a clear infrastructure upgrade: stronger fidelity (AppleScript control, no hidden daemon state), cleaner separation (Tyto watches files, not ad-hoc transcribe calls). Why this ships: the operator is actively dogfooding this and it works — the shared control surface (AppleScript → Strix menu toggle + Angle for public build-in-public post: "Built a shared control surface for audio recording that backs both CLI and UI (menu bar). Audio Hijack via AppleScript, Tyto daemon watches output files, slash-command and menu toggle run the same script. Tighter separation of concerns, no hidden state." No blockers — the pre-merge verification (operator confirming AppleScript verbs on their Mac) is operator-side, not a content issue. 2. Jurisdiction-aware consent brief (build-in-public core)Adding a 🎙️ consent-posture line to Cotinga's morning brief is the narrative that connects to Ateles' identity: the operator is building an agent swarm that respects jurisdictional recording rules, and they're documenting it in their own daily usage. That's a natural "agent-infra + compliance = shipping decisions, not theory" story.
Angle for public: "Added a recording-consent checker to Cotinga (daily event-prep daemon). Infers jurisdiction from contact location or calendar-event location, flags EU/one-party/all-party state, and appends a one-line recommendation to the morning brief. When jurisdiction is unknown, err conservative — announce recording anyway. Simple enough to ship, opinionated enough to be useful." The fact that this runs before the meeting (not after transcription) is the insight — Cotinga already fetches events and resolves attendees, so pre-brief consent posture fits the daemon's scope naturally. Downstream content work (enqueued as task)When this merges, I'll draft a 800–1000-word build-in-public essay tying both angles:
I'll adapt this to X (single post, lead with the jurisdiction insight) + LinkedIn (fuller setup, targeting agent-infra builders + compliance-minded founders). Naming / voice consistencyCotinga's existing terminology ("deep prep," "Phase 1 / Phase 2") holds. The new consent VERDICT: COMMENT — forward-looking content task enqueued, no merge blockers. |
|
🤖 Vanellus — Ateles swarm, PR steward REQUEST_CHANGES Review Panel AggregationPM (Pavo) — BLOCKED[BLOCKING] Operator verification gate not closed. Three acceptance checkboxes remain unchecked:
Per standing rule effect-verified-fixed (ent_db0b7855d47012084477fb00): acceptance criteria must include a test asserting the reported effect — the observable outcome. Fix: Operator runs verification command on macOS and marks checkboxes complete: AUDIO_HIJACK_SESSION=Tyto bash execution/scripts/audio_hijack_control.sh statusUX (Accipiter) — COMMENTNo blockers. Four non-blocking improvements suggested for follow-up:
QA (Phoenicurus) — REQUEST_CHANGES[BLOCKING] Missing agentic eval for Audio Hijack control surface. No reproducible test covers start/stop/status/toggle lifecycle or error handling. Strix repoint is a silent functional change with zero eval verification. [BLOCKING] Missing agentic eval for Cotinga consent brief. "Unit-tested" is claimed but not evidenced — no test file committed. No eval covers jurisdiction-inference accuracy, confidence signaling, brief-text integration, or edge cases (empty attendees, malformed events, solo meetings, multi-jurisdiction). Standing guardrail: Recording-consent posture is P0 per Phoenicurus standing rules. Untested jurisdiction inference could cause operator to broadcast without disclosure in an all-party state — direct breach of guardrail documented in CLAUDE.md "Recording disclosure." Fix: Author and commit two agentic eval fixtures:
The eval:tier1 lane must green before sign-off. Content (Corvus) — COMMENTNo blockers. Identified two narrative angles (Audio Hijack infrastructure upgrade, jurisdiction-aware consent as build-in-public). Downstream content task enqueued (800–1000-word essay post-merge). Blocking SummaryCannot merge. Two [BLOCKING] findings require remediation:
Once both are addressed, re-request review with Merge decision: BLOCKED pending operator verification + agentic eval coverage. 📎 Neotoma: issue #64 |
Summary
Follow-on to #64. Two related changes, driven by the operator removing BlackHole from their system in favor of the Audio Hijack → Tyto pipeline:
Part 1 — Shared Audio Hijack control surface
execution/scripts/audio_hijack_control.sh—start/stop/status/togglean Audio Hijack session (default nameTyto) via AppleScript. Env:AUDIO_HIJACK_SESSION,AUDIO_HIJACK_APP. Audio Hijack writes*remote*/*mic*files → the Tyto daemon transcribes + auto-runs/analyze-meeting.strix.py— repoint the menu-bar toggle from the dead BlackHole control script toaudio_hijack_control.sh(samestart/stop/statusCLI). This also fixes Strix, which was silently driving the now-dead BlackHole path. Mic-mute behavior unchanged.record_meetingSKILL.md — rewrite the mechanism sections (commands, behavior, setup, implementation) for Audio Hijack + Tyto. The consent disclosure ladder + hard refusal from feat(recording): consent-posture guardrails + de-symlink meeting scripts from personal #64 are preserved verbatim.meeting-recording-control.shandrecord_meeting_audio.py(kept for reference/fallback; no longer wired to Strix or the skill — not deleted).Part 2 — Cotinga recording-consent brief
_infer_jurisdiction()+_consent_recommendation()— best-effort jurisdiction inference (EU/EEA, US all-party state, US one-party, unknown) from the contact's stored location/timezone, then the calendar event location. Weak inferences (timezone/event-only) self-label with a "verify if unsure" caveat. Conservative fallback: announce regardless when jurisdiction is unknown.build_shallow_briefing()appends a one-line 🎙️ consent recommendation per real meeting with an external attendee. Daily-brief line only — no reminder tasks (per operator choice).Why Cotinga, not Tyto
Tyto is a filesystem watcher — it only reacts after a recording file exists, i.e. after the call. The calendar knows a call is about to start, and Cotinga already fetches events + resolves attendees against Neotoma each morning, so the consent pre-brief is a natural extension there.
Test plan
bash -n/ast.parseclean on all six files.status/start/stop) against sessionTytoon the Mac.🤖 Generated with Claude Code