<?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: Milmann A</title>
    <description>The latest articles on DEV Community by Milmann A (@milmann_a_b592c338cf0df1f).</description>
    <link>https://dev.to/milmann_a_b592c338cf0df1f</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%2F4219465%2F4d40e714-1db3-4139-a50f-122e773831f3.jpg</url>
      <title>DEV Community: Milmann A</title>
      <link>https://dev.to/milmann_a_b592c338cf0df1f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/milmann_a_b592c338cf0df1f"/>
    <language>en</language>
    <item>
      <title>👻 How I Built GhostPR: Turning User Screen Recordings into Verified Git Pull Requests with Kiro</title>
      <dc:creator>Milmann A</dc:creator>
      <pubDate>Sat, 31 Oct 2026 22:32:26 +0000</pubDate>
      <link>https://dev.to/milmann_a_b592c338cf0df1f/how-i-built-ghostpr-turning-user-screen-recordings-into-verified-git-pull-requests-with-kiro-2828</link>
      <guid>https://dev.to/milmann_a_b592c338cf0df1f/how-i-built-ghostpr-turning-user-screen-recordings-into-verified-git-pull-requests-with-kiro-2828</guid>
      <description>&lt;p&gt;👻 Target Hackathon: Kiroween 2026&lt;br&gt;
 — Frankenstein Category ($100k Prize Pool)&lt;br&gt;
Mandatory Hashtags: #KiroweenHackathon26 #AWS #Kiro #Playwright #OpenSource&lt;br&gt;
Repository: &lt;a href="https://github.com/Miladmet/ghost-pr" rel="noopener noreferrer"&gt;https://github.com/Miladmet/ghost-pr&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Author: Milmann Admettre (@admettre&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;The Universal Frontend Nightmare: "Cannot Reproduce"&lt;/p&gt;

&lt;p&gt;Every frontend engineer and engineering manager has lived this scenario: A user reports an obscure bug. They upload a 20-second screen recording showing a broken checkout modal or a glitchy video canvas. The QA ticket gets created, and an engineer spends 3 hours trying to recreate the exact environment, state, and click sequence.&lt;/p&gt;

&lt;p&gt;Half the time, the ticket gets closed with the dreaded label:&lt;br&gt;
Closed: Cannot Reproduce (Works on My Machine).&lt;/p&gt;

&lt;p&gt;What if a bug report didn’t just contain a video, but automatically converted itself into a reproducible Playwright E2E test, diagnosed the codebase, patched the bug, and opened a ready-to-merge GitHub Pull Request?&lt;/p&gt;

&lt;p&gt;That is the vision behind GhostPR (AutoFix AI).&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk through how I used Kiro Desktop IDE and Spec-Driven Development to stitch together video streams, headless browser automation, and AST code healing into a unified CLI engine for the Kiroween 2026 Frankenstein Category.&lt;/p&gt;

&lt;p&gt;Why GhostPR is a "Frankenstein" Creation&lt;/p&gt;

&lt;p&gt;The Kiroween Frankenstein Category challenges developers to take seemingly incompatible, disparate components and weld them into a coherent, powerful creation.&lt;/p&gt;

&lt;p&gt;GhostPR brings together four wildly different systems:&lt;/p&gt;

&lt;p&gt;The Senses (Video &amp;amp; DOM Streams): Browser screen recordings stored on Cloudflare R2 via QuickCast.&lt;br&gt;
The Laboratory (Headless Automation): @playwright/test synthesizing deterministic TypeScript E2E specs.&lt;br&gt;
The Brain (Spec-Driven AI): Kiro steering directives enforcing invariant assertions and defensive patching.&lt;br&gt;
The Hands (Version Control): GitHub Octokit automating isolated git branch creation and verified Pull Requests.&lt;/p&gt;

&lt;p&gt;None of these tools were designed to talk to each other out of the box. GhostPR acts as the neural bridge connecting them into an autonomous, closed-loop pipeline.&lt;/p&gt;

&lt;p&gt;The Secret Weapon: Kiro Spec-Driven Development&lt;/p&gt;

