<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zhihuang Lin</title>
    <description>The latest articles on DEV Community by Zhihuang Lin (@zhihuanglin).</description>
    <link>https://dev.to/zhihuanglin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3541168%2F4f09c6fa-ab0e-4d4a-80a6-18eda6fcf8d5.png</url>
      <title>DEV Community: Zhihuang Lin</title>
      <link>https://dev.to/zhihuanglin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zhihuanglin"/>
    <language>en</language>
    <item>
      <title>What Breaks When You Let an LLM Edit Screen Recordings (and How We Built a Deterministic CLI Harness for macOS)</title>
      <dc:creator>Zhihuang Lin</dc:creator>
      <pubDate>Fri, 13 Nov 2026 14:23:34 +0000</pubDate>
      <link>https://dev.to/zhihuanglin/what-breaks-when-you-let-an-llm-edit-screen-recordings-and-how-we-built-a-deterministic-cli-al8</link>
      <guid>https://dev.to/zhihuanglin/what-breaks-when-you-let-an-llm-edit-screen-recordings-and-how-we-built-a-deterministic-cli-al8</guid>
      <description>&lt;p&gt;Coding agents such as Claude Code and Codex work well on source code for three reasons: source files are plain text, &lt;code&gt;git diff&lt;/code&gt; makes every proposed change readable, and compilers or test suites reject broken edits deterministically.&lt;/p&gt;

&lt;p&gt;Screen recordings have none of those properties. A flattened MP4 bakes cursor movement, zoom state, and audio into a single video stream. Dumping raw frames into a model context window is slow and expensive. Worst of all, if an LLM edits timeline JSON directly, a single timestamp miscalculation shifts downstream cuts, clips spoken consonants, or deletes the exact two seconds where a user clicked a button on screen.&lt;/p&gt;

&lt;p&gt;While building &lt;a href="https://studio.oiloil.org/en/" rel="noopener noreferrer"&gt;Oil Studio&lt;/a&gt;—a native macOS screen recorder and editor written in Swift and Metal for Apple silicon (&lt;code&gt;macOS 15+&lt;/code&gt;)—we wanted terminal agents to handle two tedious parts of shipping software demos: cutting retakes out of rough voice-over recordings, and recording clean UI walkthroughs without manual timeline scrubbing.&lt;/p&gt;

&lt;p&gt;To make that reliable in practice, we had to move all timeline math, media validation, and safety gates out of the prompt and into a deterministic local CLI harness (&lt;code&gt;oilstudio&lt;/code&gt;). Here are the five concrete failure modes we ran into when connecting LLMs to video editing, and how the architecture handles each one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1hw9dstydawbr6sgdj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1hw9dstydawbr6sgdj3.png" alt="Oil Studio native macOS editor overview" width="799" height="540"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture overview: separating semantic judgment from media execution
&lt;/h2&gt;

