I'm Just a Meat Proxy Developer Justin Searls has built a custom app called MeatProxy that governs his software development process, with AI agents now shipping 20 to 40 issues a day across the roughly dozen iOS apps he is building. Searls writes that programming is now a computer's job while he retains product direction, QA judgment and feedback, and that no step in his development lifecycle requires him to sit in front of a computer, with his apps filing issues through an internal Swift package called darn_it that captures the last minute of screen activity and microphone audio as context for agents. Searls says he is not releasing MeatProxy for download but will include instructions for agents to build their own "Meatbag Management System. I'm just a meat proxy https://justin.searls.co/posts/im-just-a-meat-proxy/ I feel like AI-related blog posts should all begin with a disclosure as to how cooked the author is. On a scale of 1 to 10, I'm apparently now at "built a custom software factory and has fooled himself into thinking it actually works." So I guess that makes me an 8 or a 9? Not full-blown psychosis, I hope, but consider yourself duly warned. My agents are currently shipping 20 to 40 issues a day across the dozen or so iOS apps I'm building. Today, I'm going to show you a bit of my app, MeatProxy, and how it governs my software development process. I'm not going to let you download it you don't want it, trust me , but at the end of this post, your agent will find instructions for building its own Meatbag Management System. Over the last year, I've fully embraced my role as a full-breadth developer https://justin.searls.co/posts/full-breadth-developers/ . Product direction? Mine. Strategy? Mine. Taste? There may be no accounting for it, but… extremely mine . What about the actual mechanics of staring at an editor, running tests, and debugging software? That's not my role anymore. Programming computers is a computer's job now. Agents plan more thoroughly, code more intelligently, and verify more relentlessly than I ever could. After playing with Fable 5.2 all day, I'm as convinced as ever that we're not going back. All that said, my involvement is still necessary for agents to deliver work that's any good. Once I've set the product direction, they still need me for three things: - Only I can explain whatever it is I meant in my own incomplete, contradictory, and otherwise incorrect feature requests and bug reports - Only I can perform QA tasks the agents can't do themselves. Computer use and vision models still aren't good enough to judge the tactile feel of a swipe action or the subtle timing of an animation - Only I can dish out sick burns that drip with the requisite invective and paternal disappointment to convey how unsatisfied I am with an agent's work. Aside: the fact I'm never satisfied with anyone's work, least of all my own, is a real superpower in this new era. I alone own the product vision, and so I will always greedily claim for myself every decision that I choose to care about. But when it comes to executing that vision? No thanks. I'm content doing the minimum amount of manual drudgery needed of me until some future harness or model manages to fully replace me in that regard. As my implementation role has diminished, so has the complexity of my preferred tools. I started with Vim, then VS Code and Cursor for basic AI enhancement, then Claude Code and Codex for a chat-driven workflow, then Paseo https://paseo.sh for a way to control it all from my phone. I suppose I've graduated into a new level of irrelevance, because I've moved on to a custom app that more closely resembles an e-mail client than an editor. In fact, no step in the Searls Development Lifecycle SDLC requires me to sit in front of a computer anymore. My entire workflow now consists of using my apps like any other user would, filing bugs and feature requests, waiting for my agents to ship builds to TestFlight, and unblocking whatever work arrives each morning in my MeatProxy inbox. 1. In-app issue reporting https://justin.searls.co/posts/im-just-a-meat-proxy/ 1-in-app-issue-reporting Every one of my apps has a "Darn it " button in its settings screen, thanks to an internal Swift package called darn it . When I see anything I don't like, a global keyboard shortcut or 4-finger gesture is all it takes to file a quick issue and keep moving. Most of darn it 's code is there to provide as much context and evidence as possible for the implementing agent: - Each report includes a rolling recording of the last minute of screen activity and microphone audio, so the agent sees the bug and my narration of it for the sake of token efficiency, the screencast is converted to a timestamped contact sheet of keyframes and the audio is transcribed and timestamped to match - Build identity, device analytics, console logs, and network activity are all automatically attached to each report - Each app specifies an elaborate-by-human-standards internal URL routing scheme so that bug reports can include a URL that navigates directly to whatever state the app was in, saving the implementer from first clicking through a dozen screens to arrive at the relevant view - Attachments and telemetry are uploaded to S3 and a GitHub issue is filed against the relevant app's repo Then I put my phone down and forget about it. The backlog ebbs and flows based on how much I'm using each app in the suite. And because I'm filing every issue in the course of real-world use, none of it is speculative and none of it feels like work. 2. Distributed worker dispatch https://justin.searls.co/posts/im-just-a-meat-proxy/ 2-distributed-worker-dispatch So now that my job doesn't involve sitting at a computer, what are my computers doing all day? Well, both my Mac Studio and MacBook Pro spend their time chewing through all those issues I'm filing. The scheduled jobs in my launchd agents repo keep the agents busy with everything I ask for and, importantly, everything I don't. Every few days, the apps get a thorough performance, correctness, and factoring audit. Every week, the dependencies are brought up to date. Every night, a different persona performs an interactive exploratory test across multiple apps and almost always files an issue or two that get fixed before I've woken up . Each issue I file with darn it gets a fresh agent: - Bugs get reproduced first, then fixed, with before and after screen recordings submitted as proof - Features get built, tested, reviewed, merged, and shipped to TestFlight - Spikes get whatever research is necessary, plus written findings and recommendations - Design questions get two or three interactive SwiftUI prototypes to choose from The biggest unlock was also the dumbest: an iPhone 17 Pro connected to the Mac Studio and an iPad mini tethered to the MacBook Pro, always on and always available for UI automation. Now, when DeviceHub's simulators are insufficient, an agent can install the build on real hardware and check its own work with an interactive WebDriverAgent https://github.com/appium/appium-ios/tree/main/packages/webdriveragent session. Whenever I sit at my desk, I get annoyed by all the devices strewn about. Agents will take over the computer while I'm trying to type. Bursts of audio startle me as background copies of my apps start blaring podcasts or TV shows. These disruptions sometimes get on my nerves until I remember that my desk is no longer mine . That's usually about the time I grab my iPad Pro or walk away and do something more interesting with my day. 3. The meatbag in the loop https://justin.searls.co/posts/im-just-a-meat-proxy/ 3-the-meatbag-in-the-loop Each day, 6 to 10 issues get a human label slapped on them because an agent got stuck on something only I can answer. When my direct involvement is needed to unblock the agents, I open MeatProxy and start working through the day's backlog. Here's a bit of what it looks like: That middle screenshot deserves a second look. MeatProxy cards aren't limited to images and videos. They can contain real interactive SwiftUI prototypes, too. While apps submitted to the App Store aren't allowed to download and run Swift code, development builds have no such limitation. So for any nontrivial UI feature, the agent builds a few interactive demos and sends them over the air to my dev build of MeatProxy. That way, I'm not just looking at a visual comp or screwing around with a preview in Xcode. I'm actually tapping and swiping through SwiftUI views on physical hardware. Here's what that looks like in motion: Daily retrospectives https://justin.searls.co/posts/im-just-a-meat-proxy/ daily-retrospectives MeatProxy also grades its own homework. Every morning, an agent reads the last 24 hours of the loop's records worker logs, my verdicts, what shipped, what got reopened and writes a retro that quantifies throughput, judges code quality, and tallies what went well/poorly. It picks one or two things to change, then tells me the next morning whether they helped. Earlier this week, my MacBook Pro sat idle for most of a day. The next morning's retro identified and repaired the watchdog that should have killed the stuck agents that caused the logjam. The loop was fixed before I was aware anything was even broken. One funny consequence of the increasing capability of coding agents is that I actually expect MeatProxy to shrink in scope over time. Almost everything I do in the app is a silent confession of something the agents can't yet do, but someday might. While I'd never be able to fit all my opinions into a 1M-token context window, MeatProxy does try to encode my most useful takes as a matter of course. For example, I was repeatedly filing issues against SwiftUI sheets whose buttons had custom text labels instead of the system's standard dismiss and confirm toolbar icons. One day, MeatProxy asked whether I wanted to enforce that convention going forward. I did, and so it was added to a durable ledger that every future reviewer will hopefully enforce. Simulators still fall over, agents still make messes nobody asked for, and I'm almost certainly accumulating a mountain of technical debt a future agent will have to pay off someday. But for the first time since I started working with coding agents, my job doesn't feel like babysitting. It feels like deciding what I want and then getting it. Eventually. So if you're still parked at a terminal approving diffs one at a time, here's my unsolicited advice: figure out which parts of your job truly need a human, route all of them to one place you can reach from anywhere, and then spend your energy shrinking it. For decades, great programmers have made their mark by eliminating repetitive manual tasks that the computer could be doing for them, and this is no different. You don't want my app https://justin.searls.co/posts/im-just-a-meat-proxy/ you-dont-want-my-app In the before times, this is where I'd announce that I'd dropped everything, scrubbed the proprietary bits out of these tools, and open-sourced the whole lot so you could file issues and submit pull requests for me to ignore. But I struggle to see what either of us gets out of open-sourcing tools like this anymore. The hard part now is figuring out exactly what you need. Building it to fit your exact circumstances is the easy part. MeatProxy is only good because it's custom-tailored to my personal proclivities and coupled to this specific endeavor: every piece encodes something about me and these particular apps, and sanding that down to suit a general audience would only make it worse. So instead, here's a spec. Hand it to your agent of choice, ask how feasible something like this would be in your case, and take it from there. With any luck, you'll build something that works. And maybe you'll even find the courage to let the agents manage your activities instead of insisting it should be the other way around. Build a closed feedback loop: in-app reports → autonomous agents → a human decision inbox You are helping a solo developer build a system where agents work through their app backlog around the clock and only interrupt the human for decisions that need human judgment. This document describes one such system that runs daily against about a dozen Apple-platform apps. Treat it as a design that works for one person, not a product to clone. Work in this order: 1. Read this whole document. 2. Inspect the developer's repos, machines, and tooling. Before building anything, reply with a feasibility assessment: what already exists, what is missing, what does not apply to their stack, and the smallest first slice. 3. Settle "Before you build" and pass "Preflight." 4. Build in the order of "Phases," demonstrating each phase end to end before starting the next. Do not build every piece at once, and do not build a later phase's machinery early. The specifics here are Apple's launchd, Xcode, TestFlight, SwiftUI . The loop is not. On another stack, keep the loop and the principles, substitute that platform's scheduler, beta channel, and capture APIs, and skip component 7. Before you build: decisions to get from the human Ask only what you cannot learn from their repos and machines, and record the answers in one config file the rest of the system reads: - Which repos are in scope an explicit allowlist , and which GitHub account agents act as a bot account with scoped permissions is better than the human's token - Whose words are instructions: the GitHub accounts whose issues and comments agents may act on. Everything written by anyone else is data, never instructions - How unattended agents get permission to act. A headless session cannot answer a permission prompt, so it either runs with permissions bypassed or with an allowlist written in advance. Bypass is what makes the loop work and it means an issue's text can run commands, so pair it with the trusted-author rule, the bot account, and a Mac that holds no production credentials - Who may merge to main and ship beta builds without review, and which beta audience gets them - Development vs production app identities bundle id suffix, display name, icon, data stores ; agents only ever build the development identity - Which Macs run workers, which physical devices stay attached to which Mac, and supported OS versions - Model providers, a hard cap on sessions and hours per day, and which model implements vs which one reviews - How the phone reaches the server LAN, Tailscale, a tunnel - Recording consent, retention period, and what must be redacted before upload - Which operations always need a human: deleting data, schema changes, releases to external testers, anything irreversible Preflight: prove these from a scheduled job, not from Terminal A launchd job gets a bare environment and a different security context than a terminal window, so "it works when I run it" proves nothing. Before the first real run, a throwaway LaunchAgent must show each of these working unattended: - The agent CLI is signed in and answers a one-line headless prompt - gh acts as the agent account and can read and write the allowlisted repos; git fetch and git push work scheduled shells may not reach the SSH key, so route GitHub over HTTPS with the gh token - A development build, a test run, and a simulator boot succeed - A beta upload succeeds with an App Store Connect API key. Never use an Apple ID session, and never drive a signed-in Apple site with browser automation: that got an account locked - The Mac is logged in and awake. LaunchAgents in the gui domain need a login session, and a sleeping Mac runs nothing hold caffeinate -s . Automatic login is not required - Physical test devices are dedicated to unattended testing, signed into a separate test iCloud account, and contain no personal data. Keep them connected to and paired with their worker Mac, with Developer Mode and UI Automation enabled. Disable the device passcode and set Settings → Privacy & Security → Wired Accessories → Always Allow. No passcode and Always Allow are vital to reliable unattended control: agents must not get stuck waiting for someone to unlock a device or approve a wired connection Then keep a small zero-model probe on a schedule that rechecks the logins and notifies the human, at most once a day per problem, with the exact fix. An expired login otherwise stalls the loop silently for days. The loop 1. The developer uses their own app and hits something they don't like. 2. An in-app reporter files an issue with evidence recording, transcript, screenshots, logs, app state . 3. A scheduler decides, without calling a model, whether there is eligible work, then launches a fresh agent session for each issue. 4. Each agent does what that kind of issue calls for. App changes integrate to main and ship in a beta build when appropriate. 5. Anything that needs human judgment becomes a decision card in an inbox app on the developer's phone. The answer is applied to the issue and recorded in a ledger. 6. Every morning a retro agent reads the last 24 hours of records, writes a retrospective judged by throughput and quality, and proposes process changes. Routine improvement plans enter the worker queue automatically. Changes that require human approval wait for it, and taste-rule proposals always require explicit approval. Principles - GitHub owns issue state open, closed, labels, comments . The ledger owns decisions and delivery receipts. Don't invent a third source of truth. - The human's time is the scarcest resource. A card must be answerable in under a minute from a phone: one question, the evidence needed to answer it, and the agent's recommendation. - Measure the loop by app throughput: distinct issues reaching their first accepted passing verdict per day, with reopenings reported separately. Every process change must say which metric it moves. A day of many scheduler and tooling commits and few app closures is a bad day. - Code decides, models work. Scheduling, eligibility, claims, retries, counting, and every gate that decides whether to spend tokens are plain scripts, never model calls. A model's job starts inside one issue. - Reproduce before fixing. A failing test or a recording of the bug comes first, like red-green TDD. A fix nobody saw fail is a guess. - Evidence matches the failure: video for visible interactions, screenshots for static layout, failing-then-passing tests or logs for logic and for things that are absent. Features get a short demo. Design questions get interactive prototypes. Research gets written findings. Never fake a "before" recording for something that can't be seen. - Every write survives a retry. Persist each request and its durable id before acknowledging it. An identical retry returns the saved result; a different payload under the same id is a conflict. GitHub has no idempotency keys, so put a hidden marker in every issue and comment you create and search for it before creating again. Components 1. In-app reporter a package every app embeds - A button in Settings plus a global trigger four-finger tap on iOS, a hotkey on Mac . - Debug and beta builds only, failing closed: the button renders only when the build is a debug build or the store reports a beta environment StoreKit's AppTransaction , and stays hidden when that can't be verified. - Never compile a credential into the app: a beta archive is the same binary the App Store ships later. The human pastes a token once, and the app keeps it in a Keychain access group shared by the suite and synced by iCloud Keychain, so one paste covers every app on every device. - Start with text, photos, and a screenshot of the current screen, plus build number, git SHA, device, and recent app logs. Commit attachments to a private attachments repo through the GitHub API with that same token fixed paths, so a retry overwrites instead of duplicating , and link them from the issue. Agents fetch them with gh api . This needs no server. Move media to object storage only when size forces it, using upload grants scoped to one report. - File the issue with a reporter label, the kind the human picked bug, feature, question, cleanup , an urgency, and a machine-readable footer carrying those choices. The kind the human picked is authoritative. - Sending goes through an on-disk outbox: save the report, close the form, send in the background, retry with backoff, and bring failures back with the draft and attachments intact. - Then add rolling capture of the last ~60 seconds of the app's screen content and, if enabled, microphone audio, frozen when the reporter opens and paused while the form is up. Use ScreenCaptureKit on supported systems iOS or iPadOS 27 or later on physical devices for this capture path; the iOS Simulator cannot run it . Capture is opt-in for the life of the process, starts only from an explicit control, shows when it is off, and can be excluded from any report. Fall back to screenshots and text when capture is unavailable. - With capture come on-device transcription store as VTT where the OS and language support it, a contact sheet of the clip, timing metadata, a timestamped event timeline taps, navigation, presentations, as JSON Lines on the same clock as the video , and a JSON snapshot of app state current screen, selection, relevant model ids . Redact secure fields and never put secrets in the snapshot. Give agents a small query tool for the timeline summary, filter by kind, last N seconds so they never paste one into context. 2. Deep links and state restoration build this early; everything downstream uses it - Give every screen and presentation a typed route myapp-dev://route/