&lt;p&gt;When building an autonomous tool that writes and modifies code, LLM hallucinations can be catastrophic. If an AI agent attempts to patch code without proving the bug exists first, it risks breaking unrelated features.&lt;/p&gt;

&lt;p&gt;To solve this, I built GhostPR strictly using Kiro's Spec-Driven Development paradigm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Architectural Boundaries in .kiro/steering/steering.md&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before writing a single line of JavaScript, I created .kiro/steering/steering.md. This established non-negotiable architectural guardrails:&lt;/p&gt;

&lt;p&gt;Zero Cloud GPU: All video processing must run locally via native FFmpeg binaries ($0.00/mo infrastructure cost).&lt;br&gt;
Deterministic Time Sync: Video keyframes and DOM interaction markers must be anchored to relative timestamps.&lt;br&gt;
Invariant Scoped Syntax: Playwright specs must use scoped test.step() syntax with strict DOM assertions.&lt;br&gt;
Defensive AST Patching: Patches must favor optional chaining (?.) and safe fallback states.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Formal Requirements in .kiro/specs/ghost-pr-spec.md&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I codified the 4-stage pipeline into 6 verifiable requirements (REQ-1 through REQ-6), ensuring each stage had a defined contract:&lt;/p&gt;

&lt;p&gt;REQ-1: Ingest .webm stream from Cloudflare R2 without cloud GPU compute.&lt;br&gt;
REQ-2: Extract 4 visual keyframes and parse interaction telemetry.&lt;br&gt;
REQ-3: Synthesize tests/repro_.spec.ts.&lt;br&gt;
REQ-4: Search target repository AST for error tokens.&lt;br&gt;
REQ-5: Apply defensive patch and verify green execution.&lt;br&gt;
REQ-6: Create Git branch fix/ghost-pr- and dispatch Pull Request.&lt;br&gt;
How Kiro IDE Caught 4 Critical Architectural Gaps&lt;/p&gt;

&lt;p&gt;One of the most impressive moments during development was when I loaded GhostPR into Kiro Desktop IDE and ran an architectural audit.&lt;/p&gt;

&lt;p&gt;Kiro didn’t just check for syntax errors; it analyzed the entire dataflow against our steering directives and identified 4 subtle architectural gaps:&lt;/p&gt;

&lt;p&gt;The "Disconnected Execution" Gap (Critical):&lt;br&gt;
synth-test.js was generating the Playwright spec, but had hardcoded failureConfirmed: true without actually executing Playwright. Kiro pointed out that our self-healing loop was asserting a false positive:&lt;/p&gt;

&lt;p&gt;"Stage 2 is asserting a lie. REQ-5 depends on running the test to confirm red state before diagnosing."&lt;/p&gt;

&lt;p&gt;The Fix: We wired executePlaywrightSpec() directly into synthesizeTest(), setting failureConfirmed: !execResult.passed.&lt;/p&gt;

&lt;p&gt;The Late pageerror Listener:&lt;br&gt;
The error trap was declared inside a test.step() block after page.goto(). Kiro caught that any exception thrown during initial page boot or hydration would be missed.&lt;/p&gt;

&lt;p&gt;The Fix: Hoisted the listener to the very top of the test body before navigation:&lt;/p&gt;

&lt;p&gt;typescript&lt;br&gt;
test('Autonomous E2E reproduction and state verification', async ({ page }) =&amp;gt; {&lt;br&gt;
  // Hoist error trap BEFORE navigation to capture boot &amp;amp; hydration exceptions&lt;br&gt;
  const pageErrors = [];&lt;br&gt;
  page.on('pageerror', err =&amp;gt; pageErrors.push(err.message));&lt;br&gt;
  await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });&lt;br&gt;
  ...&lt;/p&gt;

&lt;p&gt;CWD Relative Path Drift:&lt;br&gt;
Normalized all input and output paths upfront with path.resolve() so GhostPR runs identically from any working directory.&lt;/p&gt;