&lt;p&gt;Instead of embedding a chat sidebar inside the video editor or asking users to install external scripts manually, Oil Studio bundles both the &lt;code&gt;oilstudio&lt;/code&gt; command-line binary and its Agent Skill directly inside the macOS app (&lt;strong&gt;Settings › AI Agent → Install&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Installing from the app sets up the CLI and Skill in one click and keeps them version-locked across app updates. Before running any task, the agent performs a read-only handshake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OILSTUDIO_SKILL_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.9.15 oilstudio status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;skill.compatible&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, the CLI stops immediately and returns an explicit upgrade hint rather than letting an older prompt schema guess at newer project fields.&lt;/p&gt;

&lt;p&gt;From there, responsibilities are strictly divided:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------------------------------------------------------------------+
| External Agent (Claude Code / Codex)                              |
| - Reads word-timed transcripts, audio metrics, and OCR timelines  |
| - Identifies semantic retakes, false starts, and terminology bugs |
| - Inspects ambiguous spans via on-demand storyboards or WAV clips |
+---------------------------------+---------------------------------+
                                  | Structured JSON (CLI only)
                                  v
+-------------------------------------------------------------------+
| oilstudio CLI &amp;amp; Validator                                         |
| - Enforces projectFingerprint &amp;amp; contextFingerprint consistency    |
| - Validates word boundaries, keptRange, and UI activity overlaps  |
| - Projects post-cut caption timing (--plan) before edits apply    |
+---------------------------------+---------------------------------+
                                  | Staged proposal (proposalId)
                                  v
+-------------------------------------------------------------------+
| Oil Studio macOS App (.oilstudio bundle)                          |
| - Displays cuts, zooms, overlays, and redactions in review panel  |
| - Applies approved changes atomically (single-step Cmd+Z undo)    |
+-------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent never reads or writes files inside a &lt;code&gt;.oilstudio&lt;/code&gt; package directly. Every edit goes through &lt;code&gt;plan validate&lt;/code&gt; and &lt;code&gt;plan submit&lt;/code&gt;, producing an inspectable proposal inside the native editor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Failure mode 1: Output-time drift when combining multiple cuts
&lt;/h2&gt;

&lt;p&gt;When a human watches a 10-minute video and writes notes like &lt;em&gt;"cut 01:10 to 01:22, then cut 03:05 to 03:18"&lt;/em&gt;, they are referring to current playback time. If an LLM proposes 15 cuts in playback/output coordinates, two things go wrong:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cumulative offset errors.&lt;/strong&gt; Models frequently miscalculate cumulative time shifts across a dozen edits, causing later cuts to land half a second into the next sentence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partial rejection breaks downstream edits.&lt;/strong&gt; If the user unchecks cut #3 in the review UI because they want to keep that remark, cuts #4 through #15 would shift if they were anchored to output timestamps.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Solution: immutable source-time addressing + pre-cut caption projection
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;oilstudio&lt;/code&gt;, cuts (&lt;code&gt;decisions&lt;/code&gt;), zoom blocks (&lt;code&gt;zooms&lt;/code&gt;), and privacy masks (&lt;code&gt;redactions&lt;/code&gt;) never use output time. Every edit references either utterance IDs (&lt;code&gt;U0012&lt;/code&gt;–&lt;code&gt;U0015&lt;/code&gt;) or integer &lt;strong&gt;source milliseconds&lt;/strong&gt; (&lt;code&gt;sourceMs&lt;/code&gt;), pinned against two hashes returned by &lt;code&gt;oilstudio context&lt;/code&gt;: &lt;code&gt;projectFingerprint&lt;/code&gt; and &lt;code&gt;contextFingerprint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the user makes a manual trim in the app while the agent is thinking, the fingerprint changes and &lt;code&gt;plan validate&lt;/code&gt; rejects the stale plan instead of applying edits to shifted state.&lt;/p&gt;

&lt;p&gt;What if the user asks the agent to &lt;em&gt;"cut out my retakes AND fix the misspelled CLI flags in the captions"&lt;/em&gt; in a single prompt? Waiting for the user to approve the video cuts before proofreading captions would force a slow two-turn workflow. Instead, &lt;code&gt;subtitles get&lt;/code&gt; and &lt;code&gt;subtitles apply&lt;/code&gt; accept &lt;code&gt;--plan&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Export editing context and generate a word-protected pause draft&lt;/span&gt;
oilstudio context &lt;span class="s2"&gt;"Demo.oilstudio"&lt;/span&gt; --out &lt;span class="s2"&gt;"$WORK/01-context.json"&lt;/span&gt;
oilstudio pauses &lt;span class="s2"&gt;"Demo.oilstudio"&lt;/span&gt; --out-plan &lt;span class="s2"&gt;"$WORK/02-plan.json"&lt;/span&gt;

&lt;span class="c"&gt;# 2. After appending semantic retake cuts to 02-plan.json, validate and stage&lt;/span&gt;
oilstudio plan validate &lt;span class="s2"&gt;"$WORK/02-plan.json"&lt;/span&gt;
oilstudio plan submit &lt;span class="s2"&gt;"$WORK/02-plan.json"&lt;/span&gt;

&lt;span class="c"&gt;# 3. Project visible post-cut captions and diagnostics without waiting for approval&lt;/span&gt;
oilstudio subtitles get &lt;span class="s2"&gt;"Demo.oilstudio"&lt;/span&gt; --plan &lt;span class="s2"&gt;"$WORK/02-plan.json"&lt;/span&gt; --out &lt;span class="s2"&gt;"$WORK/04-subtitles.json"&lt;/span&gt;
oilstudio subtitles apply &lt;span class="s2"&gt;"Demo.oilstudio"&lt;/span&gt; &lt;span class="s2"&gt;"$WORK/05-subtitle-edits.json"&lt;/span&gt; --plan &lt;span class="s2"&gt;"$WORK/02-plan.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing &lt;code&gt;--plan&lt;/code&gt; projects which captions remain visible after the pending cuts, computes diagnostics (inconsistent casing, residual spoken fillers, line-wrap warnings), and queues the caption fixes right behind the cut proposal (&lt;code&gt;pendingReason: "review_in_progress"&lt;/code&gt;). When the user clicks Apply once in the app, timeline cuts, captions, and chapter markers all land in sync.&lt;/p&gt;




&lt;h2&gt;
  
  
  Failure mode 2: Waveform cutters clip consonants, while text-only LLMs miss vocal hesitations
&lt;/h2&gt;

&lt;p&gt;Automated speech editing fails in opposite ways depending on whether you use audio thresholds or transcripts alone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audio-only silence removal clips unvoiced consonants.&lt;/strong&gt; Sounds like &lt;code&gt;s&lt;/code&gt;, &lt;code&gt;t&lt;/code&gt;, &lt;code&gt;k&lt;/code&gt;, and &lt;code&gt;p&lt;/code&gt; carry low RMS energy. Slicing strictly on volume thresholds trims word edges and makes speech sound abrupt. Worse, if an LLM tries to "help" by adding its own &lt;code&gt;±50 ms&lt;/code&gt; padding on top of an existing silence detector, cuts either leave awkward dead air or swallow adjacent syllables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transcript-only editing misses untranscribed hesitations and misreads discourse words.&lt;/strong&gt; When a speaker mumbles an aborted half-word or hesitates (&lt;code&gt;"uh"&lt;/code&gt;), local Whisper may emit no text token at all—leaving a visible lump on the audio waveform with an empty transcript span. Conversely, words like &lt;code&gt;"so"&lt;/code&gt;, &lt;code&gt;"actually"&lt;/code&gt;, or &lt;code&gt;"like"&lt;/code&gt; can be either removable verbal clutter or load-bearing logical transitions depending on the sentence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkm5j4jtszhk6o20rdtl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkm5j4jtszhk6o20rdtl4.png" alt="Word-level transcript cutting in Oil Studio" width="799" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: deterministic breath margins + multi-modal evidence on demand
&lt;/h3&gt;

&lt;p&gt;First, &lt;code&gt;oilstudio pauses --out-plan&lt;/code&gt; generates a deterministic baseline pause-cleanup draft (defaulting to pauses &lt;code&gt;&amp;gt;= 300 ms&lt;/code&gt;, a &lt;code&gt;50 ms&lt;/code&gt; word-boundary guard around verified speech tokens, and optional &lt;code&gt;--keep&lt;/code&gt; breath retention—while re-checking Whisper tokens longer than &lt;code&gt;800 ms&lt;/code&gt; against the session noise floor so DTW-stretched tokens do not accidentally protect long silences). The agent appends semantic cuts to that same plan file rather than inventing its own silence offsets.&lt;/p&gt;

&lt;p&gt;Second, &lt;code&gt;oilstudio context&lt;/code&gt; enriches each utterance with acoustic and visual metadata so the model knows &lt;em&gt;where&lt;/em&gt; text alone is insufficient:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;utterances[].audio&lt;/code&gt;: recognition confidence, speaking pace, loudness, internal pauses, and &lt;code&gt;unrecognized&lt;/code&gt; spans (timestamps where voice activity exists on the waveform without recognized words).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;screen&lt;/code&gt;: an OCR text timeline of what was visible in the recorded window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fillerCandidates&lt;/code&gt;: detected hesitation sounds and candidate filler words that require contextual judgment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rather than extracting frames for an entire 15-minute recording, the agent reads the text transcript end-to-end first, then inspects media &lt;strong&gt;only around ambiguous candidates&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Render one composite sheet (frames + waveform + word timing) for utterances 12..18&lt;/span&gt;
oilstudio storyboard &lt;span class="s2"&gt;"Demo.oilstudio"&lt;/span&gt; --utterances U0012-U0018 --out &lt;span class="s2"&gt;"$WORK/check-u12.png"&lt;/span&gt;

&lt;span class="c"&gt;# Or render a short WAV preview across a proposed splice to verify the audio join&lt;/span&gt;
oilstudio plan preview &lt;span class="s2"&gt;"$WORK/02-plan.json"&lt;/span&gt; --index 0 --out &lt;span class="s2"&gt;"$WORK/join-0.wav"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a storyboard sheet, two consecutive utterances with similar waveform contours where the first stops mid-phrase alongside a repeated UI state confirm a retake. A read-only coverage script distributed with the Skill (&lt;code&gt;check_filler_coverage.py&lt;/code&gt;) then verifies that every &lt;code&gt;fillerCandidates&lt;/code&gt; item is explicitly resolved (&lt;code&gt;cut&lt;/code&gt;, &lt;code&gt;keep&lt;/code&gt;, &lt;code&gt;review&lt;/code&gt;, or covered by a larger passage cut) and calculates time savings from the mathematical union of source intervals rather than double-counting overlapping ranges.&lt;/p&gt;




&lt;h2&gt;
  
  
  Failure mode 3: Deleting a "verbal retake" that contained a non-repeated UI click
&lt;/h2&gt;

&lt;p&gt;In a talking-head podcast, if you say a sentence twice and the second take is cleaner, you can always cut the first take.&lt;/p&gt;

&lt;p&gt;In a software tutorial, &lt;strong&gt;the audio might be a retake while the screen is not.&lt;/strong&gt; Suppose the presenter clicks "Create API Key" during take #1, stumbles over their explanation, and repeats the explanation smoothly in take #2 &lt;em&gt;without&lt;/em&gt; clicking the button again because the modal is already open. Deleting take #1 removes the actual UI action from the video, leaving viewers staring at a modal that appears out of nowhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: activity-overlap validation and &lt;code&gt;uncheckedByDefault&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;We tried warning against this in the system prompt first. Under long-context pressure, models still occasionally proposed cutting across active UI steps. So we moved the rule into &lt;code&gt;plan validate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is what an actual semantic cut entry looks like in &lt;code&gt;02-plan.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"projectFingerprint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"sha256:9c4e..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"contextFingerprint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"sha256:31a8..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Remove 3 retakes and 2 verbal slips, shortening recording by 48s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;"decisions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"cut"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"range"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"U0012"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"U0015"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"abandoned_take"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"removedText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Now let's open the export menu and set the frame rate to—sorry, let me redo that."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"keptText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Next, open the export menu and choose 60 fps."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"keptRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"U0016"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"U0017"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Later take repeats the full instruction cleanly."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"screenAction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"redundant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"visualAssessment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"The same export popover is opened again from scratch at U0016."&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"review"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"low"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"sourceMs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;61200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64850&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"filler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"removedText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"I usually leave hardware encoding on default here."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"keptText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Sounds conversational, but mentions a setting not repeated later."&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;plan validate&lt;/code&gt; enforces three structural rules on these entries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mandatory replacement proof (&lt;code&gt;keptRange&lt;/code&gt;).&lt;/strong&gt; Every &lt;code&gt;abandoned_take&lt;/code&gt; cut must point to the exact retained utterances (&lt;code&gt;keptRange&lt;/code&gt;) that cover the same information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI activity protection.&lt;/strong&gt; The validator cross-checks every proposed cut against recorded pointer clicks, keystrokes, and screen changes in &lt;code&gt;activity&lt;/code&gt;. If a cut overlaps an interaction and does &lt;em&gt;not&lt;/em&gt; include &lt;code&gt;"screenAction": "redundant"&lt;/code&gt; paired with a concrete &lt;code&gt;"visualAssessment"&lt;/code&gt;, the validator automatically flags the entry as &lt;code&gt;uncheckedByDefault&lt;/code&gt; in Oil Studio's review panel so it will not apply unless the human explicitly ticks it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duration guardrails.&lt;/strong&gt; Standard non-silence cuts longer than 30 seconds are also marked &lt;code&gt;uncheckedByDefault&lt;/code&gt; unless they are high-confidence &lt;code&gt;abandoned_take&lt;/code&gt; spans backed by a valid &lt;code&gt;keptRange&lt;/code&gt; (up to 3 minutes). Low-confidence &lt;code&gt;review&lt;/code&gt; items stay out of the executable cut list entirely and are reported separately for human judgment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbr5jr2lfui7p30hx41dy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbr5jr2lfui7p30hx41dy.png" alt="Hatched timeline cut spans with UI activity protection in Oil Studio" width="799" height="540"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Failure mode 4: UI automation recordings have teleporting cursors and dead loading waits
&lt;/h2&gt;

&lt;p&gt;The other workflow we wanted was letting an agent record a product demo of a native macOS window or web app after a UI change.&lt;/p&gt;

&lt;p&gt;If you record the screen while an automation tool clicks DOM selectors or accessibility elements, the raw video looks unnatural: the cursor jumps instantaneously from coordinate to coordinate in a single frame, followed by 2–4 seconds of motionless waiting between steps while pages load or the agent plans its next action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: unbaked vector cursor synthesis + post-capture idle stripping
&lt;/h3&gt;

&lt;p&gt;Because a &lt;code&gt;.oilstudio&lt;/code&gt; bundle stores video at native window resolution and keeps pointer trajectories as separate vector metadata rather than baking the OS cursor into the video frames, &lt;code&gt;oilstudio record&lt;/code&gt; decouples the rendered cursor from the physical mouse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Inspect available windows and center/resize the target window to 1280x800&lt;/span&gt;
oilstudio record sources
oilstudio record prepare --source window-123 --size 1280x800 --center --activate
oilstudio record start --source window-123

&lt;span class="c"&gt;# 2. Declare each target coordinate before clicking (or pass --perform)&lt;/span&gt;
oilstudio record click --at-fraction 0.74,0.18 --perform

&lt;span class="c"&gt;# 3. Stop capture and strip silent waiting gaps while rebuilding click zooms&lt;/span&gt;
oilstudio record stop
oilstudio idle &lt;span class="s2"&gt;"/path/to/New Recording.oilstudio"&lt;/span&gt; --submit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details make the resulting video look clean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Declared intent trajectories.&lt;/strong&gt; During agent recording, the physical macOS pointer is not recorded at all. Each &lt;code&gt;record click&lt;/code&gt; or &lt;code&gt;record move&lt;/code&gt; report supplies target coordinates (either screen points via &lt;code&gt;--at&lt;/code&gt; or normalized &lt;code&gt;0–1&lt;/code&gt; window fractions via &lt;code&gt;--at-fraction&lt;/code&gt;), from which Oil Studio synthesizes a continuous spring-smoothed cursor path, click animation, and motion blur at 60 fps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idle compression with zoom realignment.&lt;/strong&gt; Running &lt;code&gt;oilstudio idle &amp;lt;project&amp;gt; --submit&lt;/code&gt; afterward detects silent waiting spans (default threshold &lt;code&gt;1500 ms&lt;/code&gt;, keeping &lt;code&gt;400 ms&lt;/code&gt; around actions), aligns any slightly delayed click reports with actual visual frame changes, and recalculates automatic zoom blocks across the tightened timeline. (Permission prompts remain strictly human-controlled: only the user can grant macOS Screen Recording access or enable Oil Studio's agent-recording toggle, and a visible recording pill stays on screen throughout capture.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F88yb150x7z5gcgbvpfwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F88yb150x7z5gcgbvpfwp.png" alt="Click-following auto-zoom and vector cursor controls in Oil Studio" width="799" height="540"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Failure mode 5: Privacy redactions drift under auto-zoom or leak into agent vision
&lt;/h2&gt;

&lt;p&gt;Screen recordings of developer tools regularly contain API keys, customer emails, or internal URLs in corners of the window. Combining auto-zoom composition with external AI agents introduces two easy ways to leak those secrets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Canvas-space coordinate drift.&lt;/strong&gt; If you attach a blur or pixelation box to the &lt;em&gt;output&lt;/em&gt; video canvas, the moment an auto-zoom block scales the window to &lt;code&gt;1.8×&lt;/code&gt; and pans toward a button, the underlying window moves while the mask stays put—uncovering the secret.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unmasked frame extraction.&lt;/strong&gt; If a user masks an API key in the editor and then asks an external cloud LLM agent to adjust zooms or proofread captions, sending raw source frames to &lt;code&gt;frame&lt;/code&gt; or &lt;code&gt;storyboard&lt;/code&gt; would expose the unredacted pixels to the model provider.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Solution: pre-compositor source-frame coordinates + pre-redacted agent frames
&lt;/h3&gt;

&lt;p&gt;In Oil Studio's Metal rendering pipeline, redactions (&lt;code&gt;pixelate&lt;/code&gt;, &lt;code&gt;blur&lt;/code&gt;, or solid &lt;code&gt;fill&lt;/code&gt;) are defined in normalized &lt;code&gt;0–1&lt;/code&gt; &lt;strong&gt;source-frame coordinates&lt;/strong&gt; (&lt;code&gt;region: {x, y, width, height}&lt;/code&gt;) over &lt;code&gt;[sourceStartMs, sourceEndMs]&lt;/code&gt; and rendered &lt;em&gt;before&lt;/em&gt; camera zoom, cursor overlays, or canvas framing run. When the virtual camera zooms in or pans across the window, the pixelation stays locked to the underlying UI element.&lt;/p&gt;

&lt;p&gt;Just as importantly, that redaction pass runs &lt;em&gt;before&lt;/em&gt; &lt;code&gt;oilstudio frame&lt;/code&gt; or &lt;code&gt;oilstudio storyboard&lt;/code&gt; exports any PNG or runs OCR for an external agent, and any plan proposal that removes or shrinks an existing redaction requires manual confirmation in the app.&lt;/p&gt;

&lt;p&gt;One deliberate limitation we document clearly in the Skill: a redaction is a fixed rectangle in source-frame coordinates, &lt;strong&gt;not&lt;/strong&gt; an optical-flow object tracker. If a sensitive string scrolls up a terminal or web page, the agent (or user) must specify separate time ranges and rectangles and verify coverage on the output timeline (&lt;code&gt;oilstudio frame &amp;lt;project&amp;gt; --output-ms ... --text --out ...&lt;/code&gt;) rather than assuming a static box will chase scrolling text.&lt;/p&gt;




&lt;h2&gt;
  
  
  Trade-offs and when another tool is a better fit
&lt;/h2&gt;

&lt;p&gt;Designing around native macOS frameworks, local structured project bundles, and a local CLI meant making deliberate scope trade-offs. Depending on your workflow, those trade-offs may be dealbreakers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;macOS 15+ on Apple silicon only.&lt;/strong&gt; Keeping the capture pipeline, Metal compositor, and on-device Whisper engine small and fast meant skipping Electron and legacy cross-platform layers. If your team needs Windows, Linux, or Intel Mac support, OBS Studio, Descript, or Loom are better choices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured &lt;code&gt;.oilstudio&lt;/code&gt; projects, not arbitrary MP4 editing.&lt;/strong&gt; Both the editor and &lt;code&gt;oilstudio&lt;/code&gt; CLI rely on separate video, audio, cursor, and click metadata tracks (though &lt;code&gt;oilstudio import&lt;/code&gt; can convert existing third-party auto-zoom recording projects read-only without touching the originals). If you need a general-purpose NLE for camera footage or flat MP4s, DaVinci Resolve or Final Cut Pro is the right tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local file export rather than hosted share links.&lt;/strong&gt; Oil Studio exports standard 60 fps MP4, GIF, and SRT files locally with no cloud account. If your primary use case is recording a quick bug report and pasting an instant hosted URL with timestamped team comments into Slack or Linear, Loom or CleanShot Cloud fits that workflow much better. (We maintain a detailed &lt;a href="https://studio.oiloil.org/en/compare/screen-studio-alternative/" rel="noopener noreferrer"&gt;7-tool Mac screen recorder technical comparison&lt;/a&gt; covering exact pricing models, audio tracks, redaction behavior, and platform limits across these tools.)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The biggest lesson from building &lt;code&gt;oilstudio&lt;/code&gt; was that making non-text software "agent-friendly" has very little to do with clever prompt writing. Prompts cannot reliably add millisecond offsets, protect unvoiced consonants, or notice that a verbal stumble happened at the exact moment a user clicked a critical UI button.&lt;/p&gt;

&lt;p&gt;Putting immutable source-time addressing, acoustic/activity metadata, and strict structural validation inside a local CLI lets the LLM focus on what it is actually good at—reading a messy 10-minute rough take and understanding human intent—while keeping every edit inspectable and reversible with a single &lt;code&gt;⌘Z&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to inspect the full CLI command reference and workflow rules, see the &lt;a href="https://studio.oiloil.org/en/docs/ai-agent-cli/" rel="noopener noreferrer"&gt;AI Agent CLI technical documentation&lt;/a&gt; on &lt;a href="https://studio.oiloil.org/en/" rel="noopener noreferrer"&gt;studio.oiloil.org&lt;/a&gt;. Recording, auto-zoom editing, local Whisper transcription, and the built-in Agent CLI are free to try locally on Apple silicon Macs; if you experiment with driving native desktop apps from Claude Code or Codex, I would love to hear how you structure your own validation harnesses.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>macos</category>
      <category>cli</category>
    </item>
  </channel>
</rss>