&lt;p&gt;Stale Script Cleanup:&lt;br&gt;
Removed a dead "start": "node src/server.js" entry in package.json and pointed it directly to src/cli.js.&lt;/p&gt;

&lt;p&gt;After these 4 fixes were applied, Kiro inspected the codebase again and delivered the official sign-off:&lt;/p&gt;

&lt;p&gt;"GhostPR is ready for competition submission. The red-to-green self-healing loop is now genuinely closed."&lt;/p&gt;

&lt;p&gt;The 4 Stages in Action: A 30-Second Walkthrough&lt;/p&gt;

&lt;p&gt;Here is what happens when you run a single CLI command:&lt;/p&gt;

&lt;p&gt;bash&lt;br&gt;
node src/cli.js --session "qc_bt6mrt8n" --repo "./" --dry-run&lt;br&gt;
Stage 1: Zero-Cloud-GPU Visual Ingestion&lt;/p&gt;

&lt;p&gt;GhostPR streams the .webm recording from Cloudflare R2 and extracts visual keyframes at key intervals using local FFmpeg binaries. It parses embedded interaction markers—capturing the exact DOM targets clicked and input values entered.&lt;/p&gt;

&lt;p&gt;Stage 2: Autonomous Playwright Spec Synthesis (Red State)&lt;/p&gt;

&lt;p&gt;GhostPR generates tests/repro_qc_bt6mrt8n.spec.ts. It immediately runs the spec in headless Chromium. Because the unpatched bug exists, Playwright fails—confirming that the test genuinely reproduces the failure.&lt;/p&gt;

&lt;p&gt;Stage 3: AST Diagnosis &amp;amp; Defensive Patching (Green State)&lt;/p&gt;

&lt;p&gt;With the exact error message and failing selector in hand, GhostPR scans the codebase, locates the offending line, and synthesizes a defensive AST patch (e.g. shielding null pointer exceptions with optional chaining).&lt;br&gt;
It reapplies the Playwright test. The test passes green.&lt;/p&gt;

&lt;p&gt;Stage 4: Verified Git Pull Request Dispatch&lt;/p&gt;

&lt;p&gt;GhostPR checks out an isolated branch (fix/ghost-pr-qc_bt6mrt8n), commits the reproduction test and the patch, and uses Octokit to open a GitHub Pull Request with the video keyframes and Playwright test proof embedded in the PR description.&lt;/p&gt;

&lt;p&gt;Key Takeaways from Building with Kiro&lt;br&gt;
Spec-Driven Development Prevents AI Drift: Defining .kiro/steering/steering.md upfront acted as an architectural anchor. Whenever I asked Kiro to review or refine code, it evaluated changes against our specifications rather than hallucinating new patterns.&lt;br&gt;
Local-First is Faster and Cheaper: By keeping FFmpeg and Playwright local, GhostPR incurs $0.00/month in cloud compute costs and executes complete bug reproductions in under 25 seconds.&lt;br&gt;
Closing the Loop Matters: AI that generates code without running tests is just an expensive auto-complete. GhostPR's superpower is the Red-to-Green verification loop—it never submits a PR unless the synthesized test fails first and passes after.&lt;br&gt;
Try GhostPR &amp;amp; Explore the Code&lt;/p&gt;

&lt;p&gt;GhostPR is fully open-source under the MIT License:&lt;/p&gt;

&lt;p&gt;🐙 GitHub: &lt;a href="https://github.com/Miladmet/ghost-pr" rel="noopener noreferrer"&gt;https://github.com/Miladmet/ghost-pr&lt;/a&gt;&lt;br&gt;
📜 Kiro Steering &amp;amp; Specs: Explore .kiro/steering/steering.md&lt;br&gt;
💡 Hackathon Entry: Kiroween 2026 Devpost&lt;/p&gt;

&lt;p&gt;Built by Milmann Admettre for Kiroween 2026.&lt;/p&gt;

</description>
      <category>kiroweenhackathon26</category>
      <category>aws</category>
      <category>kiro</category>
      <category>playwright</category>
    </item>
  </channel>
</rss>
