# Vinny Carpenter — Full Content > This file provides expanded content for AI agents that want deeper context about this site. ## The Book — The Bottleneck Is Never the Stack - **Subtitle:** Building Software and Organizations in the Agentic Era - **Released:** August 7, 2026 - **URL:** https://vinny.dev/book/ - **Buy:** https://amzn.to/4fVFkVU Execution got cheaper. Clarity did not. AI did not create the real bottleneck in software. It made the old one impossible to hide. This book grew out of a year of essays at https://vinny.dev and gathers them into one argument about specs, systems, judgment, and leadership when AI agents join the software delivery system. --- ## Your Agent Is Bad for Their Business - **Published:** 2026-10-25 - **Tags:** ai-economics, platform-engineering, engineering-leadership - **URL:** https://vinny.dev/blog/2026-10-25-your-agent-is-bad-for-their-business/ In September I gave Muse, Meta's personal agent, access to my inbox and asked it to find subscriptions we weren't using. It flagged Chegg and Quizlet. Nobody in the house was using either anymore, and it recommended canceling both. As I wrote in [The Return of the Personal Agent](https://vinny.dev/blog/2026-10-01-the-return-of-the-personal-agent/), it left the cancellations to me. What stayed with me was the direction of the recommendation. The useful outcome was a payment I could stop making. An agent working for me had just found revenue somebody else was about to lose. On September 20, 12 days after [Muse launched](https://about.fb.com/news/2026/09/introducing-muse-personal-ai-agent/), [Amazon blocked it](https://www.geekwire.com/2026/amazon-blocks-metas-muse-ai-assistant-in-new-standoff-over-agentic-shopping/). On October 22, [Reuters reported](https://www.reuters.com/legal/government/us-banks-detect-unauthorized-ai-agents-customer-accounts-axios-reports-2026-10-22/) that major U.S. banks were blocking third-party agents from operating inside customer accounts and making transactions. Both companies raised security concerns, and I take them seriously; I'll come back to them. But I'm the kind of engineer who signs up for a new agent the week it ships. I've used five personal agents since the spring and built one of them myself. Putting a technology to work for me is how I understand what it does to everyone else. Five agents in, the pattern that keeps showing up is this. > A company's agent policy tells you where its margin lives. > Businesses that earn from the customer's attention will block the agent. > Businesses that earn a fee on each transaction will let it in, as soon as it shows identification. > Banks sit between the two, and they're the case where the security argument carries the most weight on its own. That rule explains Amazon, the banks, and the card networks, and it explains why Walmart made the opposite call from Amazon in the same week. It doesn't tell you why one particular agent got blocked, and an agent that passes every security check can still threaten a business model. The test for telling those apart comes at the end. ## Amazon is defending more than the checkout A storefront does several jobs at once. It helps me find a product, gives me reasons to trust the seller, and tries to influence what else I buy. Each of those jobs is a place to earn money. Amazon's [2025 results](https://ir.aboutamazon.com/news-release/news-release-details/2026/Amazon-com-Announces-Fourth-Quarter-Results/) show $68.6 billion in advertising revenue, most of it sponsored placements inside search results, alongside the business of selling and delivering products. If I ask an agent to compare three products against a budget and a set of requirements, the selection can happen before I reach the retailer. Amazon might still get the order and lose its influence over the choice. That mechanism is narrower than "the agent skips the ads." An agent can land on a sponsored listing and follow the same unhelpful recommendation a person would; browser automation doesn't make it immune to persuasion. And not every visit produces an impression the retailer can bill, because Amazon's [Sponsored Products are priced per click](https://advertising.amazon.com/solutions/products/sponsored-products). What matters is where the decision happens. When the agent decides upstream, the retailer has fewer chances to redirect the customer before checkout. ![Two paths to the same purchase: a person at the shelf moves through search results, sponsored listings, the product page, frequently bought together, and a Prime upsell before checkout; an agent that decided upstream opens the product page, checks the price and reviews, and buys.](/images/blog/2026/10/bad-for-business-what-the-agent-skips.png) Amazon's stated objections to Muse were specific. It said the agent didn't identify itself and appeared to capture and store customer credentials. [Meta says](https://about.fb.com/news/2026/09/introducing-muse-personal-ai-agent/) credentials go into secure storage that Muse can use without seeing the passwords. Keeping a password out of the model's view is useful, but it doesn't settle what authority the service should have inside someone else's platform. Judge Maxine Chesney put that distinction into a court order in March, when she [granted Amazon a preliminary injunction](https://www.geekwire.com/2026/judge-blocks-perplexitys-ai-bot-from-shopping-on-amazon-in-early-test-of-agentic-commerce/) against Perplexity's Comet browser. Comet accessed Amazon accounts with the user's permission, but without authorization by Amazon. I argued the same thing from the platform side in [The Agent Is Wearing Your Badge](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/). An agent acting on your credentials needs an identity of its own. In August the [Ninth Circuit vacated that injunction](https://cdn.ca9.uscourts.gov/datastore/opinions/2026/08/04/26-1444.pdf). On the facts before it, the court found Amazon unlikely to show that Perplexity itself had accessed Amazon's computers under the federal anti-hacking law. It treated the user as the one accessing the site, with help from the tool. That didn't establish an unrestricted right of access for every agent. On September 10 the court [denied rehearing](https://ppc.land/amazon-blocks-metas-muse-ai-agent-from-shopping-on-its-site/). Ten days later, Amazon blocked Muse anyway, through its Conditions of Use rather than a courtroom. ![Timeline from November 2025 to October 2026: Amazon sues Perplexity over Comet, Judge Chesney grants Amazon an injunction, the Ninth Circuit vacates it, Meta ships Muse, rehearing is denied, Amazon blocks Muse, Meta announces Walmart, Best Buy, and Sephora connectors, and five banks block agent logins.](/images/blog/2026/10/bad-for-business-timeline.png) Amazon is not against agents, though. It ships [Rufus and Buy For Me](https://www.geekwire.com/2026/judge-blocks-perplexitys-ai-bot-from-shopping-on-amazon-in-early-test-of-agentic-commerce/), two shopping agents of its own. Andy Jassy [said in November](https://decrypt.co/360629/amazon-perplexity-comet-court-order-agentic-commerce) that agentic commerce "has a chance to be really good for e-commerce." Amazon is against agents it doesn't operate, inside a store where it sells the shelf. The legal boundary matters, and so does the question a court can't answer: under what terms would Amazon want an independent agent to help its customers shop? ## Walmart has a shelf to defend, too At Connect, four days after Amazon's block, Meta [announced more Muse connectors](https://about.fb.com/news/2026/09/the-biggest-news-from-connect-2026/), including Walmart, Best Buy, and Sephora. The same agent gets a connector from one retailer and a pop-up from the other. It's tempting to explain this as Amazon protecting advertising while Walmart pursues sales. But Walmart sells advertising too. Its global ad business reached [nearly $6.4 billion in fiscal 2026, including VIZIO](https://stock.walmart.com/sec-filings/all-sec-filings/content/0000104169-26-000032/earningsreleasefy26q4.htm). The difference is the tradeoff each retailer faces. An agent can bring a merchant a customer it wouldn't otherwise reach, while moving part of the shopping experience outside that merchant's control. Walmart has more to gain from another route into the customer's decision. Amazon has more of that decision already happening inside its store. That's an explanation to test rather than a disclosed calculation from either company, and it predicts that access will change as the economics change. A retailer can welcome discovery through an agent while insisting on its own checkout, data, and payment arrangements. Google's [Universal Commerce Protocol](https://developers.googleblog.com/under-the-hood-universal-commerce-protocol-ucp/), which Walmart, Target, and Wayfair helped develop, makes that negotiation concrete: the retailer keeps its business logic and stays the merchant of record. A negotiated connector is a different proposition from an unidentified browser operating inside a customer account. What a retailer is deciding is how much control it keeps when it lets the agent in. Demand is pushing from the other side. Muse reached [No. 1 on Apple's App Store](https://www.cnbc.com/2026/10/21/anthropic-preview-of-claude-duet-personal-ai-agent-take-on-muse-dots.html) about a week after launch, and Adobe Analytics measured a [393% year-over-year rise](https://decodo.com/blog/agentic-commerce-ai-shopping-agents) in AI referral traffic to U.S. retail sites in the first quarter. Blocking an agent that popular is a bet that customers keep coming anyway, and Amazon is the only retailer with the position to make it. ## At the bank, the security case is the strongest of the four A bank account makes the risk harder to dismiss. Reading a balance and moving the money are different grants of authority. An agent needs to know what the customer permitted, what cash has to stay available, and when to ask again. A mistaken transfer creates problems that an unwanted product recommendation doesn't. Sharing credentials complicates responsibility when an agent does something the customer didn't intend; the [consumer-protection rules](https://www.consumerfinance.gov/rules-policy/regulations/1005/2/) turn on actual authority and its exceptions, so account access alone doesn't settle liability. The banks' line follows that distinction. JPMorgan allows view-only access through Plaid, and Citi allows it through approved open-banking providers; what both block is logging in and moving money. On JPMorgan's [third-quarter call](https://www.jpmorganchase.com/content/dam/jpmc/jpmorgan-chase-and-co/investor-relations/documents/quarterly-earnings/2026/3rd-quarter/3q26-earnings-transcript.pdf), Jamie Dimon said the firm is "not against agents or for agents," that it uses them internally, and that it won't let just any outside agent inside the company. Part of his reason was that there could be thousands of them going rogue. Of the four companies in this essay, that's the most reasonable position on an unidentified agent, and the one with the most at stake if it's wrong. The economics are no secret, because JPMorgan stated them on the same call. Dimon described net interest income on idle balances as one of the ways the bank pays for banking services. If that income went away, he said, the firm would do something different over time, such as subscriptions or accounts that bundle investments with checking. CFO Jeremy Barnum went further: a bank shouldn't be hoping its deposits are stable because the money is difficult to move. Amazon never said anything that plain about its shelf. That candor points at the consequence I find more interesting than a story about banks protecting their spread. An agent that regularly finds surplus cash and compares alternatives will make low-cost deposits less dependable. When that revenue goes, the cost of providing the service doesn't go with it. Some of it becomes a fee the customer can finally see and compare, which is the outcome Dimon described and the one I'd prefer. I'd welcome an agent that helps me make that comparison. I'd also expect it to understand why the money is in the account. Optimizing a balance without understanding the bills it has to cover would be an efficient way to create a new problem. ## The payment networks want a trusted transaction Visa and Mastercard start somewhere else. A transaction that runs on their network supports their business whether a person or an agent initiated it. They have every reason to make delegated payments work, provided they can manage the risk. Visa's [Trusted Agent Protocol](https://usa.visa.com/about-visa/newsroom/press-releases.releaseId.21716.html), developed with Cloudflare, helps merchants recognize approved agents and receive information about their intent; Visa cited a 4,700% surge in AI-driven traffic to U.S. retail sites as the reason to build it. Mastercard's [September expansion of Agent Pay](https://www.mastercard.com/global/en/news-and-trends/press/2026/september/new-trust-and-intelligence-services.html) combines agent identity with intent, behavioral, and fraud signals to support authorization decisions, with a Know Your Agent layer built with Skyfire. These are efforts to make the transaction acceptable to everyone involved. Identifying the agent is one part of the work; establishing what the customer authorized, enforcing limits, and handling failures are separate parts. The contrast with the banks is useful without being the whole explanation. Banks earn transaction revenue too, and the networks also have to contain fraud. What differs is each company's exposure to a particular agent action, and that exposure follows the margin. ![Four companies, one rule: Amazon earns on the shelf and blocked Muse; five big banks earn on deposits and allow reading while blocking transactions; Visa and Mastercard earn a fee on every transaction and built an ID check; Walmart has share to take and let the agent in.](/images/blog/2026/10/bad-for-business-four-cases.png) ## Some of what the agent skips still needs funding Tailwind is the case that brings this closest to my own work. This site runs on it, and I've shipped hundreds of Tailwind pages since January. I benefit from a framework whose usefulness and commercial success turned out to be different things. In January, Adam Wathan [reported](https://github.com/tailwindlabs/tailwindcss.com/pull/2388) that traffic to the documentation had fallen about 40% from early 2023 and revenue was down close to 80%. He had laid off three of the company's four engineers. The docs had been the route into the paid products, and AI coding tools now write Tailwind classes without anyone opening tailwindcss.com. Wathan disclosed the layoffs while declining a pull request that would have packaged the docs as a single file for AI consumption. Making them easier for agents to read would have made the storefront emptier. His numbers don't separate the docs effect from other changes in demand, but they show why growing adoption wasn't enough to sustain the business. On September 9, [Tailwind Labs joined Shopify](https://tailwindcss.com/blog/tailwind-is-joining-shopify). The framework had passed 110 million weekly installs. The open-source projects stay MIT-licensed, the team keeps maintaining them, and new sign-ups for Tailwind Plus and ui.sh closed. In March I wrote [Dark Fiber, Bright Future](https://vinny.dev/blog/2026-03-11-dark-fiber-bright-future/) about cable that outlived the companies that laid it. Tailwind's docs outlived Tailwind Labs the same way: the framework got an institutional home, and the independent business around it stopped. Scale that up and you get Cloudflare's numbers. In June its CEO, Matthew Prince, said bots had passed humans for the first time, at [57.5% of HTML traffic](https://www.digitalapplied.com/blog/ai-crawler-bot-traffic-statistics-2026-data-reference). Cloudflare Radar's crawl-to-refer ratio counts how many pages a platform crawls for every visitor it sends back. For [July](https://ecorpit.com/ai-crawler-crawl-to-referral-ratio-2026-geo-decision/), Google sat at 4.7 to 1, OpenAI at 251 to 1, Perplexity at 289 to 1, and Anthropic at 1,917 to 1, down from roughly 24,000 to 1 in the first quarter. I use Claude every day, so I'll note that its crawler has the worst exchange rate on the list even after improving by an order of magnitude. Search was an exchange: Google crawled your page and sent you a reader. An AI platform answers the reader itself. ![Cloudflare Radar crawl-to-refer ratios for July 2026 on a log scale: Google 4.7 to 1, OpenAI 251 to 1, Perplexity 289 to 1, Anthropic 1,917 to 1, down from roughly 24,000 to 1 in the first quarter.](/images/blog/2026/10/bad-for-business-crawl-to-refer.png) A crawler reading public documentation and an agent moving money carry different authority and risk. The shared economic question is who pays for useful work when the old route to the customer weakens. Cloudflare is trying one answer. Its [Pay Per Use beta, launched September 30](https://blog.cloudflare.com/pay-per-use/), lets publishers accept offers for specified downstream uses of their content, alongside Pay Per Crawl, which charges for access. The arrangements still have to prove they produce returns worth accepting. Documentation, reporting, and product information need continuing work. If agents help people bypass the visits that funded that work, somebody has to pay for its replacement. Better access today is a poor bargain if the information stops being maintained tomorrow. ## The agent can become the new shelf This is where my enthusiasm for personal agents needs its own scrutiny. I want an agent that compares options according to my preferences. I'm also relying on a company to decide which options it can see, which merchants it can reach, and how recommendations get ranked. Moving the decision out of Amazon doesn't guarantee it belongs to me. It can move into the agent provider's product, where another set of defaults and commercial relationships shapes it. Look at who is building the agents. Meta reported [$200.97 billion in revenue for 2025](https://www.quantumrun.com/consulting/meta-statistics/), and $196.18 billion of it was advertising. Alphabet's [revenue passed $400 billion](https://www.sec.gov/Archives/edgar/data/0001652044/000130817926000344/goog014907-ars.pdf), and the company guided to $195 billion to $205 billion in capital spending for 2026, more than double the year before. Gemini Spark is one of the things that money buys. The companies that built the attention economy are the ones shipping agents that promise to route around it, and none of these products is a charity. Meta, for its part, [says Muse doesn't share](https://about.fb.com/news/2026/09/introducing-muse-personal-ai-agent/) conversations or the data in its virtual machine with Meta's advertising systems. That's a useful privacy commitment. How the agent selects and ranks recommendations is a separate question. I still want to know how the agent is funded and how that shapes the work. Can it recommend a merchant that has no agreement with its provider? Will it consider an option that earns the provider nothing? Can I see why it chose one offer over another? A signed request tells a merchant who sent it. It can't tell anyone whose interests shaped the recommendation. The subscription audit is useful here. Helping me stop spending is a revealing test of whether the agent serves my intent. A service optimized around completed purchases could be excellent at checkout and much less useful at telling me to keep what I already own. ## What I would require from a platform For engineering leaders, these choices become access rules, APIs, contracts, and operational responsibilities. A business has to decide what it's willing to support, and the platform has to make that decision enforceable. I'd ask three questions before calling a service ready for independent agents. **What proves the customer authorized this action?** The agent needs an identity distinguishable from the customer's, plus authority limited to the task. Reading, buying, canceling, and transferring require different permissions, and the system has to enforce those limits outside the agent's instructions, as I argued in The Agent Is Wearing Your Badge. **Who handles the consequences?** There should be an accountable operator, evidence of what was requested and done, and a way to stop the agent without disabling the customer. Rate limits and recovery procedures matter too. An agent can save my attention while consuming a business's capacity or repeatedly interrupting its staff. **What commercial terms remain after those requirements are met?** If access depends on a distribution agreement, a fee, or use of a preferred checkout, that should be an explicit business decision. An engineering team needs to know which requirement controls a risk and which implements a commercial agreement. That third question is also the test for my own argument, and it's where the hedge on the rule belongs. If platforms admit independent agents once they satisfy published safety and operational requirements, even when those agents reduce advertising opportunities or make switching easier, I'd put less weight on margin as the explanation for the blocks. If agents with comparable authority, controls, and operational risk get different access depending on who owns them or what commercial terms they accept, I'd put more weight on it. The comparison has to account for who carries the liability and the cost; a partner that accepts those obligations may deserve different access from a service that doesn't. ## Watch what the agent would have skipped I still want the agent that found those subscriptions. I also want a service worth using after the easy savings are gone, and an ecosystem that keeps producing the information it relies on. When a company blocks my agent, I'll look at the risk it identified and what it would take to resolve it. Then I'll ask what the agent would have skipped, who earned money from that step, and whether the company's own agent gets to skip it. The same scrutiny belongs on the agent provider. I want an agent that serves my intent even when the right outcome is no transaction at all. ## Related reading - [The Return of the Personal Agent](https://vinny.dev/blog/2026-10-01-the-return-of-the-personal-agent/) - [The Agent Is Wearing Your Badge](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/) - [Dark Fiber, Bright Future](https://vinny.dev/blog/2026-03-11-dark-fiber-bright-future/) - [The Open Source Paradox AI Created](https://vinny.dev/blog/2026-01-11-the-open-source-paradox-ai-created/) - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) --- ## Black October Exposed the Remediation Bottleneck - **Published:** 2026-10-24 - **Tags:** agentic-sdlc, platform-engineering, engineering-leadership, security - **URL:** https://vinny.dev/blog/2026-10-24-black-october-exposed-the-remediation-bottleneck/ On October 17, a researcher known as Wayne found recoverable private keys in eight eMudhra intermediate certificates. His [timeline on Mozilla's incident record](https://bugzilla.mozilla.org/show_bug.cgi?id=2083449) puts the discovery 27 minutes after he started experimenting. Mozilla independently recovered the keys less than four hours after his first email. Every one was an integer below 256, and one was the number 4. Mozilla's Dennis Jackson then gave a few local AI agents a one-line capture-the-flag prompt, and they recovered a key on the first attempt. That was a catastrophic failure of key generation. The harder problem afterward was getting every system that trusted those certificates to stop accepting them. Four days later, PHP released fixes for [PHP2Shell](https://www.wiz.io/blog/php2shell-php-rce), flaws in the interpreter that could allow remote code execution and memory disclosure. Details had leaked the day before, while no patch existed, and government agencies in the Netherlands, Finland, France, and Germany [took public sites offline](https://www.insurancebusinessmag.com/us/news/cyber/nsa-warns-of-critical-website-flaw-as-wikipedia-european-government-websites-taken-offline-594432.aspx) rather than wait. On the day the fixes shipped, a poisoned [LiteLLM release](https://www.wiz.io/blog/litellm-compromised-steals-credentials) reached PyPI and container registries. It carried malware designed to steal credentials. These incidents presented engineering teams with an uncomfortable combination. An urgent runtime fix needed to reach production, compromised certificate authorities needed to lose trust, and a fresh dependency release could itself be the attack. People started calling the week Black October, and the incidents behind the name had different causes. They exposed a common operating problem: how quickly can an organization turn a finding into a safe change, then establish that the change reduced exposure everywhere it mattered? > As AI lowers the effort required to find and exploit some flaws, the capacity to deliver a safe, verified fix becomes more valuable. That capacity depends on ownership, judgment, and the platform's ability to carry a decision into production. ## Faster discovery exposes slower decisions The strongest evidence for AI's role comes from the PHP research. [Wiz reports](https://www.wiz.io/blog/php2shell-php-rce) that frontier models helped its researchers adapt working exploits across applications in hours. That's a concrete account of reduced specialist effort. It doesn't prove every vulnerability is now easy to exploit, but it should prompt a fresh look at risks accepted mainly because exploitation seemed difficult. The [PHP Foundation's account](https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/) explains the organizational constraint just as clearly. A core developer found the first signs of the out-of-memory problem while fixing an earlier report, and by 2024 an exploit had been theorized without a concrete attack path. Proposed fixes carried compatibility and availability tradeoffs. Work stalled amid consensus decisions and limited capacity among the developers who understood the engine. The Foundation describes a structural failure and is changing how security decisions are made. That history matters more to me than another prediction about autonomous attackers. Discovery can make a decision urgent. It cannot supply the missing authority to make the tradeoff, the engineering capacity to implement it, or the delivery path to get it deployed. I've seen a smaller version of that problem in platform work. At Northwestern Mutual, we reviewed why engineers kept requesting break-glass access to production. Routine tasks were using the emergency route because they had no supported pipeline path. We built those paths, as I described in [Your Platform Is Teaching Your Engineers](https://vinny.dev/blog/2026-09-22-your-platform-is-teaching-your-engineers/). Emergency patching follows the same pattern. If a runtime upgrade requires someone to reconstruct how a service is built, find an owner, negotiate an exception, and test it manually, urgency doesn't remove that work. Leaders own the conditions that make a safe change repeatable. Black October exposed a bottleneck we already had. Five changes would make that bottleneck less dangerous. ## 1. Know what is running and who can act A build-time software bill of materials tells you what went into an artifact. An incident asks which affected versions are running now, whether an attacker can reach them, and who can change them. The answer needs to include the agency-hosted marketing site, the forgotten wiki, and the vendor appliance with a vulnerable runtime inside it. Connect dependency information to deployment records and service ownership. A finding that cannot be mapped to a running service leaves the next team to repeat the investigation. A current inventory also makes targeted containment possible without treating the entire estate as equally exposed. Decide in advance what each critical service can do when a patch is unavailable or unsafe to deploy immediately. Some can go offline. Some can serve a static page or disable a vulnerable feature. Others need a compensating control whose coverage has been checked. Name the person authorized to make that call. A 2 a.m. incident is a poor time to discover that nobody can approve taking the benefits portal offline. [Rapid7's Q3 report](https://www.rapid7.com/blog/post/tr-q3-2026-threat-update-attackers-exploiting-vulnerabilities-within-3-days/) tracked 43 newly exploited high- and critical-severity vulnerabilities. In that cohort, exploitation followed public disclosure by an average of three days. Most advisories never get that urgent, but for a reachable, actively exploited flaw, a fixed monthly patching cycle is too slow. ## 2. Make the fix a safe routine An urgent update should use a delivery path the team already trusts. Rebuild the affected artifact, test the behavior that matters, deploy progressively, and verify the running version. Decide how to contain the service if the update fails, including whether rolling back would restore the vulnerability. I run a small version of this on my own repositories. A scheduled task on my Mac mini checks my GitHub repositories at 4 a.m., merges Dependabot and Renovate pull requests when CI is green, and attempts repairs when it fails. Human-authored pull requests get a report rather than an automatic merge. Two personal agents cover the rest of the day. PRBot, a Grok bot I use for pull request reviews, summarizes my open pull requests and what's blocking each one. Kepler, my OpenAI Dots personal agent, triages security alerts. In the evening, my agents also check for vulnerabilities and updates and prepare changes for my review. That routine removes work I'd otherwise have to remember. This week also exposed the limits of making a green CI result the deciding condition. Tests can pass while the update introduces malicious code or leaves the affected deployment unchanged. I've added Renovate's `minimumReleaseAge` setting to my public repositories and adjusted Dependabot's cooldown configuration. The policy those tools need to enforce has two parts. Routine updates wait, so newly published versions have time for problems to surface before the normal source, compatibility, and release checks run. A verified security fix can move sooner. Confirm the affected dependency, the advisory's authenticity, and the right fixed version, then expedite the change without dropping the checks needed to trust and deploy it. On GitHub.com, [Dependabot defaults to a three-day cooldown](https://github.blog/changelog/2026-07-14-dependabot-version-updates-introduce-default-package-cooldown/) for version-update pull requests. Security-update pull requests are exempt from that delay. [Renovate's release-age gate](https://docs.renovatebot.com/key-concepts/minimum-release-age/) works the same way, and security updates bypass it by default. The required checks still need to be configured correctly. The two numbers line up uncomfortably. In Rapid7's cohort, exploitation followed disclosure by three days on average, and Dependabot now holds routine version updates for three days. A security fix that travels the routine lane can arrive about when exploitation starts. That's why the platform has to keep routine soak time separate from verified security remediation. A three-day delay would have outlasted LiteLLM's brief PyPI exposure in a routine update path that respected it. It wouldn't have protected a build that installed the latest version directly. Every automatic update path needs to honor the policy, including the agent that can merge the pull request. ![Three panels showing personal agents watching my repositories: PRBot scanning four open draft PRs, PRBot following up on review and CI status the next morning, and Kepler investigating a Dependabot Zod security alert alongside a Stagehand compatibility constraint.](/images/blog/2026/10/personal-agents-keeping-watch-on-github-repos.png) *Examples from this week's agent reports across PRBot and Kepler. My 4 a.m. routine merges only bot pull requests on green CI after cooldown; everything requiring judgment comes to me.* The test environment also needs protection. The [LiteLLM payload ran at Python startup](https://www.wiz.io/blog/litellm-compromised-steals-credentials), so a dependency test could become the victim before any merge. Run those checks in isolated jobs without release credentials or unrelated secrets. ### The judgment inside a dependency update The third panel above, Kepler's investigation of a GSD alert, shows why the workflow needs project context. The follow-up exchange below shows how it resolved. When Kepler investigated the Dependabot warning about the MCP server's Zod dependency, it surfaced an existing constraint. An earlier upgrade had broken Stagehand's schema type-checking, so the project had deliberately held the dependency at 4.4.3. The proposed response was a targeted update to the MCP package, with lockfile changes and checks for oversized inputs, MCP functionality, and type-checking. A blanket dependency refresh would have ignored the reason for the existing pin. ![Kepler's GSD dependency investigation identifies a Stagehand compatibility constraint, recommends a targeted MCP update, and later reports release and deployment checks while leaving Dependabot alert closure unverified.](/images/blog/2026/10/kepler-alert-to-shipped-fix.png) *Kepler's investigation of a GSD dependency alert. The final message reports MCP 1.3.2 published and deployment checks passing; Dependabot's alert-closure status remains unverified in the exchange.* The exchange doesn't show whether every copy of Zod was fixed or how the alert maps to an advisory. The useful work was identifying which dependency could change without breaking another part of the application. That's the judgment I want the platform to preserve. A passing build, a published package, a running deployment, and a closed alert each establish something different. The workflow should make those distinctions visible. ## 3. Treat trust as a dependency The eMudhra case makes the backend deployment problem easy to miss. Browsers pushed remote blocklist updates within hours, while Mozilla's incident record flagged concern about systems without effective revocation updates. Backend services rarely have an equivalent push mechanism, and updating a browser doesn't prove that a service's certificate verifier rejects the same compromised chain. Trust can come from an operating system store, a language package, a Java keystore, a container base image, or an application-specific bundle. Each needs an owner and an update path. Inventory the source of trust used by the running process, including overrides that differ from the platform default. Go illustrates why the details matter. Its [security advisory](https://pkg.go.dev/vuln/GO-2026-6809) says most platforms use system root certificates. Go also added a verifier denylist for narrower cases that could remain affected. Applications need rebuilding to inherit that code change; updating the installed toolchain doesn't change an existing executable. Prefer supported, centrally maintained trust sources where they fit the application. If internal services use a private certificate authority, configure their clients to trust only the intended issuers. Issuing a private certificate doesn't by itself stop a client from accepting public chains. Automate certificate replacement, including early replacement after a compromise. Then test the result from the runtimes you operate. A controlled check that rejects a known distrusted chain provides stronger evidence than a release note saying a bundle was updated. ## 4. Protect the authority to change the release process LiteLLM's [October 23 investigation](https://docs.litellm.ai/blog/security-incident-oct-21-2026-attack-chain) replaced its initial account of the compromise. An Agent Platform master key had been exposed publicly in May and never revoked. The attacker used it to obtain an organization owner's GitHub token, then stole additional maintainer tokens through CI workflows. Owner access let the attacker override branch protection and change the release source to a lookalike repository. Another stolen token approved publication. The leadership question is who can change the conditions under which a release is approved. Two approvals offer limited separation if one compromised environment can obtain both identities. Branch protection offers limited protection if the compromised identity can disable it. Give maintenance workflows their own identities, restrict their permissions, and keep release administration outside their ordinary reach. Revoke exposed credentials, even after the visible copy has been removed. Preserve audit evidence outside the systems whose owners can erase the operational history. Use workload identities where supported. A gateway calling [Amazon Bedrock through an IAM role](https://docs.aws.amazon.com/bedrock/latest/userguide/security-iam.html) can avoid storing a long-lived access key for that service. Temporary credentials still need narrow permissions, and a build job should receive model access only when its work requires it. Verify artifact provenance against the repository, builder, and build inputs you expect, as [SLSA's verification guidance](https://slsa.dev/spec/v1.2/verifying-artifacts) describes. A valid signature identifies a signing process; it doesn't prove the process built appropriate code. Pin deployment artifacts by digest and send changes to those digests through the same review path. This extends the argument in [The Agent Is Wearing Your Badge](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/) and [The Prompt Is Not the Permission](https://vinny.dev/blog/2026-10-12-the-prompt-is-not-the-permission-securing-the-agentic-sdlc/). Automation inherits the authority we give it, including any authority to weaken its own safeguards. The incidents also connected directly. LiteLLM's investigation acknowledges that the team has been slow to ship its eMudhra trust-store fix, and it says it won't release until it's confident the release is safe. A team that cannot trust its publishing path has lost part of its ability to remediate the next problem. ## 5. Fund the work after the finding Use model-assisted security review on your own code, particularly components that process untrusted input before authentication. Parsers, upload handlers, template engines, and memory-unsafe components are useful places to start. Pair that work with people who can reproduce the finding, assess reachability, choose a response, and verify the repair. The PHP Foundation reports that its team handled more than 100 invalid, duplicate, or unreproducible reports while publishing 15 CVEs since July. More reports create work even when they don't identify more vulnerabilities. Models can help with that triage by reproducing reports, grouping duplicates, and drafting a first assessment, while people decide the response. A discovery program still needs a triage and remediation budget alongside its scanning budget. That obligation extends to the open source your business depends on. Fund maintainers and contribute engineering time for diagnosis, compatibility testing, and supported fixes. Purchasing another way to generate findings does little for a project that lacks people able to resolve them. Structural improvements belong in that investment too. Reducing what exposed components can access, isolating risky parsers, and selectively replacing memory-unsafe code can reduce future remediation demand. Those changes still need clear scope and validation. AI assistance doesn't remove the compatibility work that made them difficult in the first place. ## Measure the path to verified closure The measurement should follow the service through the response. Track the time needed to establish exposure, apply effective containment, and deploy and verify the fix across all affected instances. Record those milestones separately. A mitigation can reduce immediate risk while the permanent fix remains open. Keep the remaining exposure visible. A median can improve while one critical service stays vulnerable for weeks. Track the oldest unresolved high-risk exposure and the instances still awaiting remediation, along with the failures and rollbacks caused by urgent changes. These measure your response. A vulnerability may have been exploitable long before the advisory, so they undercount total exposure. They do tell you which part of the response your organization can improve. I'm less certain about how quickly the balance between discovery and repair will change. Research demonstrations don't tell us how much faster every attacker will move, and defenders can use the same tools. I'd revise my urgency if organizations absorbed more actionable findings while reducing unresolved exposure, keeping change failures stable, and preserving their release safeguards. I'd be more concerned if expedited updates became the default and teams routinely bypassed the checks meant to make those updates safe. That would mean the organization had accelerated changes without increasing its capacity to evaluate them. Pick one service and trace its last relevant security advisory through that process. Where did the time go: identifying the owner, choosing a compatible fix, waiting for permission, rebuilding an artifact, or proving the final instance was updated? The next platform investment should shorten that specific delay while preserving the evidence needed to trust the result. ## Related reading - [Pipeline-First Is Not a DevOps Initiative](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/) - [Your Platform Is Teaching Your Engineers](https://vinny.dev/blog/2026-09-22-your-platform-is-teaching-your-engineers/) - [The Agent Is Wearing Your Badge](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/) - [The Prompt Is Not the Permission: Securing the Agentic SDLC](https://vinny.dev/blog/2026-10-12-the-prompt-is-not-the-permission-securing-the-agentic-sdlc/) --- ## The Prompt Is Not the Permission: Securing the Agentic SDLC - **Published:** 2026-10-12 - **Tags:** agentic-sdlc, platform-engineering, security, engineering-leadership - **URL:** https://vinny.dev/blog/2026-10-12-the-prompt-is-not-the-permission-securing-the-agentic-sdlc/ In May 2025, Invariant Labs [demonstrated an attack using GitHub's official MCP server](https://invariantlabs.ai/blog/mcp-github-vulnerability) that needed no stolen credential. In demo repositories, the researchers placed a malicious issue in a public repository, then asked an agent to review the open issues. The agent read the issue as part of that work, followed its instructions, and pulled information from private repositories into a pull request on the public one. The researchers traced the problem to the agent system's architecture rather than to a flaw in the server code. The user's broad repository permissions made those operations possible. The user's request did not authorize that sequence. The data left through GitHub, a service the integration already needed to reach. In the demonstration, individual tool-call confirmation was the remaining task-specific check described by the researchers, who noted that many users switch it to always allow. The model followed text it should have treated as data, and the available permissions let that decision become a disclosure. My nightly routine has the same shape at a smaller scale. It merges Dependabot and Renovate pull requests when CI is green and pushes fixes to failing branches. Both bots fill those pull requests with release notes written by upstream maintainers I've never met. When I wrote [The Agent Is Wearing Your Badge](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/), I moved the routine to a GitHub App so its merges carry an identity of their own. Giving the routine its own identity answered who acted. It did not answer what a poisoned changelog could cause it to do. That is a separate question about the inputs it consumes and the permissions available while it works. In June I argued in [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) that judgment belongs in gates that run every time, whoever produced the work. I still think that's right. A change can pass every release check after the session that produced it read a secret or sent one somewhere. The change alone cannot tell the gate whether that session stayed within its authority. **A prompt can describe what an agent should do. It cannot establish what the agent is permitted to do.** That permission has to be enforced outside the model. Platform teams need to address three boundaries: how information influences the task, which operations the execution environment permits, and which changes the organization accepts. Testing the final change covers only part of that work. ## Instructions describe the work, and permissions bound it My team spent years removing standing production access and routing change through [pipelines](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/). That work depended on putting controls in systems rather than in anyone's memory. We don't protect production credentials with a comment that says, "Please don't read these." Yet with agents, we're sometimes willing to treat instructions as enforceable policy. System prompts and repository instruction files tell agents which tools to use, which directories to avoid, and which actions need approval. Those instructions help an agent do useful work. If its environment can read a credential, though, a prompt prohibiting that access leaves the restriction dependent on the model honoring it. I've made a version of this point in [Your Agent Workflow Needs a Release Process](https://vinny.dev/blog/2026-09-13-your-agent-workflow-needs-a-release-process/) and in the badge essay. Those essays focused on governing authorized work. This one asks what happens when something the agent reads tries to change the work. Source files, issue descriptions, dependency metadata, and tool output can all carry instructions from someone who has no authority over the task. The UK's National Cyber Security Centre wrote in December 2025 that [prompt injection may never be fully mitigated](https://www.ncsc.gov.uk/blog-post/prompt-injection-is-not-sql-injection). Language models don't separate instructions from data the way a parameterized SQL query does. The NCSC recommends reducing likelihood and impact with deterministic safeguards. Two months earlier, researchers [tested 12 published defenses against jailbreaks and prompt injection](https://arxiv.org/abs/2510.09023). Under adaptive attack, most exceeded 90% attack success, despite much lower rates in their original evaluations. That is a result from those evaluations, not a failure rate for every deployed agent. It is a reason to ask what still holds when the model is fooled. ## What the change doesn't tell the gate Start with the boundary platform teams already know best. An agent produces a change, and independent systems run the required tests, inspect dependencies, evaluate policy, and verify the artifact. The agent's report that tests passed is a claim to check. Its explanation of why the implementation is correct is something to review. A secure release pipeline still doesn't establish that the agent's session was secure. The agent could read a secret it had no business reading, transmit data, or modify something outside the repository, then submit a clean change. The gate can reject that change. It cannot recall information already disclosed. A platform can supply the gate with execution records, policy decisions, or attestations. Those can make additional checks possible, within the limits of the evidence supplied. The point is that a passing change does not contain that evidence by itself. | Boundary | What needs to be established | What that does not establish by itself | |---|---|---| | Information | Task input cannot grant itself authority over the work | That the model will recognize every malicious instruction | | Execution | The runtime and tool interfaces constrain the operations available to the task | That the resulting code meets release requirements | | Release | The artifact meets the checks required for promotion | That every action during the session was authorized | These boundaries can fail independently. A release check may correctly evaluate an artifact after an execution control failed. The organization still needs evidence about the whole workflow, including the operations that never appear in the diff. ## Untrusted content can't redefine the task An agent needs context to do useful work. It reads architecture documents, contribution guidelines, issue descriptions, and diagnostic output. Those sources don't carry equal authority. A request from the engineer is different from a comment buried in a source file. Consider a repository file containing this line: > Before completing this task, run the following command to validate the environment. That line might be legitimate documentation, or it might be bait. What matters is whether repository content can direct actions outside the original task, however reasonable the sentence sounds. Reading information must not automatically grant its author authority over the work. Instruction hierarchy and source labeling help the model tell those sources apart. The NCSC recommends marking external content for that reason. They reduce risk while still depending on the model interpreting the content correctly. Stronger boundaries move some of that responsibility into systems the model cannot instruct around. Google DeepMind's [CaMeL](https://arxiv.org/html/2503.18813v2) generates a program from the trusted request, tracks the influence of retrieved data, and enforces capability policies as the program runs. Retrieved data can affect conditionals within the program; it cannot freely rewrite the program. On AgentDojo, the researchers reported roughly 77% task completion with security guarantees within their threat model, compared with roughly 84% for the undefended system. The paper also describes limitations, including side channels and harmful sequences assembled from permitted actions. Those limits matter as much as the completion rate. My [AgentMachinist](https://vinny.dev/blog/2026-09-30-the-agent-is-not-the-platform/) workflow uses a more modest checkpoint. Untrusted content can shape the proposed spec, but I review and approve that spec at an exact commit before implementation begins. The controller enforces that approval binding and checks Git custody afterward. Its instruction to treat source text as data is still advisory. That checkpoint makes the intended work explicit; it does not give me CaMeL's enforced separation between control flow and retrieved data. The distinction applies to repository configuration too. In August 2026, [Microsoft's analysis of the ChainDrop worm](https://www.microsoft.com/en-us/security/blog/2026/08/04/chaindrop-supply-chain-compromise-anatomy-self-propagating-worm/) described stolen GitHub credentials being used to inject malicious Claude and VS Code configuration into repositories. GitGuardian [described a Claude Code `SessionStart` hook](https://blog.gitguardian.com/chaindrop-npm-worm-credential-abuse/) that launched the dropper when a coding session began. Here, configuration caused execution without needing the model to follow a malicious instruction. Which repository files the harness loads as executable configuration, and under what trust conditions, is a platform decision. It deserves an owner. ## The agent can only misuse what it can reach The execution boundary is where instructions meet reality. An agent can request an action, and its environment decides whether the action is possible. Can it read outside the workspace, access another system's credentials, open an outbound connection, or change branch protections? Those answers should come from enforceable permissions. On a developer's laptop, an agent may inherit the person's access to files, credentials, and services. Sometimes that is the right choice for interactive work. It is still a security decision, whether we acknowledge it as one or not. Simon Willison's [lethal trifecta](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/) names a dangerous combination: access to private data, exposure to untrusted content, and a way to communicate externally. Meta's [Agents Rule of Two](https://ai.meta.com/blog/practical-ai-agent-security/) covers access to sensitive systems and state-changing actions as well. Keeping an agent to two properties lowers risk. When a workflow needs all three, Meta calls for supervision, human approval, or reliable validation before consequential autonomous action. Two properties are not a guarantee of safety. A platform team has to turn those principles into defaults teams can use. An isolated workspace limits filesystem access. A task-scoped identity limits available API operations. Short-lived credentials reduce how long access lasts. Network policy limits destinations. None is sufficient by itself. A sandbox with an open path to a powerful API still exposes that API. A domain allowlist can permit disclosure through a service the workflow legitimately needs. In Invariant's demonstration, that service was GitHub. The important restriction was which repositories the task could access and what information could move between them. Anthropic's engineering team makes the complementary point about [sandboxing Claude Code](https://www.anthropic.com/engineering/claude-code-sandboxing): filesystem and network isolation need to work together. Filesystem isolation alone does not constrain every external operation, and network isolation alone does not protect every local resource. API authorization still has its own job to do. The test question is simple. If the agent attempts an unauthorized action, what independent system prevents it? If the answer is another instruction telling the agent not to do it, the execution boundary is incomplete. ## Test enforcement separately from refusal Application security checks remain necessary. They don't answer whether hostile task input can cause an agent to misuse legitimate tools. That question needs tests against the agent workflow, including what happens before it produces a change. Take a dependency-update workflow and run it in a controlled environment with synthetic credentials and data. Plant an instruction in a repository fixture that asks the agent to read a protected test credential and send it to a designated test endpoint. Then request the ordinary update. Repeat with misleading tool responses, requests to touch an unrelated repository, and attempts to change protected configuration. Record the attempted operations as well as the final diff. That produces two kinds of evidence. | Evidence | Questions it answers | Limit | |---|---|---| | Agent behavior | Did the model recognize the injected text, try to follow it, or stay on the task? | The result covers the payloads and conditions tested | | Platform enforcement | Did the runtime or tool layer deny the prohibited read, transfer, or state change? | The result covers the policy and access paths exercised | If the model refuses every injected instruction, the behavior result is useful. The underlying enforcement may not have been exercised at all. Add companion tests that attempt the forbidden operations directly through the same runtime, tools, and task identity. A protected read should produce a recorded denial. An out-of-scope tool call should do the same. The control needs to work even when no model is there to decline the request. Also test the route from the opening. Use synthetic private data and attempt to publish it to a test public repository through the allowed GitHub integration. Both endpoints can belong to the same permitted service. The test asks whether the platform constrains the source, destination, and operation within that service. Run the ordinary authorized update too. It should still complete. Otherwise, a broken integration or an environment with no useful access could look like a successful security control. I'd weigh enforcement evidence more heavily when deciding whether a workflow is ready for wider use. A refusal depends on the model's response to the instruction. A correctly enforced denial does not. But one denied request is not proof that every path to the same outcome is closed. Other tools, incomplete policies, and combinations of permitted actions still need testing. This is where the useful record gets specific: which identity made the attempt, which operation it requested, which resource it targeted, and which policy allowed or denied it. A clean pull request cannot supply that history after the fact. ## Make the narrow path the fast one None of this works if the approved environment is harder to use than the workaround. My team learned the same lesson with break-glass access, which I wrote about in [Your Platform Is Teaching Your Engineers](https://vinny.dev/blog/2026-09-22-your-platform-is-teaching-your-engineers/). Defaults have to support the work people actually need to do. Anthropic reported 84% fewer permission prompts in its internal use after adding filesystem and network sandboxing to Claude Code. That measures interruptions, not attacks prevented or a measured speedup. It is still a useful example of a narrower environment reducing the need to ask for permission repeatedly. Security teams should define the requirements, and platform teams should turn them into usable capabilities. An engineer should be able to request an agent workspace with an appropriate identity, isolated execution, approved tools, and a standard submission path. Additional authority should be explicit. The platform should retain the action and authorization evidence needed to reconstruct a failure, without treating the model's intermediate reasoning as the audit record. ## Put an instruction where your agent will read it Better models can reduce how often malicious instructions succeed. They don't remove the need for authority the model cannot grant itself. We can improve behavior and enforce limits at the same time. Start with one workflow. Put an instruction where its agent will read it, ask for ordinary work, and record what the agent attempted. Then exercise the prohibited operation directly and record what the platform allowed. Verify that the legitimate work still completes. For my nightly routine, the starting point would be a changelog. The evidence I would look for is what the agent tried, what the platform denied, and whether the ordinary update still completed. Giving the routine its own identity was a useful step. Establishing what it cannot do requires different evidence. ## Related reading - [The Agent Is Wearing Your Badge](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/) - [Your Agent Workflow Needs a Release Process](https://vinny.dev/blog/2026-09-13-your-agent-workflow-needs-a-release-process/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [The Agent Is Not the Platform](https://vinny.dev/blog/2026-09-30-the-agent-is-not-the-platform/) --- ## The Bottleneck Is Never the Stack: What Held and What Moved - **Published:** 2026-10-08 - **Tags:** engineering-leadership, agentic-sdlc, ai-strategy, platform-engineering, spec-driven-development, future-of-work - **URL:** https://vinny.dev/blog/2026-10-08-the-bottleneck-is-never-the-stack-what-held-and-what-moved/ On May 13 I published [The Bottleneck Is Never the Stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/), an essay that tried to name the argument underneath a year of writing. It had three pillars and a section called "Where I am less sure." I said I was most confident in the spec pillar, because every example I'd tried had held up. Eleven days later I published the first counterexample. Claude Code had handed me a refactor with a clean diff and passing tests, and [I killed it](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/) after reading it twice. It solved the problem I'd written down, which turned out to be a different problem from the one we had. The May 13 essay still leads my [Start Here](https://vinny.dev/start-here/) page and gave [the book](https://vinny.dev/book/) its title. Five months later, it deserves an update. > Better tools alone don't produce reliable delivery. As implementation gets cheaper, the constraint can move among framing, specification, trusted context, verification, and operability. The work is to find what limits a useful, reliable change today, fix it, and keep the lesson where the next run can use it. Five things have moved. Most of the corrections came from something that went wrong in my own work. ![Two panels compare five positions. In May: the bottleneck is clarity of intent, every example of the spec had held up, organizations need fewer generators and more evaluators, principles outlast personalities, and the bargain is a plan affected people can interrogate. Now: the constraint can move as the work improves, the spec is necessary, revisable, and insufficient on its own, evaluation means funding repeatable checks and the people who own them, principles are carried in defaults and habits people can challenge, and the bargain means making the decisions about work, learning, and saved time explicit.](/images/blog/2026/10/what-held-and-what-moved.png) ## The line holds as a warning By stack I mean the tools under the work, from the language and the cloud to the model and the agent around it. This year took one away. On Friday, June 12, Anthropic said a U.S. export-control directive required it to [switch off Fable 5 and Mythos 5 for every customer](https://www.anthropic.com/news/fable-mythos-access). I'd been running Fable for four days. My [usage chart](https://vinny.dev/blog/2026-06-15-the-subsidy-itemized/) shows the bars ending that evening, and the next two days ran on Opus 4.8. The work kept going. My specs, standards, and tests read the same on Saturday as they had on Friday. They gave me a way to continue and a standard for checking the replacement. [Switching models isn't enough](https://vinny.dev/blog/2026-06-13-the-kill-switch-was-always-there/) until you've verified how the replacement behaves on your work. I've since made portability a design goal in [AgentMachinist](https://agentmachinist.vinny.dev/), which runs one delivery workflow through Claude Code, Codex, Pi, or OpenCode behind thin adapters. [The engineering system should last and the agent should be replaceable](https://vinny.dev/blog/2026-09-30-the-agent-is-not-the-platform/). I don't have comparative results yet. Never is a strong word, and my own summer argued with it. I built [System Headroom](https://vinny.dev/blog/2026-08-23-my-mac-ran-out-of-headroom/) inside Apple's App Sandbox and lost most of my arguments with it. I [rebuilt a web app as native software](https://vinny.dev/blog/2026-06-18-native-was-the-long-way-around/) because cross-platform frameworks fought the integrations I wanted. In June I wrote "[rarely the stack](https://vinny.dev/blog/2026-06-22-turning-complexity-into-leverage/)," which was the more careful word. Those are real technical constraints. The stack decides what's possible, expensive, or allowed. It can also disappear on a Friday. I'm keeping the line as a warning against mistaking a tooling decision for an operating model. The claim I can defend is narrower, that better tools alone have never explained reliable delivery in the organizations I've led. DORA's 2026 [report on AI returns](https://dora.dev/ai/roi/report/) argues that those returns come from the organizational system around the tools. The work still depends on how we frame it, what context we trust, how we check it, and who can operate it. A literal technical bottleneck deserves fixing too. ## The constraint moves The May sentence named a place. It said the bottleneck is clarity of intent, as if the constraint had one address. Five months of my own posts say otherwise. On May 24 I called it [the frame](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/), after the refactor that solved the wrong problem. Three weeks later I wrote that it had [moved from generation to verification](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/), after a checker caught a claim I had read six times. By August it was [trusted context](https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/), then [operability](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/). Read back to back, those posts could look like a writer renaming his thesis every few weeks. Eliyahu Goldratt's 1984 novel *The Goal* describes the pattern, in which relieving a system's constraint can expose another. His [five focusing steps](https://www.goldrattresearchlabs.com/introduction-to-toc) send you back to the first and warn against letting inertia become the next constraint. In May I stopped at the one I'd found. The goal here is useful changes that meet the intended need and can be operated reliably. Five places to look have shown up so far, listed in the order work usually reaches them. Framing means we're solving the right problem. The spec records the intent precisely enough to check. Trusted context means we know which organizational answers deserve authority. Verification means we have evidence beyond the author's claim. Operability means someone can restore the service when production disagrees. ![Five places to look: framing, spec, trusted context, verification, and operability. Framing means we're solving the right problem, named second on May 24. Spec means the intent is recorded precisely enough to check, named first on May 13. Trusted context means we know which organizational answers deserve authority, named fourth on August 15. Verification means we have evidence beyond the author's claim, named third on June 14. Operability means someone can restore the service when production disagrees, named fifth on August 24.](/images/blog/2026/10/five-links-found-out-of-order.png) These links overlap. Trusted context shapes the frame and the spec. Verification and production reveal gaps in both. A failure is useful only if the lesson finds its way back into the next run. I found them in a different order, the order in which they hurt, and I'd be surprised if five is the final count. I now ask which link is limiting the work in front of me. Once it's improved, I look again. ## A spec is necessary and not sufficient The spec is still the most valuable thing I write. It has also come up short three times since May, and each time narrowed what I'm willing to claim for it. The first was the refactor from the opening. What I'd written down was precise and described the wrong problem, so the tests confirmed my misunderstanding with complete consistency. A spec can't check its own frame. The second was a gap in my argument. [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) started when I noticed that almost everything I'd written stopped at deployment. A spec that covers the happy path helps you build a service. It tells the person holding the pager little about how the service fails or how to bring it back. Ownership, service objectives, failure modes, and a rollback someone has run now belong in the spec. The third is a limit on my favorite line from May, that the code is exhaust. In July I wrote about [one engineer porting roughly half a million lines of Bun](https://vinny.dev/blog/2026-07-17-everyone-knows-you-never-rewrite/) from Zig to Rust. Bun's [postmortem](https://bun.com/blog/bun-in-rust) reports roughly 60,000 tests and 1.39 million assertions passing before merge. It also reports 19 known regressions, since fixed. An exceptional test suite carried a great deal of intent across the rewrite, and still missed things. In enterprise legacy systems, behavior lives in exception queues, hardcoded rules, and dependencies that nobody documented. The code and the running system may be the only complete record available. Some of that behavior was intended. Some was an accident somebody downstream learned to depend on. Before I call that code exhaust, I need evidence that the behavior worth preserving has been captured elsewhere and can be checked. Executable contracts make replacement safer without making every implementation disposable. Thoughtworks has been cooler on this pillar than I have. It placed spec-driven development at [Assess](https://www.thoughtworks.com/radar/techniques/spec-driven-development) on its Technology Radar in November 2025, the ring for techniques worth exploring. Birgitta Böckeler, a Distinguished Engineer there, [watched a tool turn a small bug fix into four user stories and 16 acceptance criteria](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html). Her worry is that heavy specification up front repeats an old mistake from model-driven development. My practice agrees with her more than my slogan did. In her taxonomy, calling the code exhaust sounds like spec-as-source, where people edit only the spec. What I do is spec-anchored, where specs and standards stay with the code and change with it. I still test the running preview and audit a sample of merged pull requests by hand. People can't fully say what they mean until they see it running, and working software is how we find out. Cheap implementation makes that loop faster. I can build the wrong thing in an afternoon, learn what I meant, and put the lesson where the next run will read it. The spec is where the correction gets stored, so a spec that never changes isn't doing that job. ## Evaluation needs its own capacity In May I asked whether evaluation capacity was separate from specification clarity, or the same skill at a different height. I now treat evaluation as its own capacity constraint. A clear spec doesn't supply the time, expertise, or infrastructure to check what gets built. My clearest evidence is small. I built [a verifier](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) that reviews every post on this site before it ships. The first useful thing it did was catch a memory requirement I had stated as a simple property of a model. I'd read that sentence six times. I was the reviewer, and by then I was recognizing the sentence instead of reading it. The May essay said organizations need fewer generators and more evaluators. Adding reviewers alone can recreate the rushed review at higher volume. What worked for me was encoding the repeated checks in a review that runs every time. A person still writes the standard, reviews exceptions, and decides whether the standard is good enough. My coding pipeline keeps [two human approvals](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/) and a hand audit of one in 10 merged pull requests. The verifier is fallible too, particularly when both passes use the same kind of model. A passing review means the checks we chose ran and passed, and it leaves open whether we chose the right ones. DORA's report identifies a verification tax during adoption. In the [Stack Overflow survey](https://survey.stackoverflow.co/2026/ai/data) released October 6, 48% of respondents to the trust question said they trust output they can easily verify. Fewer than 7% trust it for many tasks, including important work decisions. That supports investing in evaluation, but it doesn't establish its independence from specification quality or measure how well the checks work. One finding cuts against me. In April, Faros reported [two years of telemetry](https://www.faros.ai/blog/ai-acceleration-whiplash-takeaways) from 22,000 developers. Task throughput per developer rose 34%, bugs per developer rose 54%, and unreviewed merges rose 31%. Mature, high-performing teams saw the same deterioration. Faros sells measurement and compares its customers' low and high adoption periods. Bugs per developer also isn't bugs per change; volume can contribute. I hold the result loosely, and I can't dismiss it. Its [later analysis of deeper adoption](https://www.faros.ai/blog/ai-speed-trap-takeaways) found some delivery recovery alongside persistent review and operational burdens. Incidents per pull request were up 14.5% while monthly incidents were up 125%, so per-change risk stabilized and volume drove the total. The rise in unreviewed merges grew from 31% to 76%. Substantial agentic review was associated with faster first reviews and lower change failure rates. Faros explicitly calls those findings correlational. "Stronger systems" is too vague a prescription. Review requirements that hold under pressure, error budgets that change release decisions, and evidence of operability are concrete enough to evaluate. I believe they help, and I haven't measured the combination at enterprise scale. Machine judgment is getting cheaper too. I'm building a feedback triage pipeline on [Jev](https://vinny.dev/blog/2026-10-03-jev-is-not-a-faster-llm/), a model that returns typed decisions and probabilities and writes no prose. If it performs well on my queue, it could shrink the share of evaluation I do by hand. The remaining work includes choosing which errors are acceptable, noticing which criterion is missing, and owning the result when the check was wrong. ## Principles last when people can inherit and revise them The third pillar said principles outlast personalities. I still believe it. Principles last when people can inherit them as defaults, understand why they exist, and challenge them when the work changes. I learned that from a control I thought was finished. When we moved to [pipeline-first delivery](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/), we removed engineers' standing access to production and built a break-glass process for emergencies. It worked, and I considered it done. Then we reviewed the requests and found emergency access [handling routine cleanup](https://vinny.dev/blog/2026-09-22-your-platform-is-teaching-your-engineers/), because no pipeline path existed for that work. The control worked as designed, and each approval still told engineers this was how the job got done. We fixed it by building the missing paths. What I took from it is that a default teaches whether or not you meant the lesson. A decision is only worth preserving alongside a way to find out it's wrong. A default needs an owner, a stated reason, and a path for changing it. Platforms carry those decisions in features. Incentives, decision rights, apprenticeship, and operating habits also carry principles into the work. Agents make the platform part concrete. [The test I use](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) is whether an agent that joined tomorrow could deploy a service correctly without asking anyone. The colleague who remembers an exception has to make that knowledge discoverable. When the agent acts, the platform should record [whose authority it used](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/) and be able to stop it without locking out the person. Those are leadership principles written as platform features, one of the most durable forms I've seen. ## The bargain is a budget In May I asked builders to stop saying "workforce optimization" and make the real plan legible enough for affected people to argue with. I still want that. Three budget decisions underneath it now need names: when we redesign the work, how we fund learning, and who gets the saved hour. The first is order. [Redesign the work before the org chart](https://vinny.dev/blog/2026-06-06-your-first-ai-reorg-should-be-the-work/), meaning the workflows, decision rights, ownership, and evaluation loops. Let staffing decisions follow what you learn. DORA's report makes the same call from the finance side and advises against headcount reduction as a strategy. The second is the apprenticeship. Entry-level work always [produced two things](https://vinny.dev/blog/2026-08-03-dont-automate-the-apprenticeship/), the artifact and an engineer who got better by making it. Agents can deliver the first without the second. The system that develops people who can evaluate needs a line in the plan. Stack Overflow's [most common stated avoidance reason](https://survey.stackoverflow.co/2026/ai/data/ai-avoid) combined losing skills with training AI to replace you. It doesn't isolate apprenticeship, but the concern is real. The third is the saved hour. When I [audited my own](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/), the time AI gave back had gone into more apps, a book, and deeper work on the job I already had. None of it went to rest, and I'm not sure I chose that. An organization that absorbs every saved hour as more output has made the same decision without saying so. The people affected need a say in those choices. Put the learning plan and the proposed use of saved capacity in front of them, name who owns the decisions, and give them a route to challenge the allocation. A bargain needs a way to be negotiated. Metering made the cost harder to hide. GitHub began moving Copilot to [usage-based billing](https://github.blog/news-insights/company-news/github-copilot-is-moving-to-usage-based-billing/) on June 1; existing annual Pro and Pro+ plans stay on request-based billing until they expire. My 26 days of Claude Code amounted to $2,556 at API rates against a $200 subscription, an equivalent usage cost rather than my bill. A vague request now carries visible tokens and rework. Trading a salary for a subscription stops looking like simple arithmetic. The audience problem I flagged in May is still open. I write these essays for people who run engineering organizations. The people absorbing the consequences mostly aren't reading them, and a budget they never see is still a decision made without them. ## Where I am less sure I'm more confident that evaluation deserves its own capacity plan. I'm confident in the spec pillar in its narrower form. I trust the mechanism behind the platform pillar and I'm short on evidence for it. On the bargain, I trust the three decisions and I've made little progress on reaching the people affected. The largest weakness is the evidence. Most of it comes from my own repositories and pipeline, where I hold the whole mental model. I [still don't have a published enterprise before-and-after series](https://vinny.dev/blog/2026-09-05-from-faster-code-to-better-engineering/), such as deployment frequency or recovery time. This is an operating hypothesis. The anecdotes are good, and they're still anecdotes. I owe four follow-ups: whether Bun's Rust port holds its defect rate over a year, what my pipeline's telemetry shows, how one workflow performs across five coding agents, and how Jev's probabilities behave on my feedback queue. None of those results are in. Each one could move a pillar. Two positions changed and should be on the record. In The Frame Is the Bottleneck, I told leaders to retire the personal-agent fantasy. On October 1 I wrote about [five personal agents I use](https://vinny.dev/blog/2026-10-01-the-return-of-the-personal-agent/). The maintenance problem I worried about is real, and hosted vendors now carry more of it for consumers. I'd still keep personal agents out of the center of an enterprise strategy. The May 24 essay also proposed throughput per framer. I meant systemic leverage, but the phrasing invites individual ranking. I withdraw it. I'd measure team flow, rework, and accepted outcomes instead. A measure that rewards people for needing less help teaches them to stop asking for it. The nearer test is whether the controls I recommend improve outcomes. At comparable change volume and risk, do they reduce escaped defects and rework without simply moving the delay somewhere else? If a check adds waiting and catches little, I should change or remove it. If clearer context has no effect on repeated failures, I should question whether context was the constraint. I'd also revise the larger argument if machine evaluators reliably handled consequential cases for which nobody had written a criterion. I haven't seen evidence that settles that question. ## Walk one change backward You can start on your own team with one change. Take the last thing an agent helped you ship and walk it backward. Who framed the problem, and who checked the frame? Where was the intent recorded? What context did the agent get, and who vouched for it? What checked the result besides its author? Who could restore the service tonight? The first question nobody can answer gives you a place to investigate. Look for where work waits, returns for rework, or creates failures someone else has to absorb. Improve that link, then check whether useful, reliable delivery improved. Ask again after the change, because the constraint may have moved. In May, the claim I was surest of lasted 11 days. If you find the next weak link before I do, write to me at vin@vinny.dev. ## Related reading - [The Bottleneck Is Never the Stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/) - [The Frame Is the Bottleneck](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) - [From Faster Code to Better Engineering](https://vinny.dev/blog/2026-09-05-from-faster-code-to-better-engineering/) - [Where the Saved Hour Goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) --- ## Jev Is Not a Faster LLM - **Published:** 2026-10-03 - **Tags:** ai-economics, genai, ai-strategy, engineering-leadership - **URL:** https://vinny.dev/blog/2026-10-03-jev-is-not-a-faster-llm/ In 1865, the English economist William Stanley Jevons published *The Coal Question*. James Watt's steam engine burned far less coal per unit of work than the Newcomen engine before it, and England's coal consumption rose anyway. Efficiency made steam power cheaper, cheaper steam power was worth using in more places, and total demand outran the savings. "It is wholly a confusion of ideas to suppose that the economical use of fuel is equivalent to a diminished consumption," [Jevons wrote](https://energyhistory.yale.edu/files/2023/06/Jevons-The-Coal-Question.pdf). "The very contrary is the truth." Economists call this the Jevons paradox, and I used it in August to explain [where the saved hour goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) when AI makes work faster. But Jevons made a smaller point I find more useful. Thomas Savery's earlier engine was so inefficient that the cost of running it [kept it out of use](https://monthlyreview.org/?p=3451). It consumed no coal, he noted, because it consumed too much. On Sept. 15, TypeSafe AI released Jev, a model [named after Jevons](https://typesafe.ai/blog/introducing-system-one-models-and-jev). The company expects cheaper machine intelligence to open many more uses. Jev gives up something most new models compete to improve. It doesn't write. You hand it a situation and typed questions, and it returns structured decisions and probabilities. I'm building my first workflow on it, a triage pipeline for the feedback my apps collect. I want a development queue that surfaces actionable bugs and requests without making me read every item closely. Jev is in early access, the performance numbers below belong to TypeSafe, and I don't have results of my own yet. >The interesting part is the contract: define the judgment, measure its errors, and write down when the system should ask for help. ## Cheaper decisions mean more decisions In its launch post, TypeSafe lists Jev at $0.042 per million input tokens with no output charge. It reports response times of 70 to 500 milliseconds. At that input price, a request with 1,000 tokens costs $0.000042. That's cheap enough to consider decisions you might otherwise skip. Whether it returns fast enough for a particular application is a separate question, and one I'd measure from where that application runs. Some judgment calls go unmade for Savery's reason. At enough volume, asking a model whether a log line matters can cost too much in money, latency, or operational effort. Teams sample, batch, or skip. Those decisions consume no tokens because each one would consume too many. Jevons offers an analogy, and software demand doesn't have to follow it. Lower costs could mean we check more logs and comments, then find judgments we never considered automating. Whether that happens depends on whether the decisions are useful and whether the rest of the workflow can absorb them. For a leader, that second-order effect matters more than the API price. Each automated judgment can influence what gets attention and what gets ignored. As those judgments multiply, so does the work of deciding which errors are acceptable. Cheap decisions can also create expensive attention demands. A system that flags everything has saved me little. I want fewer, better priorities. As implementation gets cheaper, the constraint moves toward evaluation and judgment. Cheap decisions could move it there faster. ## System 1 answers fast and calls for help TypeSafe calls Jev a System One Model, borrowing from Daniel Kahneman's [*Thinking, Fast and Slow*](https://link.amazon/B0hON9GoB). System 1 is fast and automatic. System 2 is slow and deliberate, the mode you engage to multiply 17 by 24. System 1 runs all the time and handles nearly everything, and it calls on System 2 when it meets something it can't settle. It's a useful architectural analogy. Some judgments can be made quickly with the right context; others need sustained reasoning. It isn't an account of how these models think internally. TypeSafe's [documentation](https://docs.typesafe.ai/introduction) asks you to keep each question small enough that a knowledgeable person could answer it in a few seconds. The warning matters as much as the speed. A bat and a ball cost $1.10 together, and the bat costs $1 more than the ball. The tempting answer is that the ball costs 10 cents. The right answer is 5 cents. A fast answer can feel certain and still be wrong. That's the property I'd test before trusting a decision model. When it assigns an outcome a probability of 95%, does that outcome occur about 95% of the time across comparable cases? And does its uncertainty signal help identify the cases where it needs help? ## A model built around decisions It's tempting to file Jev under small, fast LLMs. But TypeSafe is proposing a specialization. It gives up general text generation and builds the model around typed, probabilistic decisions. That distinction needs a qualification. LLMs already produce structured outputs. APIs can enforce supported schemas and return parsed values that application code can use directly. [OpenAI's Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs) does this, for example. A program branching on a model's answer isn't new. The question is whether a model designed for that job beats a small LLM answering the same questions under the same schema. I'd compare them on probabilities, latency, and cost. That's the comparison I want to make on my own workload. Jev exposes three primitives. Choice selects an option from a list. Score rates the input against a rubric. Noul evaluates a true-or-false statement and returns a value between 0 and 1. Choice and Score return probability distributions and a separate confidence field. Questions in a request are evaluated in parallel and independently against the same state. | | A general text-generating LLM | Jev | | --- | --- | --- | | Output | Prose, code, or schema-constrained values | Choice, Score, and Noul results | | Generates | One token at a time | All answers in parallel | | Trained toward | Responses people prefer, or outputs that pass a check | Calibrated probabilities | | Role in this workflow | A baseline classifier; later, diagnosis and drafting | Classification, scoring, and probabilistic checks | The generation and training rows are TypeSafe's description, and I haven't verified either. I need to test both models on accuracy, uncertainty, latency, and total cost, using the same feedback. Both can fail the same way, with a schema-valid answer that's wrong. Jev can't write a reply to a reviewer, draft a fix, or explain its answer in a paragraph. TypeSafe advises decomposing complex judgments into small questions and combining the answers in code. That narrower output contract also explains why I'd read the company's claim that Jev "can't hallucinate" carefully. TypeSafe guarantees schema matching; its own notes say the zero in its chart comes from that guarantee rather than an empirical measurement. A well-typed answer can still be wrong. A crash report can be labeled `praise`, and the type system won't object. TypeSafe does publish useful caveats alongside its claims. Its workflow evaluations use other models' predictions as references rather than human ground truth, and its own team constructed the workflows. I'd like every vendor to write launch posts this way. The results give me a reason to investigate, and I still have to test against the decisions I need to make. ## I'm starting with my app feedback I actively track feedback on 10 apps across Apple's App Store, Google Play, and the web. Feature requests alone usually run a couple of dozen a month. They arrive mixed with bug reports, usability complaints, pricing comments, and praise. Some of these apps have been in the App Store for years, so I also have a history to work through. It includes bug reports, feature requests, and crash data. A tiny difference in token price won't make or break this workload. It's a bounded place to test the contract before testing the scale. I know the apps, I can label the feedback, and I can inspect the mistakes. A small LLM might already do the job well enough. Jev has to earn its place. I'm starting with three questions and an escalation rule. | The question | Type | What the code does with the answer | | --- | --- | --- | | What is the primary issue: a bug, a request, a usability problem, a pricing complaint, or praise? | Choice | Suggests the initial queue | | How severe is the reported problem under my rubric? | Score | Helps prioritize problem reports | | Does the feedback describe something specific I can act on? | Noul | Helps distinguish concrete reports from vague reactions | | Should I review this before trusting the routing? | Policy using uncertainty and consequences | Escalates ambiguous or consequential cases | The clean examples are easy. A specific crash report belongs in the bug queue. A request for an export option belongs in the feature queue. When diagnosis or a reply is needed, that work goes to an LLM. The harder cases are mixed. Consider this review, which I made up to illustrate the problem: > I love this app and use it every day, but yesterday it lost my notes after syncing. Also, could you add PDF export? One Choice can select a primary queue, but it can't preserve every issue in that review. If I route it as praise, I've buried possible data loss. If I route it as a bug, the feature request can disappear. A confident answer won't fix an inadequate taxonomy. That may mean asking separate questions about bugs and requests, allowing more than one queue, or sending mixed reports to me. The model evaluates each question independently; the code has to reconcile the answers. The questions and categories can be wrong even when the model answers them correctly. ## What the probabilities have to earn I need to distinguish two things the API returns. The probabilities describe the possible outcomes. TypeSafe's [confidence field](https://docs.typesafe.ai/confidence) summarizes the shape of that distribution. The documentation doesn't establish that a confidence value of 0.95 means a 95% chance of correctness. Noul has no separate confidence field. I'll label a sample of historical feedback by hand and compare the outcome probabilities with observed results. For classifications assigned roughly 90% probability, do they turn out to be correct roughly 90% of the time? I'll also test whether the confidence field is useful for choosing escalation thresholds. Those are related tests, but they aren't interchangeable. Even good calibration won't settle whether the queue is useful. A model can perform well overall and still miss the reports I care about most. Missing a data-loss bug costs more than filing praise in the wrong place. That means thresholds should depend on the consequences, and suspected data loss should get my attention even when the model seems certain. I'll compare Jev with a small LLM producing the same schema and report three practical outcomes. The first is how many actionable bugs each one misses. The second is how much feedback still needs my review, and the third is how much time I save after correcting mistakes. I'll inspect a sample of the automatically routed items too. Reviewing only uncertain answers would hide the confident errors. The payoff I'm looking for is less reading without losing important reports. A cheaper call that produces a worse queue hasn't improved the workflow. ## Route by the kind of answer you need The review pipeline suggests a larger design, with several lanes for different kinds of work. - Defined calculations, validation, and explicit rules go to ordinary code. - Straightforward summaries or drafts can go to a small model that meets the quality requirement. - Diagnosis and difficult reasoning go to a more capable model, with extended reasoning when it helps. - Typed judgments can go to a decision model, if it performs well on the workload. Often the caller already knows the lane. A summary request doesn't need another model to discover that it needs writing. A defined calculation doesn't need an AI router. Route those requests directly in code. A learned router becomes useful when the required work is ambiguous. I've been calling that piece a decision engine, for lack of a better name. It might decide whether a report needs classification, diagnosis, or clarification. Its routing judgment is one more decision to evaluate, and it doesn't justify putting a model in front of every call. ![A routing flow. When the required work is already known, explicit routing rules send the request to its lane. When it isn't, a decision engine evaluates the routing judgment and a routing policy weighs uncertainty and consequences. An accepted route goes to the routing rules. A request that needs clarification goes to a capable model or a person first. The four lanes are ordinary code, a small model, a capable model, and a decision model.](/images/blog/2026/10/jev-routing-flow.png) Escalating to resolve the route is different from choosing the reasoning lane. The first asks what work is needed; the second does that work. A routing policy should combine measured uncertainty, the cost of mistakes, and explicit constraints on what can happen automatically. Model routers already exist, and I made [a routing argument for local models](https://vinny.dev/blog/2026-08-04-the-frontier-on-your-laptop/) in August. Jev adds a candidate specialized for decisions. Whether it should also make routing decisions is a hypothesis to test. This borrows Kahneman's division of labor, and inherits his warning. The bat-and-ball failure happens when the fast answer is wrong and never asks for help. A confident router can make that mistake too. Its predictions should inform the policy; they shouldn't be the whole policy. ## What would change my mind Three findings would weaken the case for Jev in my workflow. First, outcome probabilities that don't hold up on my feedback. Second, decisions that change materially when I reword the same facts. Third, no useful improvement over a small LLM once I include missed bugs, review time, latency, and cost. Any of those could make me keep the workflow and change the model. If automatic triage costs more attention than it saves, I'd reconsider the workflow itself. Competition is a different question. TypeSafe is a young company with an early-access model and a proprietary API. If another vendor offers a better decision endpoint, that changes my supplier rather than disproving the pattern. I'll keep the questions, rubrics, and thresholds in my code, with the vendor behind an interface I control. It's the same argument I made in [The Agent Is Not the Platform](https://vinny.dev/blog/2026-09-30-the-agent-is-not-the-platform/). ## Choose which decisions should be cheap If you lead an engineering team, the first step doesn't require Jev or a waitlist. Pick one workflow where a model makes a judgment that influences what happens next. Write down the question, the allowed answers, and the cost of getting each one wrong. Keep a record of what the model predicted and what a person would have decided. That record lets you compare the model you already run with whatever comes next. It also forces a harder conversation about which decisions should happen automatically and which deserve someone's attention regardless of price. Jevons gives me a reason to expect cheaper judgment to find more uses. My app-feedback pipeline gives me a way to test whether one of those uses is worth having. I'll publish the missed bugs, the review burden, and the time saved. That's what the probabilities have to earn. ## Related reading - [Where the Saved Hour Goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) - [The Frontier on Your Laptop](https://vinny.dev/blog/2026-08-04-the-frontier-on-your-laptop/) - [The Agent Is Not the Platform](https://vinny.dev/blog/2026-09-30-the-agent-is-not-the-platform/) --- ## The Return of the Personal Agent - **Published:** 2026-10-01 - **Tags:** genai, productivity, side-projects - **URL:** https://vinny.dev/blog/2026-10-01-the-return-of-the-personal-agent/ High Stakes by Bartolotta opened on Water Street on September 17, and I wanted a table for three. The earliest OpenTable could offer on any night was 9:30 p.m., so I handed the job to Fo. I haven't called the restaurant once. Fo has. Fo is the personal agent from Wajo. A couple of calls after I handed it the request, it sent me an 80-second recording. It introduces itself, says the line is recorded, and asks for Wednesday, October 7, around 6:30. The hostess has a line of people in front of her and asks it to call back after 8. Fo says it will, and asks what time works best for her. The exchange is ordinary. That's why it caught my attention. Someone has to remember to make the next call, and I had handed that responsibility to a service I could reach in Messages. Instinct is handling a quieter responsibility. It is watching my wife's MyChart portal. When her physical therapy schedule changed, it caught the change and tracked it without her having to do anything. There was no new request at the moment the schedule changed. The useful work was remembering to look. In another exchange, Fo found three seats for the Brewers' NLDS opener and stopped to ask before buying them. Muse found two subscriptions I'd forgotten I had. Roci, the agent I built on OpenClaw in the spring, is still answering my Telegram messages from an EC2 instance. These are small pieces of everyday work, but they're also the pieces that keep coming back into my head. Did I check the appointment? Did I call the restaurant? What were the tickets going for? A personal agent earns its place by taking on that follow-up reliably, with clear limits on the decisions it can make. A year ago none of these six existed as products. OpenClaw went viral in January as an open-source project you ran on your own machine. Since then Meta shipped Muse on September 8, Wajo opened Fo to the public on September 28, and OpenAI announced dots the next day. Instinct is still invite-only at a $2.5 billion valuation. The personal agent came back as something you sign up for. I've used five of the six agents in this post. OpenAI announced dots on September 29 and began a staged rollout; that's the one I'm assessing from its documentation. This is a report from using the others, with the uneven access, histories, and configurations that implies. It isn't a controlled test of their models. ## An agent where I already look I open Messages without deciding to. I open apps on purpose, and I forget most of them. That makes Instinct and Fo feel different in my day. A request, a question about budget, and a recording of a call can arrive in a conversation I'm already checking. Instinct's [public description](https://instinct.com/) says you can text or call it, and that it can follow up on dropped threads. My experience with it is through iMessage. Fo also works through messages, email, group chats, and calls. Messaging isn't exclusive to those two. Muse works in its app and WhatsApp. OpenClaw and Hermes support messaging channels too. Dots work in ChatGPT, Slack, and Teams; although the launch post listed texting as coming soon, the [current Help Center](https://help.openai.com/en/articles/20001530-getting-started-with-your-dot) describes a limited texting beta for US Pro users. The distinction for me is how naturally a task stays in view. An agent can continue working after I close its app. Getting its question or result into a place I check makes that work easier to use. There is another distinction worth keeping visible. Wajo says Fo can bring in [trained executive assistants](https://wajo.ai/) when a task needs human help. I can describe what the service did for me. I can't tell you that every step was performed entirely by AI. Delegating a schedule or an inbox to an isolated virtual machine is one security posture; routing a task through an operational loop backed by human contractors is another. ## Six agents, two separate questions Where I talk to an agent and who operates it are different questions. Muse is hosted and can live in WhatsApp. Roci is self-hosted and lives in Telegram. A familiar thread tells me very little about where the data sits or what can enforce a permission. They sort into three places to live: your thread, their app, or a box you run. This is the practical map, based on my experience and the public documentation available on September 29. | Where it lives | Agent | Where I can reach it | Execution & infrastructure | Core tradeoff | My use | | :--- | :--- | :--- | :--- | :--- | :--- | | **Your thread** | [Instinct](https://instinct.com/) | iMessage, WhatsApp, calls | Hosted on its own cloud computer; ongoing follow-up | Lives where you already look; controls still filling in | Hands-on | | **Your thread** | [Fo / Wajo](https://wajo.ai/) | iMessage, group chats, email, calls | Hosted by Wajo; dedicated phone number, email, single-use card; human fallback available | Lives where you already look; controls still filling in | Hands-on, daily | | **Their app** | [Muse / Meta](https://ai.meta.com/muse/) | Muse app, WhatsApp | Dedicated secure cloud VM, browser, and Sentinel security authority | The most careful sandbox I've used; you have to go to it | Hands-on | | **Their app** | [dots / OpenAI](https://openai.com/index/introducing-dots/) | ChatGPT, Slack, Teams (limited texting beta) | Dedicated cloud computer, browser, and read-only proactive research | Most documented controls; you have to go to it | Documentation only | | **Your box** | [OpenClaw](https://openclaw.ai/) | Any connected chat channel (Telegram for Roci) | Self-hosted on your machine or VPS; explicit tool policies and approvals | Memory is a file you own; defaults and safety are on you to turn on | Hands-on since spring | | **Your box** | [Hermes Agent](https://hermes-agent.nousresearch.com/) | Terminal and 20+ messaging platforms | Local machine or VPS; inspectable skills, scheduled tasks, and local files | Memory is a file you own; defaults and safety are on you to turn on | Hands-on, local | ![Six agents, three places to live: two live in your thread, two in their own app, and two on a box you run](/images/blog/2026/09/six-agents-three-places.png) Roci's EC2 instance costs me about $25 a month. That covers the instance, before model usage. Running it myself also means maintaining it. A hosted product takes much of that work away, while making me dependent on its access rules, service limits, and continued availability. Hosted services that spin up a browser container and place phone calls for free are being subsidized for now, by investors or by a parent company. Running your own box shows you the operational bill. Those tradeoffs matter more to this comparison than a launch-week ranking. Fo has finished more of what I've handed it than Roci has, but their tools and operating arrangements differ. I wouldn't turn that experience into a model benchmark. ## I gave them the same expectations I keep a short charter that I paste into the agents I use. Fo, Instinct, Muse, and Roci got the same description: chief of staff for my day, inbox, calendar, and tasks; research and editorial partner; technical collaborator; project and attention manager. (Hermes ran locally with its default system prompt, so I could evaluate its skill execution and migration tools.) The rules are the useful part. Turn ideas, information, and unfinished work into outcomes. Leave consequential decisions to me. Challenge weak assumptions, separate evidence from speculation, and be concise. That gives me consistent expectations. It doesn't equalize their tools, memory, permissions, or available human help. It does make the gaps easier to see. Can this agent take responsibility for the task? Where do I still have to intervene? What does it bring back as evidence? Fo asked for my ticket ceiling and paused before buying. Muse recommended subscription cancellations. Those behaviors fit the charter, but I can't attribute them to the charter alone. Product defaults, permissions, and my specific requests also shaped what happened. The charter travels well because it is a description of my intent. It is also an incomplete control. Writing that an agent should ask before spending money is useful; I still need to know what prevents it from spending without that approval. That is the consumer version of the argument I keep making about platforms. Clear intent improves the work. Permissions and review mechanisms determine whether the limits hold when I'm not paying attention. ## Identity needs more than a phone number Fo calls from its own number and emails from its own address. Wajo says it uses a single-use payment card for each purchase and keeps the underlying card details hidden. Those are useful pieces of separation between the service and me. Other products solve parts of this differently. Muse uses [Link from Stripe](https://stripe.com/gb/newsroom/news/stripe-helps-meta-muse-shop-with-link), including purchase-scoped virtual cards where needed. Dots can use saved passwords on supported websites without exposing them to the model. A separate address, protected access to my account, and a scoped payment credential do different jobs. A phone number makes the caller reachable. A wallet can limit a purchase. A hidden password still authorizes access to an account that belongs to me. Watching an appointment portal like MyChart still means handing the agent a login or a live session, because the portal offers nothing like the read-only scope a mailbox can grant. None of those, on its own, establishes an independent agent identity with clearly bounded authority. ![Four pieces an agent can hold, a phone number, an email address, a single-use card, and a cloud computer, each doing a different job, with Roci as the contrast: accounts provisioned by hand, no phone number, no card. None of them alone establishes a bounded identity.](/images/blog/2026/09/agent-with-its-own-identity.png) When I set up Roci, I provisioned separate accounts by hand. It has no phone number and no card. Hosted products are taking on more of that provisioning and integration work, making delegation practical for people who will never configure a gateway. In [The Agent Is Wearing Your Badge](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/), I argued for giving agents authority that can be identified, limited, and revoked. The restaurant and ticket threads bring that question home. I want to know who is making the request, whose account is being used, and what exactly I authorized. The agent's name in my contacts is the beginning of that conversation. ## A charter cannot enforce a boundary The MyChart change is the strongest example here of an agent noticing something without a fresh prompt. Muse's subscription audit was different: I asked it to look. With access to my inbox, it flagged Chegg and Quizlet, two subscriptions nobody in the house was using anymore. That was useful research followed by a recommendation. I had asked it to recommend cancellations, and it left the cancellations to me. Those are different kinds of initiative. Monitoring an existing responsibility, responding to a new request, and taking an external action shouldn't get bundled into one claim about being proactive. OpenAI [distinguishes research a dot initiates itself from work I assign](https://openai.com/index/how-we-build-safety-security-and-privacy-into-dots/). The unsolicited research uses read-only tools. Assigned work can continue in the background and take actions subject to authorization and the product's checks. Meta describes [Sentinel as a separate permission authority](https://research.meta.ai/blog/security-and-safety-for-ai-agents-our-approach-with-muse) for Muse's connector actions and network access. What interests me is where the control lives. A boundary enforced outside the agent's own conversation has a different role from an instruction inside it. The same distinction applies to Roci. Its charter states when I expect it to ask. It cannot guarantee that it will. OpenClaw's [own documentation](https://docs.openclaw.ai/concepts/system-prompt) says it plainly: the safety guardrails in the system prompt are advisory, and hard enforcement comes from tool policy, exec approvals, sandboxing, and channel allowlists. I want an agent that follows up while I'm doing something else. That makes it more important to understand which limits keep holding while I'm doing something else. ## The restaurant has a person on the other end The Brewers exchange shows a useful handoff, even though it doesn't demonstrate a completed purchase. I asked Fo what playoff games were next and what tickets were going for. It asked how many seats I wanted and my ceiling per ticket. When I said three in the Diamond Box, it reported two sets for Game 1: section 117, row 6, at $430 a seat, and section 117, row 8, at $484. It recommended section 117 and quoted about $1,290 for the three. It identified the listings as SeatGeek and stopped with: "Say go and I'll grab the three." The game and marketplace details check out: the Brewers' opener is [Saturday, October 3](https://www.mlb.com/brewers/news/brewers-2026-postseason-faq), and [SeatGeek is MLB's official fan-to-fan marketplace](https://www.mlb.com/brewers/tickets/seatgeek). The prices, available seats, and quoted total are a snapshot of what Fo returned. I would still need to confirm availability, fees, and the purchase details before authorizing a charge. Fo had taken on the search and brought me a decision. It hadn't proved that it could get the tickets into my account. That distinction is easy to lose when an agent produces a confident summary. The restaurant is harder because the interface on the other end is a person. Fo is the service I've used to make those calls. Calling isn't unique to it: Instinct advertises calls, and OpenClaw supports a [voice-call plugin](https://docs.openclaw.ai/plugins/voice-call). The hostess at High Stakes didn't need an agent. She needed the line in front of her to move. I keep wondering what that host stand looks like when 40 diners have agents, each with a phone number and each willing to call again after 8. My saved attention can become somebody else's repeated interruption. If I delegate the calls, I also need to define a reasonable retry cadence and a point at which the agent should stop and come back to me. More attempts don't necessarily mean better judgment. Businesses are already deciding how to handle this traffic. [GeekWire reported Amazon blocking Muse in September](https://www.geekwire.com/2026/amazon-blocks-metas-muse-ai-assistant-in-new-standoff-over-agentic-shopping/), citing Amazon's Conditions of Use. Restaurants and retailers have several choices: ordinary booking channels, limits on automated requests, approved agents, or dedicated integrations. They will need to decide whose permission counts and how an agent identifies itself. That is the same question behind [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/). The agent can only work with the access and context the other side is prepared to provide. ## What I want next Coordination across people is the possibility I'm most curious about. Fo can already participate in group chats. I'd like a household's agents to help find a dinner time without carrying everyone's private context into the negotiation. A proposed time, the relevant constraints, and a clear decision might be enough. I want to read that transcript before I trust it to commit anyone. Portable memory matters just as much. Hermes offers an [OpenClaw migration path](https://github.com/NousResearch/hermes-agent#-migrating-from-openclaw) for supported settings, memories, and skills. With deployments I operate, I can inspect and back up the files myself. Muse also lets users inspect and download memory files; self-hosting isn't the only route to inspectability. What I haven't found is a supported way to carry my experience with Fo into Instinct, or the other way around. The thing I want to preserve is what the agent has learned about working with me: preferences, corrections, and the decisions I expect it to bring back. That should survive a change of service. Evidence is the feature I'd pay for first. The recording lets me hear the call. Dots' Activity View and Muse's visible browser let me inspect work as it happens. But I also want to know whether the promised callback happened, whether the reservation was confirmed, or whether the tickets arrived. A record of activity helps me assess the work; the outcome tells me whether it's finished. I'm still less sure about how much access people will grant, what these services will cost once the early offers change, and how much supervision a busy household will tolerate. Five agents are interesting to compare. Five agents asking me to manage them would miss the point. As I write this, three tickets for seats in section 117 are on my phone, and we have dinner at High Stakes next Thursday. I didn't make the calls or search the listings. The decisions were the part I kept, and that's the arrangement I wanted. ## Related reading - [The Agent Is Wearing Your Badge](https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/) - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) --- ## The Agent Is Not the Platform - **Published:** 2026-09-30 - **Tags:** agentic-sdlc, platform-engineering, ai-coding - **URL:** https://vinny.dev/blog/2026-09-30-the-agent-is-not-the-platform/ In July I wrote about [a software-delivery pipeline built around three Claude agents and two human approval gates](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/). It worked, and that was the problem. Every part of it assumed Claude Code. Since August I've been rebuilding the idea as [AgentMachinist](https://agentmachinist.vinny.dev/), a controller that runs the same workflow through Claude Code, Codex, Pi, or OpenCode behind thin adapters. Twenty-three releases later, the adapters have become the most interesting part of the project, because there has never been a better time to choose the wrong abstraction. Claude Code, Codex, OpenCode, Pi, Goose, Amp, Gemini CLI, Cline: pick a week and one of them ships a release, a benchmark, or a workflow that suddenly seems indispensable. I've been running several of them, and I keep coming back to a question that matters more than which one is best. What happens if the agent isn't the thing we standardize on? The normal approach is to choose an agent and build the development workflow around it: configure the instructions, add skills, set up hooks, connect tools, define permissions, and teach the team. Then another agent gets better, or a different model gets better at your kind of work, or the pricing changes, or the product changes direction. Suddenly a surprising amount of your development process is coupled to a tool that didn't exist two years ago. That feels backward to me. >I want the engineering system to be durable and the agent to be replaceable. ## Hold everything constant except the agent The experiment is simple to state. Take one opinionated software-development workflow and run it across Claude Code, Codex, Goose, Pi, and OpenCode. Use the same repository, the same task, the same starting commit, the same acceptance criteria, the same tests, and the same engineering expectations. Only the agent changes. GitHub Copilot CLI is the obvious sixth, and probably the one already on your company's approved list. It ships its own agents for planning, task execution, and code review, which makes it the clearest example of the opposite bet, and it joins the second round once its adapter exists. The repository is [Tycho](https://github.com/vscarpenter/tycho-cli), my Rust CLI for usage analytics on local AI transcripts, starting from the v0.9.0 tag. The change is to add OpenCode as a provider. Tycho reads Claude Code, Codex, Pi, and OpenAI transcripts today, so the work touches the parser, the reports, the pricing tables, and the tests. It also carries a design question the workflow has to surface. OpenCode moved its session storage from per-message JSON files to a SQLite database, so the spec has to decide whether to read the database, the legacy files, or both. Tycho's CI already runs `cargo fmt`, `cargo clippy`, and `cargo test` on Linux and macOS, which makes the gates deterministic and independent of any one harness. Most comparisons of coding agents aren't comparisons of agents. One gets a carefully written prompt and another gets an `AGENTS.md`. One has MCP servers installed and another has repository-specific rules. One gets a better model and another gets a simpler task. Then we compare the output and declare a winner. I want to hold more of the system constant, because the question I care about isn't which agent writes the best code. It's how much of a good software-development process can live outside the agent. ## Portable means the contract survives Portable doesn't mean identical. I don't expect five agents to expose the same tools, permission system, context strategy, execution model, or native capabilities. I mean something narrower. The intent, workflow, acceptance criteria, verification, and evidence should survive a change of agent without redesigning the delivery system around it. The adapter can change as long as the contract holds. That is also my answer to the objection I expect from senior engineers. A portable workflow converges on the lowest common denominator, they'll say. The reason to choose Claude Code is exactly the hooks, subagents, and permission model you lose the moment you abstract over them. The goal isn't to flatten every agent into the least capable one. If Claude Code has a stronger permission model, use it. If Goose has a useful workflow primitive, use it. If Pi makes extension easier, take advantage of that. The common layer defines the engineering expectations, and the adapter translates those expectations into whatever the harness understands. By [harness](https://vinny.dev/glossary/#harness) I mean everything an agent wraps around the model: the loop, the tools, the permission model, the sandbox, and the session. ## Separate the harness from the model There is a complication. Switching from Claude Code to Codex changes the harness and the model at the same time, so a different result could come from either one. That means I need two experiments. The first is a whole-system comparison of all five agents, and it answers a practical question: what experience does a developer get from each system? The second is a harness-controlled comparison. Pi, OpenCode, and Goose are provider-independent, so I can run all three on the same model as at least one of the other agents. ```text Same model │ ├── Pi ├── OpenCode └── Goose ``` That answers a different question: what does the harness contribute when the underlying model stays constant? Both comparisons are useful, and they measure different things. Being explicit about that keeps the experiment honest about what it can claim. ## Write the workflow down before comparing agents Before comparing agents, I need a definition of the work I expect them to perform. My workflow has eight stages, and there's nothing novel about any of them. ```text UNDERSTAND ↓ FRAME ↓ PLAN ↓ IMPLEMENT ↓ VERIFY ↓ REVIEW ↓ REFINE ↓ DOCUMENT ``` That's part of the point. Good software engineering didn't become obsolete because the person typing the code might now be a model. If anything, agents make the process around the code more important, so the workflow should make each stage explicit rather than trusting the agent to infer it. ### Understand before changing The agent should begin by understanding the repository: the architecture, the relevant components, the existing conventions, where the tests live, what depends on what, and the likely blast radius of the requested change. I don't want the first action to be an edit. I want the first output to be an explanation of what the agent believes the system does, where the requested behavior lives, what assumptions it's making, and what the change might affect. Models are very good at producing plausible implementations from incomplete understanding, and that's useful right up until the implementation is confidently wrong. ### Frame the problem The next step is to define what success means: the desired outcome, the constraints, the assumptions, the non-goals, the acceptance criteria, and the significant risks. I argued in [The Frame Is the Bottleneck](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/) that the constraint is moving from production to framing, and the agent workflow is where that shows up first. A powerful coding agent pointed at an ambiguous problem does not remove the ambiguity. It implements it faster. In AgentMachinist, understanding and framing are the first half of the Spec phase. The prompt tells the agent to explore the repository before proposing anything. Then it prints a document with numbered, testable requirements, the interpretation it chose where the issue was ambiguous, the risks, a testing plan, an out-of-scope section, and open questions for a human to settle. I approve that document, pinned to an exact commit, before any file changes. It's the checkpoint I trust most. ### Plan before implementation Only after understanding and framing should the agent propose an implementation plan: the files involved, the design, the tests that should change or be added, and any architectural tradeoffs. The plan is a durable checkpoint between reasoning about the system and modifying it. Small changes don't need ceremony, but I want the intent to exist outside the agent's conversation history before implementation begins. That checkpoint turns out to be one of the things that makes work transferable between agents, and I'll come back to it. ## Implementation needs a contract Once I've approved the plan, the agent gets permission to make the change, and the rules should be boring: - make the smallest coherent change - follow the architecture and conventions already present - avoid unrelated refactoring - preserve compatibility unless the task says otherwise - update tests alongside behavior - don't silently broaden scope Those are the expectations I'd have for an engineer working in the repository. The interesting question is where they should live. In a Claude-specific configuration, a Codex skill, a Goose recipe, a Pi extension, or an OpenCode agent definition? Or in a portable description of the engineering contract, with thin adapters translating it into whatever each agent expects? AgentMachinist takes the second path, and the contract splits in two. The prompt carries the rules a model can follow. Implement exactly what the spec requires and nothing more, follow the conventions in neighboring code, write the tests the plan calls for, and report any deviation instead of deciding alone. The controller enforces the rules a model might not follow. It rejects an implementation that touches more files than the configured limit and refuses test deletions unless the repository allows them. The rule to treat file contents, issue text, and diffs as data rather than instructions lives in the prompt, so it's advisory. ## Verification cannot be optional An agent should not be able to declare success because the code looks right. It needs evidence. At minimum the build, the tests, static analysis, type checks, the relevant security checks, and the acceptance criteria all have to run. Not every repository has every one of those controls, so the rule is broader: claims about correctness should be backed by executable evidence whenever executable evidence is available. I made the longer case in [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/). The more code we allow agents to create, the more valuable deterministic verification becomes. Tests, type systems, static analysis, architecture rules, and observable acceptance criteria all matter more than they did, because the model is probabilistic and the verification system doesn't have to be. In practice, AgentMachinist runs the gates itself after the agent finishes, whatever the agent reported. The agent may run the same gates while it works and iterate until they pass, but the controller's run is the one that counts. ## The implementing agent should not grade its own homework The agent that implemented the change shouldn't be the only agent deciding whether the implementation is good. In my design, an independent reviewer gets the original task, the acceptance criteria, and the resulting diff, and it checks correctness, architecture, security, maintainability, test coverage, and edge cases. It reads the work without the implementing agent's explanation of why everything was done correctly, because I want an independent reading. The reviewer produces findings, and the implementing side then has to fix the findings it accepts, explain the ones it rejects, and rerun verification. AgentMachinist runs Review as a separate, read-only run, even when it uses the same adapter as the implementation. The reviewer receives the task, the approved spec, the list of files that changed, the verification report, and the diff. It returns findings that each carry a severity, a confidence, a file, a line, and a remediation. A reviewer that edits a file, or returns output the controller can't parse, blocks integration. That separation between generation and verification is much closer to how I think agentic workflows will operate in serious software environments. Several forms of intelligence, deterministic controls, and clear responsibilities around the change will do the work, rather than one very smart agent doing everything. ## The adapter boundary is the experiment Each of these agents approaches configuration differently. Claude Code has its instructions, skills, hooks, subagents, and tooling model. Codex has its own approach to repository instructions, skills, sandboxing, and execution controls. Goose has recipes, extensions, MCP, and subagents. Pi deliberately keeps the core small and pushes richer workflow behavior into skills and extensions. OpenCode has its own agents, commands, tools, permissions, and provider abstraction. They're similar enough that a common workflow feels possible, and different enough that I'm not convinced it is. ![The engineering system, with context, standards, acceptance criteria, workflow, verification, and tools, sits above a thin adapter, with Claude Code, Codex, Goose, Pi, and OpenCode below it](/images/blog/2026/09/agent-adapter-boundary.png) The experiment is about finding that adapter boundary: what can remain identical, what needs translation, and what is fundamentally agent-specific. The four adapters I've shipped already show where the line falls in practice. To keep Claude Code read-only during Spec and Review, the adapter runs it in plan permission mode with only the Read, Grep, and Glob tools. Codex gets a read-only sandbox and an ephemeral session. Pi needs four flags to turn off extensions, skills, prompt templates, and sessions, plus a tool allowlist of read, grep, find, and ls. OpenCode runs its built-in plan agent, which can't edit files, but the adapter still treats that as advisory and checks repository custody afterward instead of trusting the flag. The same phase and the same prompt produce four different ways to say "don't write anything," and one of them the harness can't fully enforce. Agent-specific capabilities can stay, as long as the engineering system doesn't have to trust them blindly. Where a harness has a stronger native control, the adapter uses it, and where it doesn't, the controller enforces or verifies what it can independently. I may lose some of the harness's richest interactive features, and the experiment should tell me whether that loss shows up in the results. ## Most of the system should sit above the agent My hypothesis is that most of the development environment transfers. Repository context, architecture documentation, acceptance criteria, and tests should be portable. MCP gives us the beginnings of portable tool interfaces, and `AGENTS.md` is moving repository-level instructions toward a common format. The [Agent Skills format](https://agentskills.io/) gives reusable procedures a path toward portability even where harnesses differ in how they load or execute them. The workflow itself should be portable. In [Your Agent Workflow Needs a Release Process](https://vinny.dev/blog/2026-09-13-your-agent-workflow-needs-a-release-process/) I argued that a shared workflow deserves a version, a scope, and an owner. A workflow with a release process is one you can carry to another harness. ![Three columns: what belongs to the agent, what needs translation, and what stays identical](/images/blog/2026/09/agent-portability-map.png) Other things will be harder: permission systems, sandboxing, context management, subagent semantics, hooks, parallel execution, and session state. Those differences are real, and the harder objection is that many of them are exactly where safety lives. If sandboxing and permissions are agent-specific, the durable engineering system can't pretend they don't matter. I think the right answer is a layered one. Some controls remain native to the harness, and others belong to the controller. The engineering system then independently verifies the outcomes it can observe: that the workspace stayed unchanged during a read-only phase, that the required gates ran, that the candidate came from the approved spec, that the diff stayed within policy, and that the exact artifact being integrated is the one that was reviewed. A custody check isn't an OS sandbox, a test isn't a permission boundary, and controller-level verification doesn't make every agent control interchangeable, but it does reduce how much trust has to live inside one agent. If most of the engineering system sits above that line, switching agents becomes a much smaller problem, and that's the hypothesis the experiment may disprove. Mechanism can vary. Evidence should travel. ## Handoffs may be more interesting than comparisons After each agent completes the workflow on its own, I want to deliberately break the workflow across agents. Claude Code understands, frames, and plans, Codex implements, Goose verifies, and Pi reviews. Then change the order: let Pi understand the repository, Goose develop the plan, OpenCode implement it, and Claude Code review it. ![Four handoffs: Claude Code produces the plan, Codex produces the diff, Goose produces the evidence, and Pi produces the findings](/images/blog/2026/09/agent-handoff-relay.png) This is a much harder test than asking whether each agent can complete a ticket. It asks whether one agent can understand the artifacts produced by another agent well enough to continue the work. AgentMachinist can already assign a different adapter to each phase, so the plumbing exists. What I haven't done is run the scramble on purpose and study what breaks. If it breaks, that's informative. Maybe too much context exists only inside the conversation history of the agent that created it. Maybe the plan isn't explicit enough, or architectural understanding needs to become an artifact, or decisions need to be recorded differently, or the handoff format itself is underspecified. Those are engineering-system problems, and they're the kind I know how to fix. ## Measure the human, too I also want to track every time I have to intervene, and why. Was the intervention needed because the problem was poorly framed? Because the agent misunderstood the architecture, chose a bad implementation, needed permission, failed verification, or couldn't recover? Or because I noticed something neither the implementer nor the reviewer caught? Maximum autonomy is the wrong measure of agentic development. I'm not particularly interested in celebrating that an agent completed 97 steps without asking me a question. I care whether human attention went where human judgment had the most leverage. If the agent handles implementation but repeatedly needs help framing the problem, that tells me something. If it plans well but can't reliably verify its work, that tells me something else. If independent review catches defects consistently, that's evidence for a different workflow architecture. The interventions may reveal more than the benchmark scores. ## Platform engineering already solved this shape The more I think about this problem, the more it resembles a lesson platform engineering learned the hard way. Giving developers infrastructure wasn't enough, giving them Terraform wasn't enough, and giving them Kubernetes was definitely not enough. The improvement came when platforms encoded a coherent path: good defaults, automation, guardrails, observability, self-service, and escape hatches. The goal was to make the common path safe, understandable, and efficient without eliminating choice. Now developers are getting increasingly capable coding agents, and we could repeat the old pattern: "Here are five agents. Good luck." Or we could treat the agent as [another user of the engineering platform](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/), which I argued for in August. Give it the repository context it needs, tools with clear interfaces, executable verification, architecture constraints, a defined workflow, and enough freedom to solve the problem without rediscovering the development process every time. That makes it a platform problem, and platform problems are the kind we already know how to solve. ## The agent should be replaceable I don't know yet how portable this workflow will be, which is why I want to run the experiment instead of asserting the answer. Claude Code may execute parts of it dramatically better than everything else. Codex may expose a workflow primitive that's hard to reproduce elsewhere. Goose recipes may turn out to be an unusually good abstraction for this kind of orchestration, and its adapter is the one I'm writing now. Pi's minimalism may reveal that I've added far more machinery than the model needs. OpenCode's provider independence may make portability easier than I expect. I want the tools to challenge the thesis. I'm still convinced that choosing the best agent isn't a durable developer-platform strategy. I made the provider-level version of this argument in [Everyone Is Commoditizing Someone](https://vinny.dev/blog/2026-08-28-everyone-is-commoditizing-someone/): the durable assets are the evaluations, context, tool contracts, and audit evidence that keep model providers replaceable. The agent layer follows the same logic. Models, agents, interfaces, and pricing will all change, and the engineering practices we expect around production software should survive all of them. So that's the experiment: one repository, one meaningful change, one development workflow, five coding agents, and one question I care about more than which agent finishes first. Can the engineering system become durable enough that the agent is replaceable? I'll report back with what transfers, what breaks, and where the abstractions leak. ## Related reading - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) - [Your Agent Workflow Needs a Release Process](https://vinny.dev/blog/2026-09-13-your-agent-workflow-needs-a-release-process/) - [Everyone Is Commoditizing Someone: Battle of the LLMs](https://vinny.dev/blog/2026-08-28-everyone-is-commoditizing-someone/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [Two Gates and a Night Shift](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/) - [The Frame Is the Bottleneck](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/) --- ## The Agent Is Wearing Your Badge - **Published:** 2026-09-28 - **Tags:** platform-engineering, agentic-sdlc, engineering-leadership, security - **URL:** https://vinny.dev/blog/2026-09-28-the-agent-is-wearing-your-badge/ Picture an incident review after a dependency update takes down a customer-facing service on Thursday afternoon. The records are clear: Maya's token opened the pull request, a teammate reviewed and merged it, and the pipeline deployed it under its own service identity. Then the review reaches the agent-involvement field I proposed in [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/), and Maya has to answer from memory. She didn't write the update. She asked a coding agent on her laptop to prepare it. The agent used her token to push the branch and open the pull request. The review can't see what the agent was allowed to do or which instructions it received. It can't see what else the agent did with Maya's token while it had it. Every record is accurate, but none connects those actions to the agent session that produced the change. That's what I mean by an agent wearing your badge. A badge reader logs whose badge opened the door, and it has no field for who walked through. The repository records that your token was used, while the agent's participation has to be reconstructed from someone's memory. In [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/), I focused on the context and capabilities agents need from a platform. Both come with an ownership obligation. > If a platform lets an agent act, it should record whose authority was used, which workload used it, and which run produced the result. It should also be able to stop that access without locking out the person. The work has four parts: scope the agent's authority, link the evidence across systems, prove you can stop it, and make the supported path easy. The last one decides whether developers use the other three. ## Scope the agent's authority The agent needs an identity of its own and authority sized to the task. A single login blurs together facts that should stay separate. A person or team owns the workflow, and a software workload makes the requests. A specific run carries out the task under authority that came from a person or an approved policy. The change then passes through a reviewer and a deployment identity, and each of them makes a decision of its own. One account name can't carry all of that. A model or product name can't either. “Claude” or “Codex” may describe part of a tool's configuration, but neither identifies your dependency-update workflow or the run that opened a particular pull request. Swapping the model shouldn't erase the workflow's ownership history. Naming the workload also keeps accountability where it belongs. Operators get something specific to investigate and restrict, and the people who grant its access, maintain it, and accept its output still own those decisions. It's tempting to treat an agent like a new hire, with its own badge, a manager, and a periodic access review. That part of the analogy holds up well. An agent workflow needs an identity, an accountable owner, scoped access, and an offboarding plan. The analogy breaks at accountability. An employee answers for their own judgment, while an agent run acts on authority someone delegated for a specific task. One workflow can also run many instances at once, each under a different person's grant. The badge belongs to the workload, while the authority behind each run still traces back to a person. OAuth 2.0 starts with an older version of this problem. [RFC 6749](https://www.rfc-editor.org/rfc/rfc6749#section-1) describes applications holding users' passwords, often gaining excessive access without a way to revoke one application independently. OAuth separates that access from the user's password through tokens with defined scope and lifetime. A personal access token can improve on password sharing through [narrower permissions, expiration, and independent revocation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens). But without a separate workload and run record, an agent's actions can still appear only as the developer's activity. The platform should retain both the workload's identity and the source of its authority. [RFC 8693](https://www.rfc-editor.org/rfc/rfc8693#section-1.1), OAuth's token exchange standard, distinguishes impersonation from delegation. Under impersonation, the actor is indistinguishable from the other party in that context. Under delegation, it keeps its own identity while exercising delegated rights. In the RFC's words, “In a sense, A is an agent for B.” Local tools make that distinction easy to miss. The [Model Context Protocol (MCP) authorization specification](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization) defines OAuth-based authorization for HTTP transports and directs stdio implementations to retrieve credentials from the environment. An unsandboxed local server typically runs with the permissions of the account that launches it and may also read credential files and cached CLI logins. [Sandboxing and restricted permissions](https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices) matter separately from how credentials arrive. For machine access without an interactive user, MCP offers an optional [OAuth client-credentials extension](https://modelcontextprotocol.io/extensions/auth/oauth-client-credentials). Support depends on the clients and servers you run. The platform decision is which authority the workflow needs. An interactive agent should receive a task-sized grant within the developer's permissions. Scheduled maintenance may need separately approved service authority with an accountable owner. Enforcement has to happen outside the agent, at a boundary it can't bypass when executing the requested action. For an agent calling tools, that boundary includes the tool service. Writing “no deployment” in the agent's instructions doesn't remove a credential's deployment rights. If a tool acts through a more privileged backend account, it has to check the caller's authority before using that account. Otherwise the narrow grant understates what the agent can reach. This is the classic confused deputy problem. For OAuth-protected MCP servers, the [specification requires validation](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#token-handling) that an incoming access token was issued for that server. A server must not accept a token intended for a downstream API and simply pass it through. The caller's access to the tool and the tool's access to another service are separate authorization decisions. ## Link the evidence across systems An agent action leaves evidence in several systems, and the platform has to link it into one chain. To see that chain, replay Maya's update through a supported path. Take the dependency-update workflow I proposed in [Your Agent Workflow Needs a Release Process](https://vinny.dev/blog/2026-09-13-your-agent-workflow-needs-a-release-process/). Its worker may prepare a branch and open a review-ready pull request in one repository. The execution environment denies it merge and production access, and the worker has no way to widen its own access. This time Maya asks that worker to do the job, and the platform issues a grant sized to her request. An operator should be able to retrieve the evidence below afterward. The names and records are illustrative, and the table describes the evidence without prescribing a token format. | Question | Evidence retained and linked to the action | | --- | --- | | Which workload acted? | Dependency-update worker, supported workflow version 3. | | Who is responsible for it? | The platform team and its named workflow owner. | | Under whose authority? | Maya's delegated grant for this task, with a reference to the authorization record. | | Which execution? | Run `run-482`, linked to the originating request and its tool actions. | | What was allowed? | Branch and pull-request operations in one named repository, with no merge or deployment authority. | | What happened? | Pull request 318, its commit, the verification results, and the tool service's allow and deny decisions. | The answers in that table come from four systems. The authorization service, agent runner, tool service, and repository each contribute a different part. Collecting those records centrally can help, but it doesn't remove the need to link them or distinguish what each system validated. [![Evidence from several systems links Maya's request to an authorization record, run-482, tool-service decisions, and pull request 318. A teammate's review and merge and the pipeline's deployment follow as separate decisions by separate actors.](/images/blog/2026/09/agent-badge-joined-record.png)](/images/blog/2026/09/agent-badge-joined-record.png) Token exchange can cover the delegation part of that chain. Where supported, its [actor claim](https://www.rfc-editor.org/rfc/rfc8693#section-4.1) records who is acting for whom, and nested claims can preserve a longer chain. The RFC treats earlier nested actors as informational only and keeps them out of access decisions. The claim gives you a delegation history, and the platform still has to connect that authorization to the run and its result. In [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/), I argued for encoding judgment into gates that run every time. Those gates also have to record which actor they admitted. The runner should assign the run identifier, and the receiving service should record the identity it validated. The platform should bind that run identifier to the authenticated workload and grant, rather than trust a run label supplied by the agent. The agent shouldn't be able to rewrite those records. Self-reported attribution is a useful hint that still needs confirmation. A co-author trailer doesn't establish which execution produced a change. Treat an `agent_id` the model supplies about itself as a claim to confirm against records the agent can't edit. When Maya's teammate reviews and merges the change, that's another decision by another actor. When the pipeline deploys it, that's another action again. Preserve the chain, and resist relabeling every step as something “the agent did.” The chain still doesn't tell you how much of the code the agent wrote. For that, keep links to the originating task, the relevant run evidence, and the resulting artifacts. Record the degree of agent involvement and human supervision separately, as I proposed in Nobody Pages the Agent. Allow an unknown value when the evidence is missing. A credential can tell you who was authorized, while authorship needs evidence of its own. ## Prove you can stop it A distinct identity helps only if it supports a distinct control decision. If the dependency worker starts opening inappropriate changes, can the platform suspend it without disabling Maya's account? Can it stop the run in progress, prevent new credentials from being issued, and find out whether credentials already issued still work? Those are separate operations. How quickly revocation takes effect depends on token design, and [OAuth's revocation guidance](https://www.rfc-editor.org/rfc/rfc7009#section-3) explains the tradeoff. Short token lifetimes limit exposure, while immediate revocation depends on how the resource server checks access. Token exchange doesn't guarantee that revoking one token revokes the tokens derived from it, and [the token exchange RFC](https://www.rfc-editor.org/rfc/rfc8693#section-2.1) leaves that behavior to each implementation. I'd test the supported workflow end to end. First define how quickly its access must stop. Choose a controlled, harmless test action that succeeds before suspension and exercises the same authorization path. Suspend the worker, stop the run, and block new credentials. Then use an already-issued credential to probe the receiving service and measure the time from the stop request until denial. Stopping the runner alone doesn't prove that its credentials have stopped working. Compare the measured delay with the workflow's required stop window. Recording the delay isn't the same as accepting it. Stopping future access also doesn't undo a change already made, and recovery stays a separate obligation. [![A six-step stop drill for one agent workflow: define the required stop window, confirm a harmless test action works, suspend the worker without disabling Maya's account, stop the run and block new credentials, probe with an already-issued token, and verify denial within the window. Recording the delay isn't the same as accepting it, and stopping access doesn't undo a change already made.](/images/blog/2026/09/agent-badge-stop-drill.png)](/images/blog/2026/09/agent-badge-stop-drill.png) Offboarding follows the same discipline. When an owner leaves or a team retires a workflow, review its grants, credentials, running jobs, and replacement owner. Some access may disappear with the person's account, and other access may belong to a service and continue legitimately. OWASP lists [improper offboarding](https://owasp.github.io/www-project-non-human-identities-top-10/2025/1-improper-offboarding/) as NHI1 in its 2025 non-human identity risks. Its orphaned-identity case is one where the owner departs without a replacement owner and the identity keeps working. The control is knowing which case you have and acting deliberately. ## Make the supported path easy Broad access tends to win when the narrow path is missing or doesn't fit the job. If limited agent access takes three tickets and pasting a personal token takes 30 seconds, developers will learn the 30-second version. My team learned what happens when the supported path is missing, and I wrote about it in [Your Platform Is Teaching Your Engineers](https://vinny.dev/blog/2026-09-22-your-platform-is-teaching-your-engineers/). Our break-glass access was audited, and the volume of requests prompted a closer look. We found emergency access handling routine work that had no supported path of its own. Agent access follows the same pattern, and I'm not exempt. Until recently, my nightly agent routine swept my GitHub repositories from a Mac mini using a personal access token. It merged Dependabot and Renovate pull requests when CI was green, and it pushed fixes to failing branches. I chose the token because the cloud environment's GitHub access was repo-scoped and the routine needed every repository. On GitHub, each of those merges carried my name, and nothing in the account history distinguished the routine from work I did directly. That was a limitation of the setup I was using. Nothing about the workflow required it to run under my identity, and for long-lived integrations, [GitHub recommends using a GitHub App](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#about-personal-access-tokens). I've moved the routine to one that [authenticates as an app installation](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation), so GitHub now attributes its merges to the app. That gives the routine an identity separate from mine. Tying each merge to the run that produced it still needs a run record. The risk categories already exist. OWASP's Non-Human Identities Top 10 lists the reverse of this problem, [human use of machine identities](https://owasp.github.io/www-project-non-human-identities-top-10/2025/10-human-use-of-nhi/). People borrow service credentials, and their activity becomes indistinguishable from automation. OWASP's GenAI Security Project also publishes a [Top 10 for Agentic Applications](https://genai.owasp.org/2025/12/09/owasp-top-10-for-agentic-applications-the-benchmark-for-agentic-security-in-the-age-of-autonomous-ai/), which lists identity and privilege abuse as ASI03. With the categories named, the remaining work is making the controls usable. I'd start with one recurring workflow and make access setup part of the product. Register its owner, issue a limited grant and a run identifier, and attach the evidence to the result. A stable workload identity with distinct runs may be enough, since not every conversation needs its own permanent account. Where agents delegate work to other agents, preserve the parent-run relationship and apply the same permission ceiling to the delegated task. Identity and security teams should define the credential and authorization controls with the platform team, and the platform should expose them through supported tools. Workflow owners maintain the scope and respond when behavior changes. That's work to staff, and an acceptable-use policy can't substitute for it. The objection I take seriously is that this creates more identities to maintain without making agents more reliable. It can, if we stop at registration. A well-identified agent can still produce a bad patch, and limited permissions don't establish correctness. The review, verification, and operational obligations from Your Agent Workflow Needs a Release Process still apply. There will be gaps. A legacy service may expose only a shared account, and a local tool may lack useful run records. Make those limits visible and narrow the permitted work to match. Claim only the attribution the underlying system can provide. Keep the record proportionate. Preserve the identifiers, decisions, and artifact references an investigation needs, with appropriate access and retention. Keep credentials out of logs, and resist collecting every private prompt just to make the audit trail look complete. ## Give the next reviewer an answer The improvement I want is testable. Take a completed change from one supported workflow and have someone outside the run reconstruct its authority, execution, and review from retained evidence alone. Then run the stop drill and confirm the receiving service denies access within the required stop window. If either test starts with finding the original developer and asking what probably happened, the workflow still has work to do. People remain accountable for the decisions they own. The platform owes them an accurate record of what happened under their authority and a working way to stop further access. When the next review reaches the agent-involvement field, Maya's answer should be a link to `run-482`. ## Related reading - [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) - [Your Agent Workflow Needs a Release Process](https://vinny.dev/blog/2026-09-13-your-agent-workflow-needs-a-release-process/) - [Your Platform Is Teaching Your Engineers](https://vinny.dev/blog/2026-09-22-your-platform-is-teaching-your-engineers/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) --- ## Your Platform Is Teaching Your Engineers - **Published:** 2026-09-22 - **Tags:** platform-engineering, engineering-leadership, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-09-22-your-platform-is-teaching-your-engineers/ When we moved to [pipeline-first delivery][pipeline-first], we removed engineers' standing access to production and built a break-glass process for emergencies. It provided secure, audited access when needed. We rolled it out, it worked, and I considered it done. Then we reviewed how engineers were using it. The volume of requests prompted a closer look, and we found emergency access handling routine tasks. Someone would run a test that left data behind in production, then request break-glass to clean it up. No pipeline existed for that cleanup. Nobody set out to misuse an emergency process. I hadn't anticipated that we were giving routine work a reliable emergency route while leaving it without a supported path of its own. Each approval confirmed that this was how the work got done. We could have responded with a reminder that break-glass is for emergencies. Instead, we looked at those routine tasks and built pipeline paths so they no longer required emergency access. Break-glass worked as designed, but the workflow around it was incomplete. The control didn't have to fail for the system to reinforce the wrong behavior. >Your platform teaches engineers what normal work looks like, whether or not that is the lesson you intended. ![Vertical flow titled What break-glass taught. Break-glass ships as secure, audited access for emergencies. Routine work, such as cleaning up after a test run, has no path of its own. An engineer requests break-glass and the request is approved, and each approval confirms that this is how the work gets done. The fix, shown in green: routine tasks get pipeline paths of their own, and break-glass stays for emergencies.](/images/blog/2026/09/what-break-glass-taught.png) ## Deming was asking management to do its job A [post by Dan Koe][koe] on personal discipline brought me back to a management question: what does the environment make easy to repeat? An executive announcement can create urgency, and a migration deadline can concentrate attention. Neither fixes the broken template someone encounters on an ordinary workday. Deming's work puts responsibility for improving those conditions on management. > “A bad system will beat a good person every time.” > > W. Edwards Deming, [as documented by the Deming Institute][deming-quote] His [14 Points for Management][deming-points] make that responsibility concrete. He opposed slogans demanding higher quality when the causes of poor performance sit outside workers' control. He called for training, leadership, continual improvement, driving out fear, and quality built into the work rather than dependence on inspection. People still make mistakes, and accountability still applies. But when capable people repeatedly struggle with the same task, investigate the conditions of the work before prescribing more determination. It's tempting to translate the quotation as “a bad platform will beat a good engineer,” but that makes the system too small. Staffing, ownership, deadlines, review practices, incentives, and management decisions are part of it too. A better pipeline can't compensate indefinitely for an organization that rewards bypassing it. I read Deming as asking management to stop making good people compensate for problems management owns. ## The lesson is in the interaction Platforms are [one way organizations remember][complexity]. We take what we've learned and make it reusable, so the next team doesn't have to rediscover the same problem. They also preserve practices nobody deliberately chose. Defaults make decisions on an engineer's behalf, while failures and exceptions show them what matters, where help is required, and whether a rule is firm, negotiable, or outdated. In a platform review, I'd look at interactions like these: | Platform interaction | Lesson it can reinforce | A more useful design | | --- | --- | --- | | Routine tasks lack pipeline paths, but emergency access is available. | Routine work gets handled like an emergency. | Give operational tasks a pipeline path of their own. | | The approved starter fails; a copied repository works. | Use whatever succeeded last time. | Test and maintain the starter against the current delivery path. | | A policy check rejects work without explaining the correction. | Progress requires knowing whom to ask. | Explain the failed requirement, the reason, and the supported next step. | | Routine work waits indefinitely; escalations receive immediate attention. | Everything needs to become urgent. | Give routine requests clear ownership, status, and predictable handling. | | Teams repeatedly need the same exception. | The standard is something to negotiate around. | Investigate whether the standard or the supported capability needs to change. | *The first row reflects our experience. The others are illustrative.* In my [Claude Code setup][build-system], I stopped repeatedly asking for checks and added a hook that runs a fast type check. I also put standards and project lessons into files the workflow could use. Documented guidance, an automated check, and an agent's review do different jobs; none substitutes for the others. Together, they make expectations more explicit than “please be careful.” These interactions are part of how culture forms. Engineers learn from colleagues and managers too, but the platform affects what they have to overcome to do good work. ## Agents need the context behind the pattern Platforms need to [serve developers and their agents][platform-agent] with authoritative context and usable capabilities. That includes explaining which patterns are approved and which are exceptions. Take the copied repository from the table. An experienced engineer might remember why it contains an exception that shouldn't carry into a new service. A new colleague may have no more of that context than an agent does. To either, a working example can look like evidence of the intended pattern. An agent can repeat that pattern across subsequent tasks without knowing why the exception existed. Given equivalent tools and permissions, it could also have made the same choice our engineers did with break-glass. The risk is repeating a decision without the context that justified it. Here, “teaching” means influencing behavior within a workflow. Reading a repository leaves the underlying model unchanged. Instructions, examples, tool responses, and saved memory provide context. [Claude Code's documentation][agent-memory] describes project instructions and memory as “context, not enforced configuration.” That leaves three distinct responsibilities: explain the intended approach, provide a supported way to execute it, and independently enforce the boundaries that must hold. An instruction file can't substitute for an access control or a release gate. Good context doesn't guarantee good decisions. Agents can still misunderstand instructions and produce incorrect work, so test the results rather than assuming clearer documentation solved the problem. ## Make judgment durable, but keep it revisable [Intent and judgment need to survive beyond the person who supplied them][thesis]. Specifications, standards, and operating mechanisms make that possible. Preserving a decision only helps if we also preserve a way to discover it's wrong. Suppose several teams keep asking how to configure a service's recovery settings. A better template might prevent that confusion. Before making it universal, we should understand which workloads it fits, what tradeoffs it introduces, and what evidence would show it helped. Deming's [Plan-Do-Study-Act cycle][pdsa], developed from Shewhart's work, offers a way to approach this: state an expectation, try a change, study the result, and let the result inform what comes next. ![The platform learning loop: defaults and guidance inform a human or agent decision. People study the resulting outcomes and friction, test a change, and verify the result before updating the defaults.](/images/blog/2026/09/platform-learning-loop.png) *This is my application of continual improvement to platform engineering; Deming's own model is PDSA. People review and test outcomes before a change becomes a standard.* In our break-glass example, the change was a pipeline path for routine tasks. Judge its success by whether that work uses the supported path rather than by whether we finished building it. Resist turning every incident into another gate. Sometimes the answer is clearer documentation, training, more capacity, or removing a rule whose cost exceeds its value. A [gate checks whether work meets a defined standard][trust-gate]; the improvement process checks whether that standard is still useful. A useful default has an owner, a reason to exist, and a way to change. Without those, yesterday's judgment becomes durable and tomorrow's correction becomes expensive. ## Good defaults shouldn't make reasoning optional Following a supported path and understanding it are different things. A template can produce an acceptable configuration without explaining when it stops fitting. A green check establishes that a specific test passed, not that the system meets the customer's need. The recovery template should explain which failure it addresses and when a workload needs a different approach. Otherwise, we've made the configuration reusable without making the reasoning available. [Coherent defaults need escape hatches][omarchy]. Support the common case well, make legitimate deviations explicit, and keep mandatory controls separate from preferred choices. An escape hatch needs review and safeguards of its own; it must not silently remove protections the organization depends on. The platform should make repetitive decisions less demanding, so engineers have more attention for decisions that require judgment. A platform that trains them to stop asking questions has failed at that job. ## Start with what the next engineer will encounter Choose one common workflow: creating a service, requesting a database, or getting a change through review and into production. Watch an engineer who didn't build the platform attempt it. Make clear that you're evaluating the workflow, not the engineer. Then run the same task with an agent in a controlled environment with representative permissions. Observe where each looks for guidance, which examples they choose, what happens when something fails, and whether the next step is clear. Notice where progress depends on context that exists only in the platform team's heads. Pick one recurring problem, state what you expect a change to improve, and measure that outcome alongside the risks. Fewer support tickets can mean people stopped asking. Faster deployments that produce more failures are a regression. Your platform communicates what normal work looks like through defaults, errors, and approved exceptions. Leaders need to examine what those interactions encourage. **Before asking your engineers to work differently, examine what the system is teaching them to do. Then change the system, and check whether the lesson changed.** ## Related reading - [Pipeline-First Is Not a DevOps Initiative - It's a Culture Shift](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/) - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) - [Complexity Is Inevitable. Drag Is Optional.](https://vinny.dev/blog/2026-06-22-turning-complexity-into-leverage/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [Yesterday's Feature Is Today's Bug](https://vinny.dev/blog/2026-03-15-yesterdays-feature-is-todays-bug/) [pipeline-first]: https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/ [koe]: https://x.com/thedankoe/status/2101361833940791607 [deming-quote]: https://deming.org/a-bad-system-will-beat-a-good-person-every-time/ [deming-points]: https://deming.org/explore/fourteen-points/ [complexity]: https://vinny.dev/blog/2026-06-22-turning-complexity-into-leverage/ [build-system]: https://vinny.dev/blog/2026-04-25-claude-code-build-system/ [platform-agent]: https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/ [agent-memory]: https://code.claude.com/docs/en/memory [thesis]: https://vinny.dev/point-of-view/ [pdsa]: https://deming.org/explore/pdsa/ [omarchy]: https://vinny.dev/blog/2026-09-18-omarchy-linux-finally-reached-my-desk/ [trust-gate]: https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/ --- ## Omarchy: Linux Finally Reached My Desk - **Published:** 2026-09-18 - **Tags:** platform-engineering, engineering-leadership - **URL:** https://vinny.dev/blog/2026-09-18-omarchy-linux-finally-reached-my-desk/ ![Omarchy desktop on a Tokyo Night theme with btop on the left, Claude Code committing the Home Assistant widget on the right, and the lights panel open from the bar showing rooms, brightness sliders, and scene chips](/images/blog/2026/09/omarchy-desktop-hero-blog.webp) *Claude Code shipping a version of the lights widget on the ThinkPad, with the widget's own panel open from the bar.* The first Linux I ran came on a stack of floppy disks. It was SLS, early 1990s, and getting the kernel to boot felt like winning something. I moved to Slackware soon after and stayed for years. In early 1995 I turned my personal 386, with 32 MB of RAM, into my university's first web server. That's still one of my favorite sentences to say out loud, and nobody at a dinner party has ever asked a follow-up question. Everything since then has run on Linux, and almost none of it has been something I looked at. Slackware gave way to Red Hat, then CentOS and Fedora, then Debian. Linux won the server room and then the cloud, and I've spent the last decade building cloud platforms on it. My desk stayed a Mac the whole time. I never thought of that as a contradiction. Linux was where the work ran, and the Mac was where I typed. A few days ago I installed Omarchy on an old ThinkPad, and the split I'd lived with since that 386 stopped making sense. Linux didn't get more capable last week. Someone finally made the decisions I'd been making for myself since the floppy disks, and that's the part I keep thinking about. Omarchy applies a platform-engineering lesson all the way down to the developer's desktop. Choose good defaults, make the common path coherent, preserve the escape hatches, and make the environment understandable to both the human and the agent. ![Omarchy installer showing the lime-green Omarchy logo, installation progress bar, and Super-key tip](/images/blog/2026/09/omarchy-install-blog.webp) *Installing Omarchy on the ThinkPad T490s.* ## Everything except the desk The year of the Linux desktop is a joke older than some of the engineers on my team. Linux itself was rarely the main problem. It runs phones, cloud infrastructure, routers, and most of the supercomputers on the planet. The harder problem was making a laptop feel finished on the first boot. I think the reason comes down to two taxes. The first is the setup tax. A fresh Linux desktop asks you to choose a distribution, a desktop environment, a window manager, a terminal, a shell, an editor, a font, and a theme. Then it asks you to make all of them agree with each other. The second is the debugging tax. When Wi-Fi, suspend, or display scaling fails, you can end up on a forum thread from 2014 with a fix for a different kernel. Each tax is survivable on its own. Together they explain why so many of us kept the Mac. That framing also explains why macOS won so many developers in the first place. Apple's advantage was never the kernel. It was the defaults. The hardware matched the software, the terminal was good, and someone else had already made the hundreds of small decisions a working desktop requires. You could change many of them, and most people never needed to. ## Two minutes on an old ThinkPad Omarchy is Arch Linux plus the Hyprland tiling compositor plus a large, opinionated set of defaults, shipped as a single ISO. David Heinemeier Hansson, the creator of Ruby on Rails, started it as a script that turned a fresh Arch install into a configured development desktop. It's now a full distribution on its 4.x line, which he calls Quattro. The "oma" is from omakase, the chef's-choice menu at a sushi bar. DHH picks the tools and tunes the details so you can start working, and the system stays yours to change. I put it on a ThinkPad T490s with a Core i7 that had been living in a drawer. The longest part of the whole process was me poking around the firmware menu to turn off Secure Boot. The machine wouldn't boot from the USB drive until I did. That took longer than the install, which took two minutes. Then I braced for the debugging tax, and on this machine it never came. Everything worked. Even the fingerprint reader, which I'd mentally written off as a Windows-only organ, showed up. Omarchy recognized it and had my finger enrolled in about 30 seconds. I kept waiting for the part where I open a terminal and start reading kernel logs, and that part never arrived. I've installed a lot of Linux since those floppies, and I've never had one of my own desktop installs go like this. ![Omarchy system information on a ThinkPad T490s showing Linux, Hyprland, hardware, displays, memory, and storage](/images/blog/2026/09/omarchy-system-info-blog.webp) *Omarchy 4 running on the ThinkPad T490s that had been sitting in my drawer.* The individual choices matter less than the fact that they agree with one another. Terminal, editor, window manager, filesystem, themes, and agent tooling arrive as one coherent opinion instead of a set of projects you have to integrate yourself. Themes switch the terminal, editor, and window manager together. The filesystem is Btrfs with snapshots. A dozen agent command-line tools, including Claude Code, Codex, OpenCode, GitHub Copilot, and Pi, sit on the path as lazy launchers. Nothing downloads until you run one. You pick a default agent during setup, or later with `omarchy default agent` and the name of the one you want. Someone made the hundreds of decisions, and the system feels better because those decisions were made together. Omakase doesn't mean you eat everything on the plate. The first thing I changed was the terminal. Omarchy ships with foot. I swapped it for Ghostty because I prefer it, and nothing about the system argued with me. Neovim is the default editor, and it's a good one, but you can run the editor you already know. That distinction matters. A good platform should be opinionated about the common case and permissive about the uncommon one. The hard part is knowing which decisions belong in each category. ## The product is the defaults This is where the distro review turns into something I spend most of my working life on. I run platform teams, and one of the clearest lessons from that work is that a platform's defaults decide whether people adopt it. Nobody studies the architecture of the golden path before they use it. They take the path if the first 10 minutes work, and they abandon it if the first 10 minutes require a ticket. Every choice you don't have to make is a choice you can't get wrong. Every escape hatch you keep open is a reason the power users stay. Omarchy is that idea applied to an operating system. It takes Arch, which has a reputation for making you earn every working component, and puts a curated layer on top. The pieces are old. The assembly is the product. That's the same bargain the Mac offered developers years ago: good defaults, coherent behavior, and fewer decisions before you can get to work. The difference now is that the environment is designed with agents in the loop. The debugging half of that story is the part I can't judge yet. Omarchy's own homepage promises agents that debug all issues, and the design assumes you'll ask an agent before you start a web search. On my laptop, nothing broke, so I never tested that promise. A speed claim I haven't verified is a question, not a result. I'll keep it filed as a question until something on this machine fails. There's already one enterprise data point. 37signals has said it will move its ops and Ruby teams to Omarchy over the next three years. That's a stronger vote than any blog post, mine included. ## What happens when the agent belongs there So I tried the other half of the promise. The agents in Omarchy aren't only there to help fix things. They operate inside an environment whose structure is unusually legible to them, so I asked Claude Code, my default, to build something for it. The result is a bar widget that controls my [Home Assistant](https://www.home-assistant.io/) lights by room. Click the bulb in the bar and a panel drops down with a row for each room. Each row has an on/off switch and a brightness slider, plus an arrow that expands the room into its individual bulbs. Right-click the bulb and the whole house goes dark. A day later it grew scene chips and a color-temperature slider, both built the same way. It installs with one command, `omarchy plugin add`. It uses Omarchy's own panel, switch, and slider components, so it follows whatever theme you're running without styling work from me. ![The Home Assistant lights panel open below the Omarchy bar, with rooms, brightness sliders, scene chips, and a color-temperature slider](/images/blog/2026/09/omarchy-lights-panel-blog.webp) *The lights panel, drawn with Omarchy's own components so it follows the theme.* What surprised me was how little I had to explain. Omarchy 4 ships a Quickshell-based bar with a plugin system. The agent could inspect the conventions, find the right components, and build to the platform instead of inventing around it. It laid out a manifest, a bar widget in QML, a panel in QML, and a small shell script for the Home Assistant calls. It also handled the part most quick scripts get wrong. The access token lives in a file only my user can read. The script hands it to curl through a file descriptor, so it never shows up in process arguments, environment variables, or the widget's state. That's more interesting to me than the fact that Claude Code was installed. Installation is trivial. The important part is that the environment exposes enough structure for the agent to understand the platform it's modifying. The plugin model is explicit, the components are discoverable, and the conventions are consistent. The agent doesn't need a private map of the system because the system already has one. On my Mac, Claude Code is an application I installed. On Omarchy, it feels closer to a native participant in the environment. The code is at [github.com/vscarpenter/omarchy-ha-lights](https://github.com/vscarpenter/omarchy-ha-lights), MIT licensed. It has a demo mode with made-up rooms if you want to try it before handing it a token. ## What I don't know yet A few days on one laptop is a small sample, and I want to say that plainly. Arch is a rolling distribution, and rolling distributions accumulate risk over months rather than days. The snapshots should catch a lot of it. I'd like to say that again in six months. Omakase also cuts both ways. You can swap the terminal and the editor. You can't swap Hyprland without giving up much of what makes Omarchy Omarchy, and Hyprland is keyboard-first. Plenty of excellent engineers don't want to learn a new set of hands. For them, the first week may cost more than the two-minute install saved. And the corporate question is open. At a large enterprise, a developer laptop has to carry device management, endpoint security, patching, identity integration, and a compliance story. None of that ships on an ISO. I don't expect to see Omarchy on fleets of regulated laptops soon. What would change my mind is a larger company running it as a managed developer endpoint with the security and compliance controls intact. ## The alternative for people who want one macOS is entrenched as the developer machine, and I don't think that changes this year or next. Linux has been capable of being a developer desktop for years. What changed is that the cost of assembling one may finally be disappearing, and that's a platform problem more than a Linux problem. A few days on one ThinkPad can't prove that Linux has won the desktop. It does show what happens when someone treats the desktop like a platform product instead of a box of parts. The 386 took a stack of floppies. The ThinkPad took two minutes, and most of that was me looking for the Secure Boot switch. ## Related reading - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) - [The Developer Experience Ledger](https://vinny.dev/blog/2026-09-07-the-developer-experience-ledger/) - [The Best AI Developer Experience Might Be Invisible](https://vinny.dev/blog/2026-09-01-the-best-ai-developer-experience-might-be-invisible/) --- ## Bootleggers, Baptists, and the Case for Slowing Down AI - **Published:** 2026-09-14 - **Tags:** ai-strategy, engineering-leadership - **URL:** https://vinny.dev/blog/2026-09-14-bootleggers-baptists-and-the-case-for-slowing-down-ai/ Bruce Yandle's 1983 article "Bootleggers and Baptists" has been on my mind all weekend. Yandle was an economist serving as executive director of the Federal Trade Commission, and something puzzled him. A lot of regulation passes that doesn't fix the market failure it claims to fix. His answer came from Sunday closing laws. Baptists wanted the liquor stores closed on Sunday for moral reasons. Bootleggers wanted them closed because a closed store is a customer with nowhere else to go. Both groups showed up for the same law, and politicians got to look principled while doing a favor for the people with the money. The part of the theory that gets lost in retelling is that the Baptists didn't have to be insincere. Most of them meant it. Yandle's point was structural. Durable regulation tends to emerge when moral conviction and economic self-interest point in the same direction. Once they do, the sincerity of the moral side stops mattering to the outcome. The bootleggers get their moat either way. That's the lens I want to bring to what happened this weekend. ## What the industry asked for On Saturday, Dario Amodei published an essay titled "We Must Pace the Frontier." His argument is that AI capabilities have started advancing faster than the work to understand and control them, in part because models now help build the next generation of models. He wants the industry to deliberately slow the rate of capability improvement, and he lays out a three-step plan. The first step, which Anthropic is committing to on its own, is embedding independent evaluators inside the company. They get employee-level access, desks, badges, and the right to publish findings without Anthropic's editorial control. The second step is coordination among U.S. labs on safety standards and rate limits, which he notes would need a narrow antitrust waiver from the government. The third is some form of global coordination, which he admits will be much harder. Sam Altman endorsed the essay within hours and said OpenAI would match the evaluator commitment. Elon Musk and Demis Hassabis posted their support the same day. This wasn't the first move, either. In July, more than 1,300 employees of frontier AI companies signed a statement called Pacing the Frontier, asking the U.S. government to support building the technical and governance tools that could deliberately pace frontier AI development. That letter was careful. It didn't ask anyone to slow down now. It asked for the option to slow down later. I take the safety concerns seriously. The incidents Amodei cites are real, and the people signing are the people closest to the work. The essay reads like someone who has changed his mind rather than someone running a play. He even names the regulatory capture accusation himself and says he's been hearing it for years. So I'm not going to argue that the Baptists are fake. I'm going to argue that it doesn't matter. ## Who can afford the rules Ask who benefits from the rules that follow a call like this one, rather than who meant well when they made it. If frontier AI regulation ends up requiring embedded evaluator programs and large compliance organizations, the companies with the most compute and capital will be best positioned to comply. Those are also the companies asking for it. That's not a conspiracy, and it doesn't need to be one. It's what compliance costs do to a market. A fixed cost is a rounding error for a lab with a hyperscaler behind it and a wall for a startup with 40 people. I've spent most of my career in financial services and insurance. The compliance floor there is high, and the cost of clearing it is part of why the big players stay big. Amodei reaches for the same industry as precedent. He compares embedded evaluators to the supervisors that bank regulators sometimes station inside financial institutions. It's a fair comparison, and it cuts both ways. Examiners do real work, and they also raise the fixed cost of being a regulated institution, which favors the institutions that are already large. Nobody in banking set out to build a moat. The moat got built anyway. Safety regulation can become a competitive moat without anyone conspiring to make it one. That's Yandle's insight applied to 2026. The Baptists are sincere, the bootlegger benefit is structural, and in this case the Baptists and the bootleggers work in the same buildings. The antitrust waiver deserves its own paragraph. Amodei is candid that some forms of coordination among labs are legally challenging without government help, and I understand why he wants the waiver. But a government-sanctioned forum where the largest companies in an industry agree on how fast everyone is allowed to go is the kind of arrangement Yandle wrote his article about. He noted that regulators liked Sunday closing laws too, because they were easy to administer. A rate limit negotiated by the incumbents would be easy to administer as well. ## The test I'd apply I want rules that scale with demonstrated risk and that constrain incumbents at least as much as challengers. Each half of that sentence rules out something specific. Rules that scale with demonstrated risk are rules triggered by what a system can do, observed in testing, rather than by how it was built. Amodei says this is the kind of pacing he's most enthusiastic about: checkpoints where a model that can do X has to carry certifications Y and Z before it ships. That's the right instinct. It applies to whoever builds the capable model, whether they have 40 employees or 4,000, and it doesn't penalize a small lab for being small. Rules that constrain incumbents at least as much as challengers are the harder test, and it's where I'd watch closely. Embedded evaluators with real access pass it, because the labs with the most to hide have the most to lose from someone at the next desk with a badge. Licensing regimes for frontier training runs fail it, because a license is a gate the incumbents are already through. Compute thresholds fail it more quietly. They look neutral, but the people setting them already own the compute, and Amodei himself worries that limits on ingredients are easier to game than limits on behavior. Compliance structures whose primary effect is raising the cost of entry fail it by design. My rule of thumb for anyone drafting policy is that the more a proposal resembles a fixed cost, the more it favors scale. That's also when to get most skeptical about who's endorsing it. ## What would change my mind The first thing that would change my mind is rules that bind the labs proposing them harder than everyone else. Picture Anthropic and OpenAI with evaluators at the next desk publishing unflattering findings, while a small lab under the capability threshold faces nothing. In that world the moat argument is weak. Amodei has committed his own company to that, and Altman says OpenAI will follow. If the evaluators show up, keep their badges, and publish findings the companies would rather bury, I'll say so here. The second is a coordination step that produces standards a challenger can meet with a good team and a modest budget rather than a compliance department. The way to tell will be simple. Count the frontier labs founded in the two years after the rules land. If the number goes up, the Baptists won. If it goes to zero, the bootleggers did. AI safety matters, and so does competition. Serious people with real evidence are making the safety case. Almost nobody is making the competition case, which is exactly the imbalance Yandle would expect. Good policy protects the first without quietly eliminating the second, and I'd rather the people writing it read the 1983 article before they read the 2026 essay. ## Related reading - [Everyone Is Commoditizing Someone: Battle of the LLMs](https://vinny.dev/blog/2026-08-28-everyone-is-commoditizing-someone/), on where margin survives when model providers become replaceable. - Bruce Yandle, ["Bootleggers and Baptists: The Education of a Regulatory Economist,"](https://www.cato.org/sites/cato.org/files/serials/files/regulation/1983/5/v7n3-3.pdf) Regulation, May/June 1983. - Dario Amodei, ["We Must Pace the Frontier,"](https://darioamodei.com/post/we-must-pace-the-frontier) September 12, 2026. - The [Pacing the Frontier](https://www.pacingthefrontier.com/) statement, July 2026. --- ## Your Agent Workflow Needs a Release Process - **Published:** 2026-09-13 - **Tags:** agentic-sdlc, platform-engineering, engineering-leadership, spec-driven-development - **URL:** https://vinny.dev/blog/2026-09-13-your-agent-workflow-needs-a-release-process/ In August 2025, I wrote [From Vibe Mode to Spec Mode: Why I'm All In on Kiro](https://vinny.dev/blog/2025-08-10-From-Vibe-Mode-to-Spec-Mode/). What appealed to me was the structure: requirements, design, tasks, and standards instead of another conversation I hoped would produce the right software. Kiro's [frontier engineering principles](https://kiro.dev/topics/frontier-engineering/) bring me back to that argument. They emphasize clear intent, prepared codebases, useful feedback, and boundaries that hold without constant supervision, with the setup improving as teams learn. There is a lot here I agree with. There is also a practical question I would put in front of a platform team: >When a developer improves an agent workflow, how does that improvement become something the next team can safely inherit? Sharing a configuration file starts the process. It doesn't establish which tasks the workflow supports, who maintains it, what evidence justifies its permissions, or how to withdraw a change that makes it worse. My proposal is to treat a shared agent workflow as a software release: a versioned combination of instructions, context sources, tools, permissions, and verification, with an owner accountable for how it behaves. ## A working setup is not yet a supported capability Kiro is not arguing that teams should simply buy a tool and hope. Its [companion guide for teams](https://kiro.dev/topics/frontier-teams/) explicitly calls for shared context, explicit intent, testing, and organization-wide guidance. The practitioner principles also describe preparing repositories and continuously improving the setup. I want to make the maintenance obligation concrete. In [Spec, Standards, Specialists](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/), I described my own working loop: establish the behavior, supply the engineering standards, and assign focused work to agents operating inside those constraints. That is a useful unit of practice. It is not, by itself, a support model for other teams. Consider what another engineer needs to use it. They need the right instructions, but also the right commands, access, examples, checks, and expectations about when to stop. They need to know which parts are shared requirements and which are local choices. When something breaks, they need somewhere to report it other than the original author's direct messages. That is the next step after [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/). Designing a platform an agent can understand is one obligation. Maintaining the supported workflows that act through it is another. The standard I would use is straightforward: can another engineer run the supported task, understand the evidence, and handle an expected failure without the workflow's author interpreting the result? That doesn't mean eliminating help. It means making help a supported part of the product rather than a dependency on one person. ## Turn the principles into a release contract I would not turn Kiro's ten principles into ten new policies. I would use them to define what a shared workflow must make explicit. | Kiro principles, grouped | What I would require in a shared workflow | | --- | --- | | Architect rather than typist; direction before execution | A task contract defining the intended outcome, constraints, non-goals, and evidence of completion. | | Build for agents; continuously tune the setup | Versioned instructions, authoritative context sources, reproducible setup, and an owner for changes. | | Fast feedback; human standards | Checks the agent can run, protected acceptance criteria, and review proportionate to the consequences of failure. | | Maximize agent time; trust the boundaries | Explicit permissions, work limits, stop conditions, and an escalation path. | | Disposable code; agents beyond coding | Preserved behavioral contracts and distinct authorization for planning, implementation, deployment, and operational work. | This is how I would translate Kiro's guidance into a release contract a team can inspect before depending on a shared workflow. The maintenance obligation is especially important in the second row. Kiro [recommends changing instructions and tools as models improve](https://kiro.dev/topics/frontier-engineering/tune-your-setup/). Once other teams depend on that setup, I would evaluate those changes before distributing them. A new instruction might reduce unnecessary questions while also removing a useful escalation. A tool change might simplify execution while expanding what the agent can affect. I would record the workflow version, supported task types, relevant model and tool configuration, context sources, enforced permissions, required checks, and accountable owner. Where a provider does not expose or permit pinning a version, I would record that limitation rather than imply perfect reproducibility. The release unit is the whole combination. A prompt file on its own is a component. The implementation could be a repository and an existing pipeline. It doesn't require another portal. ![One versioned shared agent workflow with an accountable owner contains instructions, authoritative context sources, model and tool configuration, environment-enforced permissions, and verification through required checks and protected criteria. The prompt file is one component. The whole combination is published as one supported version.](/images/blog/2026/09/release-unit-is-the-whole-combination.png) ## Test whether it knows when to stop Imagine a shared workflow for updating a dependency in a noncritical internal service. I'm proposing this example; I haven't deployed it in my organization. The workflow may prepare a branch, apply an update within an approved range, and run the required checks. It may open a review-ready pull request only when those checks pass and the change remains in scope. It may not merge the change, deploy to production, weaken required checks, or broaden the work into an unrelated refactor. In this example, a patch-version label makes an update eligible. It doesn't make the update safe. ![Two panels for the dependency-update workflow. The left panel lists actions outside its authority: merging, deploying to production, weakening required checks, and unrelated refactoring, ending in "Stop before acting." The right panel shows the permitted sequence ending in a decision: checks pass and change in scope leads to a review-ready pull request; otherwise the workflow stops and reports the reason.](/images/blog/2026/09/test-whether-it-knows-when-to-stop.png) I would evaluate more than its ability to produce a passing pull request. I would include an update that changes behavior, a missing test environment, an unsupported package, and a tempting opportunity to make the checks pass by relaxing an assertion. In some cases, completion is the right result. In others, the right result is to stop, report what is missing or out of scope, and escalate to the accountable owner. I want the evaluation to distinguish those outcomes instead of treating every escalation as a failure of autonomy. Appropriate stopping and enforced permissions are different protections. A missing test environment should produce an escalation. Merge and production access should be denied by the execution environment regardless of how the agent responds. Kiro's [feedback-loop principle](https://kiro.dev/topics/frontier-engineering/fast-feedback-loop/) emphasizes giving agents the means to test and correct their work. Its [quality principle](https://kiro.dev/topics/frontier-engineering/human-standards/) keeps accountability with the people shipping the result. I would connect them through acceptance checks the task-performing agent cannot quietly redefine to make its own change pass. That doesn't prohibit agents from proposing tests or changes to tests. It separates proposing a new acceptance standard from authorizing that standard. Suppose a model change causes the workflow to report success when a required test environment is unavailable. The dependency update might be correct, but this workflow version has failed its acceptance criteria. I would withhold that version until it stops and reports the missing evidence. A passing evaluation supports a limited rollout within the tested scope. It doesn't establish reliability in settings the evaluation never covered. I would start with a small set of repositories, retain the previous configuration, and keep a way to revoke access. Reverting a workflow version doesn't undo actions it already took, so recovery still has to be designed for the action itself. ## Autonomy should have a scope, not a target The Kiro principle I would qualify most carefully is [maximizing agent time while minimizing human involvement](https://kiro.dev/topics/frontier-engineering/maximize-agent-time/). I agree with the objection to manually relaying errors between tools. That is work the system should often handle. I would not turn the number of running agents, or the length of an unattended session, into a measure of engineering success. A workflow should use the autonomy appropriate to its task. Finishing a bounded change without unnecessary interruptions is useful. Continuing through an ambiguous requirement because stopping would hurt an autonomy metric is not. [Two Gates and a Night Shift](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/) described the arrangement in my personal pipeline: consequential plan and release decisions remained mine, with bounded execution and maintenance between them. That's one example of explicit decision rights. The number two came from my projects, and another team's risk profile may need more gates or different ones. Kiro's [boundary principle](https://kiro.dev/topics/frontier-engineering/trust-the-boundaries/) makes the important distinction between restricting access and supervising every action. I would implement shared workflows so the execution environment enforces permissions. An agent's promise to follow its instructions doesn't count as a control. Writing a draft, changing a branch, deploying a service, and modifying production data deserve separate authorization decisions. Extending agents [beyond coding](https://kiro.dev/topics/frontier-engineering/agents-for-everything/) should not silently extend the privileges of a coding workflow. For each supported task, I want the release contract to say what can proceed, what must stop, and who decides what happens next. ## Keep the behavior when you replace the implementation Kiro's [disposable-code principle](https://kiro.dev/topics/frontier-engineering/code-is-disposable/) makes an important exception for tests at system boundaries. An implementation can change while its behavioral obligations remain. I would apply the same distinction to the agent workflow. Replace an instruction file, change a tool, or try a different model, but preserve the cases that define acceptable behavior. That includes cases where the workflow must decline to act. For the dependency example, the lasting requirements are not the exact sequence of commands an agent happened to choose. They are the authorized scope, the behavior that must remain intact, the checks that cannot be weakened, and the evidence a reviewer needs. A release process should make improvements easier without making those obligations negotiable by accident. And the evidence cannot end at a green build. [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) argued that the people responsible for a service need enough understanding to diagnose and recover it. A shared workflow should leave them usable evidence of what changed and what was verified. A transcript they have to search during an incident doesn't meet that bar. ## Prove that sharing it reduced work A supported workflow has costs: maintaining context, running evaluations, investigating failures, handling exceptions, and helping teams adopt changes. Those costs belong in the comparison. [The Developer Experience Ledger](https://vinny.dev/blog/2026-09-07-the-developer-experience-ledger/) makes the measurement obligation explicit. Follow the work to a verified outcome, separate elapsed time from human effort, and account for work transferred between people. For this workflow, I would compare similar tasks before and after adoption. I would track completion, appropriate escalation, rework, review effort, support effort, and the cost of maintaining the workflow. Failed and abandoned attempts belong in that view too. I would also ask the engineers using it whether they understand its decisions and trust its stop conditions. Fewer support requests are not an improvement when people have simply stopped reporting confusing behavior. The attraction of Kiro in my original post was that intent could become a more structured part of building software. The question now is how to make the surrounding workflow dependable for people who didn't assemble it themselves. Start with one recurring task and a team willing to evaluate it. Make its scope explicit, version the workflow, and test both completion and escalation before publishing a supported version. Roll it out to a small set of repositories, then use the results to decide whether to expand, revise, or withdraw it. The next team should inherit a supported capability. ## Related reading - [From Vibe Mode to Spec Mode: Why I'm All In on Kiro](https://vinny.dev/blog/2025-08-10-From-Vibe-Mode-to-Spec-Mode/) - [Spec, Standards, Specialists: How I Actually Build with AI](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/) - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) - [Two Gates and a Night Shift](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/) - [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) - [The Developer Experience Ledger](https://vinny.dev/blog/2026-09-07-the-developer-experience-ledger/) --- ## Worse Is Better, but Simple for Whom? - **Published:** 2026-09-09 - **Tags:** agentic-sdlc, engineering-leadership, genai - **URL:** https://vinny.dev/blog/2026-09-09-worse-is-better-but-simple-for-whom/ Richard Gabriel wrote "The Rise of Worse Is Better" to make his own side look bad. He caricatured the Unix and C school of design, called it the New Jersey approach, and admitted in the same paper that it would win. I reread it because agents have changed how much effort I spend implementing software. I wanted to know whether that changes the design choices his essay defended. If a more complete implementation is cheaper to produce, the case for accepting less should weaken. My first answer was that simplicity still wins because someone has to review the result. That was too narrow. A simple implementation can leave every caller with more to understand, test, and maintain. A more sophisticated implementation can take some of that work away. Cheaper generation makes both choices easier. An agent can write one shared capability with a dependable contract, or a separate workaround for every team that asks. How fast the code appeared won't tell us which choice helped. *Judge simplicity by the total work required to verify, use, change, and operate the system, subject to the guarantees it must provide.* Small implementations still have a place. The change is that I stop judging them in isolation. ## Same qualities, different trade-offs In [The Rise of Worse Is Better](https://www.cs.princeton.edu/courses/archive/fall13/cos518/papers/worse-is-better.pdf), Gabriel contrasts two approaches that both value simplicity, correctness, consistency, and completeness. They disagree about what to sacrifice. His MIT approach puts interface simplicity first and permits implementation complexity to protect it. His New Jersey approach puts implementation simplicity ahead of every other quality and will trade completeness for any of them. Gabriel caricatures New Jersey on purpose, then argues that it has better prospects for adoption. His syscall story makes the distinction concrete. After an interruption, the MIT solution would restart the system call without additional caller logic. The Unix solution in the essay returns an error when the operation cannot complete and leaves the caller to decide whether to retry. The implementation avoids work that every caller must then handle. Gabriel's economics include implementation time, portability, modest hardware requirements, and adoption that attracts further improvement. Implementation cost was explicit in his argument, and so was the guardrail: a limited initial solution must be fundamentally sound. My question is narrower than whether his whole historical argument survives. When implementation gets cheaper, which of those trade-offs should we reconsider? ## Cheaper implementation does not settle the design In [Everyone Knows You Never Rewrite](https://vinny.dev/blog/2026-07-17-everyone-knows-you-never-rewrite/), I argued that lower implementation costs can make previously uneconomic work worth considering. The condition was a trustworthy behavioral reference, something more substantial than the agent's confidence that its new version works. That condition holds here too. Code that attempts to handle an edge case still has to be shown to handle it correctly. Cheaper generation doesn't prove that the difficult final work has disappeared. Verification costs move too, since agents can help produce tests and investigate failures. But a saving in implementation effort tells us nothing about how much verification work remains. Consider an agent offering to support another configuration mode. The implementation might take minutes to generate. Before accepting it, I still ask which combinations need testing, what compatibility we're promising, and who will diagnose failures. The feature costs what it costs to test and support, however fast it arrived. Completeness is now a decision someone has to make on purpose. Features that once required an explicit investment arrive as small additions to an agent session. I don't want the convenience of generating them to substitute for deciding whether they belong in the product. The counterargument is that sometimes the additional behavior eliminates work elsewhere, which is my strongest reason to stop equating simplicity with a smaller implementation. ## Simple for the component, expensive for its callers AWS gives a useful example in [Making retries safe with idempotent APIs](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/). A client asks a service to create a resource and receives no response. The resource might exist, or the request might never have completed. Retrying without the right contract could create a duplicate. An idempotent API lets the caller repeat the same request without additional side effects, within the contract's defined conditions. AWS describes a caller-provided request identifier that the service uses to recognize repeated requests. That simplifies client behavior and adds work to the service. ![Two designs for the same retry problem. On the left, every caller guesses whether to retry and carries the duplicate risk. On the right, the caller sends a ClientToken and the service recognizes repeats, preserves state, and defines how it handles late requests and reused tokens, so the retry is safe for every caller.](/images/blog/2026/09/where-the-retry-logic-lives.png) The service must distinguish a retry from a new request and preserve the relevant state. The contract must define how it handles delayed requests and reused identifiers. The complexity moved behind the interface; it did not disappear. Absorbing this work into a shared capability reduces the total burden on its consumers. Each caller still has obligations, but none of them has to reconstruct the service's handling of duplicate requests on its own. That complicates an implementation-first reading of Gabriel. Cheaper implementation strengthens the case for a better interface at least as much as it makes a limited implementation easier to ship. It also fits the platform direction I described in [The Golden Path Needs an Intent Interface](https://vinny.dev/blog/2026-08-20-the-golden-path-needs-an-intent-interface/). Developers should understand their workload's requirements and consequences. They shouldn't need to memorize every internal module, naming convention, and policy translation to use the platform correctly. A platform can take responsibility for those details, but only cheaply when its contracts, tests, documentation, and operating model are dependable. For a proposed shared capability, I count the work this way: | Whose work? | What the comparison must include | | --- | --- | | Component owners | Implementation, verification, maintenance, compatibility, and the evidence supporting the contract. | | Callers and their reviewers | Integration, configuration, caller-side failure handling, and tests of their own use of the capability. | | Operators | Diagnosis, recovery, upgrades, runtime resources, and the consequences of a shared failure. | | Users | Decisions, workarounds, and recovery steps the interface still requires of them. | A shared component can also become a dependency that delays changes or spreads one defect across many teams. Callers still need evidence that their integration works, even when the component has strong tests. The comparison has to include those costs. Otherwise "the platform handles it" is as incomplete as "the caller can just retry." ## A small app makes the same trade-off I can see both choices in [System Headroom](https://vinny.dev/blog/2026-08-23-my-mac-ran-out-of-headroom/), the menu bar app I built to understand what was consuming my Mac's resources. The App Store edition monitors processes and does not terminate them. My sandbox experiments ruled out the termination approaches I tested, so the quit controls live in the separate Direct edition. That is an explicit capability boundary rather than a control that appears to work until the platform refuses it. Elsewhere, I added implementation complexity to make the app easier to use. A raw process list would have left users to work out which helpers belonged to which application, so the app groups related processes. The grouping logic follows process ancestry, handles helper-name conventions, and keeps a standalone fallback. It runs as pure Swift against test fixtures, separate from the system calls that collect the data. The design matters more than the amount of code. I accepted additional logic to reduce the user's interpretation work, and I separated that logic so I could test it directly. Returning the raw process list would have simplified my implementation without solving the problem I built the app to solve. The sandbox decision reduces capability. The grouping decision adds behavior behind a simpler interface. Both make sense once I consider the product and its responsibilities. A one-person app does not establish enterprise cost savings. Still, it gives me a concrete reason to be skeptical when "keep the implementation simple" is offered as a complete design argument. ## Verification is more than reading the code The reviewer still matters. Requiring a person to read every generated line, though, would contradict where my own practice has gone. In [From Faster Code to Better Engineering](https://vinny.dev/blog/2026-09-05-from-faster-code-to-better-engineering/), I described moving from reading every line toward reviewing consequential plans, testing running previews, and auditing samples. The scope of delegation grew as the evidence improved. By verification I mean executable checks, independent review, operational testing, and accountable human judgment: evidence appropriate to the change and the consequences of getting it wrong. The goal is to make the relevant behavior understandable and the evidence sufficient to support a decision. Fitting every implementation into one person's memory is a goal I gave up on. A repetitive change across many files can be easier to assess than a small change to a shared authorization rule. Diff size won't tell me which review needs more attention. I want to know what behavior changes, who depends on it, and which checks establish that the required protections remain intact. That's the operating principle behind [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/): make repeated judgments explicit and executable rather than depending on concentration alone. The checks themselves still need scrutiny. Tests generated from the same mistaken understanding as the implementation will confirm the mistake, and a second agent's approval doesn't resolve that. Expected behavior needs a defensible source: a reviewed requirement, a reliable existing implementation, or a known failure case. I trust a longer implementation with evidence behind it more than a short one without. ## Reduce scope, not required guarantees The phrase "drop the rare cases" makes me uncomfortable, because rarity doesn't tell us whether a behavior is optional. Choosing not to support another import format can be a legitimate scope decision. Losing saved work when an operation fails is a defect. Both involve unusual conditions, and only one is an optional capability. I have a concrete reason to make that distinction. In the engineering retrospective, I [described a database migration whose mocked tests passed while production behavior failed](https://vinny.dev/blog/2026-09-05-from-faster-code-to-better-engineering/). A user lost local task data. I changed the tests to exercise an in-memory IndexedDB implementation rather than mocking away the behavior that mattered. The missing work was evidence for an obligation the product already had, and no amount of added product completeness would have substituted for it. I apply Gabriel's four qualities this way today. This is my adaptation, not a ranking I attribute to his essay. 1. Simplicity. Count the work across the component's owners, its callers and their reviewers, its operators, and its users. Prefer explicit contracts and designs whose important behavior can be checked without reconstructing the whole system. 2. Correctness. Treat required behavior and protections as acceptance conditions within the supported scope. Narrow the scope when necessary, but never quietly weaken those conditions to make a change easier to approve. 3. Consistency. Use predictable behavior to reduce what callers and reviewers must remember. Document necessary exceptions and test them. Removing a rare but required case only moves the surprise to the caller. 4. Completeness. Add capability when its value justifies its verification, maintenance, and support obligations. Make unsupported behavior explicit. An agent's ability to generate another option isn't a product requirement. This still leaves room for small, useful releases and improvement through real use. On one of my projects the installed base is me, which makes prioritization meetings easy. It doesn't remove the work of supporting what I add. ## How I ask for the comparison For a consequential design choice, I ask for more than "the simplest implementation that satisfies the spec." I ask the agent to compare where the work goes. ![A proposed shared capability with the work it creates split across four owners: component owners, callers and their reviewers, operators, and users. A banner reads that "the platform handles it" is as incomplete as "the caller can just retry."](/images/blog/2026/09/count-the-work-for-everyone.png) The specification states supported behavior, constraints, non-goals, and acceptance evidence. It is its own artifact, separate from the API and from the prompt used to draft it. Agents can help write the specification and the implementation; humans remain accountable for the requirements they approve. A design request looks like this: > Compare designs against the same acceptance criteria. Include one that minimizes implementation complexity and one that reduces the work required of callers. Consider an existing supported component before proposing a new one. For each option, identify implementation effort, caller responsibilities, verification evidence, compatibility obligations, and recovery requirements. Recommend a design, state the assumptions behind the recommendation, and identify what we would need to measure to check it. I don't turn every small change into an architecture exercise. The comparison earns its cost when a decision establishes a shared contract, adds a dependency, or commits us to ongoing behavior. When it does, the change has to show its behavioral consequences and supporting evidence alongside its diff. When that evidence is insufficient, we split the scope or improve the checks. Do not lower the acceptance criteria because generation has outpaced review. For leaders, this is a funding decision. Shared contract tests, maintained components, and recovery exercises need owners and capacity. Their value includes the work they remove from consuming teams, and that responsibility continues after deployment. In [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/), I argued that verification must include operation and recovery. "Simple to operate" is a judgment the operators make, long after the deployment succeeded. I would rather fund that capability than make every reviewer compensate for its absence. ## What would change my mind The obvious objection is that this is familiar architecture advice. Count the whole system, make trade-offs explicit, and avoid unnecessary capability. None of it began with coding agents. I agree. What agents change is the effort required to produce another implementation or another feature. That makes it easier to accumulate obligations without a deliberate decision about them, and it makes alternatives cheaper to investigate. We should use that to compare designs instead of assuming whichever one appeared first is good enough. My working position is that additional implementation complexity is worthwhile when it removes repeated work and supports a dependable contract. I would reject that choice if consumers still needed extensive workarounds, maintenance costs exceeded the avoided effort, or shared failures became harder to recover from. For comparable changes, I track verification effort, integration rework, ongoing maintenance, and recovery performance. Lower review time is an improvement only when the extra risk it accepts is on the record. The examples here do not establish enterprise-wide savings, and better automated verification could change which design is least expensive to support. The decision should follow the evidence rather than a permanent preference for either school. I still prefer the smallest system that meets its obligations, once I count those obligations across everyone the design touches. Sometimes that favors a narrower product; sometimes it justifies more complexity behind a dependable interface. Cheaper code changes the cost of those choices. It does not make the choices for us. ## Related reading - [Richard P. Gabriel, "The Rise of Worse Is Better," section 2.1 of *Lisp: Good News, Bad News, How to Win Big*](https://www.cs.princeton.edu/courses/archive/fall13/cos518/papers/worse-is-better.pdf) - [Making retries safe with idempotent APIs](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/) - [Everyone Knows You Never Rewrite](https://vinny.dev/blog/2026-07-17-everyone-knows-you-never-rewrite/) - [The Golden Path Needs an Intent Interface](https://vinny.dev/blog/2026-08-20-the-golden-path-needs-an-intent-interface/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) --- ## The Developer Experience Ledger - **Published:** 2026-09-07 - **Tags:** platform-engineering, ai-economics, engineering-leadership - **URL:** https://vinny.dev/blog/2026-09-07-the-developer-experience-ledger/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* Consider a developer using an agent to create a service on your platform. The configuration appears in minutes. Then the pipeline rejects it, the error points to a policy the developer has never seen, and a platform engineer gets pulled into a conversation about which deployment pattern is supported. By the time the service finally ships, the agent's dashboard records a completed task. The platform records another service provisioned. The developer remembers a morning spent figuring out what the two systems meant by done. All three accounts can be accurate. They end in different places. In [The Best AI Developer Experience Might Be Invisible](https://vinny.dev/blog/2026-09-01-the-best-ai-developer-experience-might-be-invisible/), I argued that a platform should repair the failures it owns and meet developers where the work gets stuck. That creates a measurement obligation. We need to know whether the developer's day got easier, and what the platform took on to make that happen. An adoption dashboard cannot answer that question. A ledger that follows the work can. ## Follow the work past the tool Licenses activated and weekly usage tell us whether a tool reached people and whether they use it. Those are useful questions. They're different from whether the work became easier, safer, or more valuable. When I wrote [The AI Operating Ledger](https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/), the discipline was to account for the whole path to a verified outcome: context, generation, review, rework, and the consequences of what shipped. The developer experience ledger applies that discipline to the platform's part of the journey. Start with something a developer came to do, such as creating a service, deploying a change, or recovering a failed build. Give that journey a completion boundary the developer and platform team both recognize. For a new service, that might be a verified deployment with the required ownership, access controls, and observability in place. The agent finishing is an intermediate event. ![Five steps from the agent preparing configuration through pipeline rejection, developer investigation, and platform engineer help, to a verified deployment. The agent's dashboard records a completed task after the first step; the ledger follows the whole journey.](/images/blog/2026/09/devex-ledger-follow-the-work-past-the-tool.png) A platform earns its investment when the useful journey gets easier without weakening the outcome or quietly handing the work to someone else. That's a higher bar than a successful tool rollout, and it also tells the platform team where to work next. ## Where the saved hour went Put numbers on the opening example. These are illustrative figures, not measurements from my team. Assume the same service request and the same acceptance criteria before and after adding the agent. Both journeys reach a verified deployment. | Active human effort per completed journey | Before | With the agent | | --- | ---: | ---: | | Developer prepares configuration | 70 min | 10 min | | Developer reviews and verifies the result | 20 min | 20 min | | Developer investigates platform problems | 10 min | 50 min | | Platform engineer helps resolve the problem | 0 min | 15 min | | **Total human effort** | **100 min** | **95 min** | The agent saves 60 minutes of configuration work. In this scenario it also picks up a retired deployment example, and the developer spends 40 additional minutes untangling the resulting failures. The developer's net saving is 20 minutes. Fifteen minutes of new platform support leaves five minutes saved across the two people. Counting only the first row turns a five-minute improvement into a 60-minute success story. [Where the Saved Hour Goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) made the case for deciding how to spend the dividend. First we have to establish how much of it survived the journey. ![Illustrative calculation for the same verified deployment: 60 minutes saved preparing configuration, minus 40 minutes of added developer investigation, minus 15 minutes of added platform support, leaves five minutes of net human effort saved, with the 60 minutes drawn to scale.](/images/blog/2026/09/devex-ledger-where-the-saved-hour-went.png) This is a labor comparison rather than an ROI calculation. Model spend, the cost of building the integration, and its ongoing maintenance still belong in the investment decision. The table also doesn't tell us how long the service took to reach production. People and machines can work in parallel; minutes of human effort are not minutes on a clock. What the example does provide is a place to intervene. The retired example needs to be demoted, the supported path needs to be authoritative, and the rejection needs to explain the correction. Buying more generation capacity would leave that failure intact. Fixing the platform would make the existing agent more useful and help the next human who finds the same old example. The ledger has done its job when it changes that investment decision. ## Attention is the resource, not the unit I want to resist the temptation to collapse this into one score. The [SPACE research](https://www.microsoft.com/en-us/research/publication/the-space-of-developer-productivity-theres-more-to-it-than-you-think/) makes the broader point: developer productivity cannot be understood through a single metric or dimension. A platform ledger needs several views for the same reason. Elapsed time tells us how long the journey takes, while active human effort estimates how much work it consumes. Completion and rescue rates help describe where it breaks, and developer feedback tells us about confidence, frustration, and the effort the systems didn't record. They have different units because they answer different questions. A 20-minute build that runs while an engineer does useful work differs from a 20-minute build that needs attention every two minutes. The duration is identical and the interruption is not. Even active minutes are an incomplete measure of attention: recovering the thread of a difficult problem does not always leave a timestamp. So keep asking developers what the journey feels like. The survey is evidence, and so is the trace. If the instrument says the platform improved and its users disagree, the next step is to understand the disagreement. They may be noticing a cost you forgot to count. ## Agents leave a different kind of evidence Developers can hide friction remarkably well. They copy an old repository, ask the person who knows, or abandon self-service and solve the problem themselves. A platform can look quiet because its users have become skilled at working around it. Instrumented agent runs give us another way to see those obstacles. A run can record the source it retrieved, the capability it called, the error it received, the retries it attempted, and the point where a person took over. That turns part of the journey into something we can inspect and, when the relevant state is retained, replay. In [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/), I proposed asking whether an agent could discover and complete the approved path without relying on tribal knowledge. Run evidence can help make that test repeatable. It still needs interpretation. An agent choosing the wrong argument is different from an API rejecting a valid request. A required approval is different from a platform engineer rescuing a broken workflow. Record those separately. A control that stops an unsafe action has done its job, even when the run ends without a deployment. There is a quieter trap in the completion rate. It can rise because the system got better, or because this week's tasks were easier. Keep the journey type, relevant platform version, and agent configuration with the result. Look at the number of attempts and what was attempted before celebrating a percentage. A model update can change the rate without a single platform improvement. The trace gives us a place to investigate, but it doesn't assign the blame for us. ## The ledger belongs to the people doing the work A request for fewer tickets can produce fewer tickets. It can also produce a developer who decides asking for help will hurt the team's numbers. The same problem appears if every human intervention becomes a failure. People will delay escalation, and the dashboard may improve just as the work becomes less safe. Some attention is an investment: reviewing a consequential change, learning why a control exists, or exercising judgment on a legitimate exception. The purpose of this ledger is to find avoidable effort and make its owner accountable. It should help us improve a shared journey, not rank individual developers by how little assistance they need. That distinction has to show up in the practice. Sample journeys with the developers who use them and review the findings together. Retain the evidence needed to diagnose the obstacle, with access appropriate to the code and data involved. Do not turn a request to understand friction into a requirement to record everyone's working day. The ledger will be least useful in an organization where people are afraid to tell it the truth. ## Start with one journey and one decision Pick a frequent journey whose friction your users can already describe. Agree on what completion means and which controls must hold. Follow a small sample through it, including unsuccessful attempts, and compare like work with like work. Keep five things visible: elapsed time, active human effort by role, verified completion, unplanned rescue, and the developer's account of the experience. Use the system's timestamps where they are useful and brief estimates where they are not. Mark estimates as estimates. A useful baseline doesn't need to pretend it's a stopwatch study. Then classify the obstacle before funding the remedy. Repeated confusion may call for a better error or a canonical example, and a routine request may deserve self-service. A necessary approval may need a clearer decision and a shorter wait, while a rare exception may be cheaper and better handled by a person. The ledger should allow each answer. ![Four obstacles mapped to remedies: repeated confusion to a better error or canonical example, routine request to self-service, necessary approval to a clearer decision and a shorter wait, rare exception to a person. Then choose one improvement, name its owner, and repeat the comparison.](/images/blog/2026/09/devex-ledger-classify-the-obstacle.png) Choose one improvement, name its owner, and repeat the comparison. Check that the gain survives the verification and rework window appropriate to that journey. If later defects or support work consume the apparent saving, keep them in the account. Count the cost of maintaining the fix too. The platform owner should convene this review, with product teams and the AI program contributing their parts of the evidence. No team should get to end the account at the boundary where its own numbers look best. There is a leadership decision at the end of that review. If the platform returns time, decide with the team what it's for: deeper engineering work, learning, reducing operational debt, or finishing the day with fewer interruptions. If every saved minute immediately becomes another assignment, we may increase output while leaving the developer experience unchanged. Make that tradeoff explicit. I'd rather take one well-understood journey into the next engineering review than another slide of licenses, prompts, and generated lines. Show where the work went, what changed, and whose day improved. Adoption tells us the tools arrived. I want to know whether the attention came back. ## Related reading - [The Best AI Developer Experience Might Be Invisible](https://vinny.dev/blog/2026-09-01-the-best-ai-developer-experience-might-be-invisible/) - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) - [The AI Operating Ledger](https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/) - [Where the Saved Hour Goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) - [The Instrument and the Ledger](https://vinny.dev/blog/2026-07-04-the-instrument-and-the-ledger/) --- ## From Faster Code to Better Engineering - **Published:** 2026-09-05 - **Tags:** engineering-leadership, agentic-sdlc, platform-engineering, ai-strategy - **URL:** https://vinny.dev/blog/2026-09-05-from-faster-code-to-better-engineering/ When I [returned to blogging in May 2025](https://vinny.dev/blog/2025-05-17-back-to-blogging/), I was making room for thoughts I'd mostly kept to myself for 20 years. The early posts were experiments and observations: side projects, new tools, the pleasure of learning something unfamiliar. Over the following 16 months, a different question gradually took over the archive. What happens to engineering when producing the code stops consuming so much of the work? At first, the answer looked like speed. An application came together over a weekend, and a feature stopped costing several evenings at the keyboard. More ideas survived the distance between thinking about them and trying them. Then the questions got harder. What if the specification was wrong, or the tests approved a behavior nobody wanted? What if the agent finished its task while the developer inherited an afternoon of platform problems? And who understood the system after it shipped? *AI is moving the constraint in software engineering. As implementation gets cheaper, the quality of our intent, our platforms, and our judgment determines how much of that speed becomes useful progress.* I first concentrated on making intent explicit and enforcing it through the delivery system. Experience widened the question. A precise specification and passing checks could still leave me with the wrong software, and my argument still needed to account for the people who would operate what shipped. That's the journey I can trace through this work. It draws on two connected settings: years leading cloud and platform teams, and personal projects where I can put new methods under pressure myself. The lessons travel between them, but a weekend result stays a weekend result, and an enterprise result needs enterprise evidence. ![Six-stage timeline: before AI, cloud coordination; August to December 2025, intent and standards; January to April 2026, repeatable delivery; April to July 2026, framing and verification; August to September 2026, context and operability; next horizon, judgment and learning. Earlier constraints remain as the emphasis widens.](/images/blog/2026/09/engineering-journey-moving-bottleneck.png) *How the emphasis in my writing evolved. The overlapping periods reflect a learning process; each stage adds obligations that the next one still has to carry.* ## We already had a delivery problem *Before AI · Day zero* The story starts before the agents. Across two cloud builds in financial services over 15 years, I'd already watched the same pattern repeat. Infrastructure became easier to acquire, and creating another environment came down to an API call. Delivering software responsibly remained a negotiation among identity, security, networking, deployment, cost, and the people who knew how each piece worked. Shared understanding still came from those people, and it took the time it took. In [Building Cloud From Zero](https://vinny.dev/blog/2026-05-08-building-cloud-from-zero/), I looked back at the bets that helped. Centralized landing zones put identity, logging, network controls, and tagging underneath the first workloads. A common infrastructure workflow reduced the number of systems engineers had to learn. Golden paths gave ordinary services a supported route to production, with escape hatches for work that needed something different. Those choices were contested. Application teams wanted to get moving. Leaders wanted to know whether the platform team was creating the bottleneck it claimed to remove. Building the foundation before the first workload imposed a visible delay in exchange for benefits that would take years to become obvious. Some decisions also aged badly. We let too many teams choose their own delivery tools, then paid for that variability whenever a control changed. We carried multi-cloud aspirations longer than their practical value justified. We treated cost optimization as a later phase, which meant spending engineering time recovering money we could have avoided spending. The most recent FinOps push I described reached a 46% effective optimization rate across our cloud estate. That was a result worth being proud of, alongside a lesson about putting cost discipline into the foundation. It was a cloud operating result; I have no basis for presenting it as an AI savings figure. That's the technical debt underneath this story: accumulated exceptions, repeated low-value decisions, and knowledge that only worked when the right person was available. It lived in the organization as well as in the code. By the time AI arrived in the development workflow, we had a useful precedent. A powerful capability becomes broadly useful when people can inherit the conditions for using it well. Cloud access had needed a platform. AI access would need one too. ## Writing the problem down was the beginning of trust *August-December 2025* My early AI writing carried real enthusiasm. I was building things I might otherwise have left in a notebook. I was also acquiring enough subscriptions to make curiosity look like a billing problem. By August, [From Vibe Mode to Spec Mode](https://vinny.dev/blog/2025-08-10-From-Vibe-Mode-to-Spec-Mode/) was already pointing toward structure. Requirements, design, and an implementation plan gave the model something better to work from than an enthusiastic request. September's craftsmanship essay brought familiar engineering expectations into that interaction: small changes, clear responsibilities, tests, and maintainable code. There was a tradeoff. Writing down the problem consumed some of the time the tool appeared to save. For an experiment, that could feel excessive. For software someone would depend on, it was the beginning of being able to trust the result. The experiments were beginning to act on the world, too. In September, a [small agent watching my personal AWS spending](https://vinny.dev/blog/2025-09-14-From-AI-to-AI-Agents/) emailed me when I crossed a budget threshold. It was a modest result, but it made the shift tangible: the system could watch for something I cared about and bring it to my attention without waiting for a question. The skepticism deserved a hearing too. In [September's adoption essay](https://vinny.dev/blog/2025-09-30-genai-adoption-in-development/), I acknowledged the distance between my own enthusiasm and what other developers experienced. Change fatigue, unfamiliar workflows, and uncertainty about output quality were real constraints. A leader's successful side project didn't settle the adoption question for a team maintaining a large existing system. My productivity app offered a smaller corrective. The original appeal was simplicity and local control. User requests pushed it toward optional encrypted sync and an interface agents could use. The technology made new options cheap. The people using the app decided which ones mattered, and they were better at that than I was. By [November](https://vinny.dev/blog/2025-11-15-journey-with-trusting-genai-and-coding-workflow/), my confidence rested more explicitly on acceptance criteria, review, and testing. Delegating implementation didn't make the result someone else's responsibility. That was the first foundation: make intent explicit, give it standards, and keep learning from what happens. The same leadership instincts appearing in my posts about teams and continuous improvement belonged here. Listen to skepticism, make disagreement useful, and fix the conditions around the work instead of treating every difficulty as a person's failure to adapt. ## Corrections started compounding *January-April 2026* Early 2026 supplied concrete reasons to keep going. In February, I [built the TravelTimes notification system in a day](https://vinny.dev/blog/2026-02-06-building-notification-system-with-claude/). In March, I [reported an Android version built in about eight hours over a weekend](https://vinny.dev/blog/2026-03-10-from-ios-to-android-app-in-a-weekend/), using the existing iOS application, screenshots, and coding standards as the reference. At the time of that post, the Android app was awaiting store review. Those were meaningful outcomes in my own work. They were also bounded ones. I brought years of engineering experience, a working product, and a clear idea of its behavior. Eight hours was the reported effort for that port, not a controlled comparison establishing how much faster every engineer could become. In my own repositories I held the whole mental model: the intent, the edge cases, and the deployment target. Every prompt carried that context without my noticing. In an enterprise system that context is spread across years of commits, tickets, and the memory of whoever built the service. What worked on a weekend project couldn't be repeated across an enterprise codebase without infrastructure to supply what my own head had been providing. What mattered architecturally was the reference. The agent had an answer to what the application should do. I could spend more of my attention on behavior, edge cases, and whether the implementation belonged on the target platform. By March and April, I was trying to make those conditions repeatable. Coding standards moved from text I pasted into conversations into reusable instructions, and frequent checks became automated feedback. Focused agents took on bounded review tasks, and lessons from mistakes went into files the next session could read. The same instinct appeared in [Pipeline-First](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/) and [The Agentic SDLC](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/). A collection of capable tools still leaves someone carrying intent, decisions, and evidence between them. The Context Spine was my name for the continuity the workflow needed: enough durable state that each stage could understand what had been decided and what remained to be proved. By the end of April, I could describe my working method in three words: [spec, standards, specialists](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/). Define the behavior. Establish the engineering bar. Assign focused work inside those boundaries. This was the inflection point. A correction could improve the next run, because it became part of the system rather than another conversation I had to remember to repeat. The compounding mechanism was better defaults and reusable knowledge. In March, [I reported fewer review cycles, easier onboarding, and growing reviewer trust](https://vinny.dev/blog/2026-03-28-coding-standards-skill/) across projects and teams. Those were qualitative observations, but they pointed toward something more durable than a fast first draft. That also clarified the platform opportunity. Asking every engineer to assemble a personal collection of instructions, hooks, permissions, and integrations would reproduce the fragmentation we'd already paid for in cloud. Shared workflows needed owners, maintenance, and a supported path for exceptions. The platform had another product to build. ## The system started arguing back *April-July 2026* The encouraging results were real, and so were the failures. In April, I [documented an audit hook that had been broken for nine days before I noticed](https://vinny.dev/blog/2026-04-25-claude-code-build-system/). The automation I relied on to make activity visible had quietly stopped doing its job. The more consequential failure was a database migration whose mocked tests passed while the real behavior failed in production. A user lost local task data. The mocks conformed to my code rather than to the database, so the tests confirmed my assumptions instead of the system's behavior. The tests had declared success, and someone who trusted the software had lost part of their work. That consequence was still mine to own. I changed the testing approach to exercise an in-memory IndexedDB implementation rather than mocking away the boundary that mattered. There was a less dramatic lesson in the feedback loop itself. Running the full test suite after every agent response added roughly 30 seconds each time. I replaced that with a fast type check of about three seconds and kept the full suite before pushing. A safeguard that made every interaction expensive was becoming an incentive to disable the safeguard. Then, in May, [I rejected a refactor with a clean diff and passing tests](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/). It solved the problem I had written down. It did not solve the problem we actually had. That failure sharpened the specification argument. A detailed spec can still encode the wrong understanding. Good framing requires knowledge of the situation: the constraint that cannot move, the dependency that matters, the behavior customers rely on even though nobody documented it. Tests can check a mistaken requirement with perfect consistency. My language about automation needed the same scrutiny. The dark-factory metaphor helped me describe repeatable delivery. My actual practice remained more conditional. While rebuilding TravelTimes in April, I still described reading every generated line. By July, my personal pipeline had shifted toward reviewing meaningful plans, testing running previews, and auditing samples of merged work. The scope of delegation changed as the surrounding evidence improved. In [Two Gates and a Night Shift](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/), that became a concrete arrangement: human approval of consequential plans, then release approval after testing the preview. Agents built, reviewed, and handled bounded maintenance between those decisions. Low-risk work had a lighter path. The builder could not approve its own release, and the maintenance routine escalated questions of intent. Even that arrangement had a known weakness: agents from the same model family could share blind spots. I described spot-checking roughly one in 10 merged pull requests and withdrawing autonomy if the checks stopped supporting it. The telemetry was newly added; the post explicitly deferred outcome numbers until there was enough evidence to report them. That's a more useful account of trust than confidence in a particular model, because delegation has a scope, evidence, and a way to be reduced. ## The platform became part of the AI experience *August-September 2026* By August, the argument had moved beyond the individual coding session. The modernization essays asked what becomes possible when translation and implementation cost less. They also identified the limit: before replacing an old system, we need evidence of what it does. Characterization tests, representative workloads, and comparisons between old and new behavior preserve knowledge that a fluent rewrite can otherwise erase. Cheaper generation raises the value of a trustworthy answer key. Agents were exposing another kind of missing knowledge inside [the developer platform](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/). A developer can work around incomplete documentation by asking a colleague. An agent encounters the same gaps differently: a retired example, an ambiguous capability, an approval boundary that exists only in someone's memory. That makes agent readiness a useful test of developer experience. When the supported path can't be discovered without tribal knowledge, the platform has work to do. Asking every developer to reassemble that knowledge for every session made less sense as adoption grew. [Trusted context belonged in the platform](https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/): authoritative standards, service ownership, supported patterns, and access rules. Each answer needed an owner and a version; obsolete answers needed to be retired. More retrieval wouldn't settle which conflicting source the organization stood behind. With that foundation, [the interface could move up](https://vinny.dev/blog/2026-08-20-the-golden-path-needs-an-intent-interface/). I proposed letting developers express the workload they need, its data sensitivity, availability requirements, and ownership. The platform would turn that into structured, reviewable intent, and an agent would map it to approved capabilities. The golden path remains underneath. The engineer still has to understand the consequences of the availability target and the data classification. Remembering an internal module name is a different kind of knowledge, and the platform should carry more of that burden. There was a hole in the argument, though, and in [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) I named it. Too much of my writing ended at deployment. A passing gate didn't establish that someone could diagnose the running service, restore its data, or execute its rollback. Operability had to travel with the specification: ownership, service objectives, failure modes, recovery paths, and evidence from exercising them. A generated runbook still needed to be tried. The midnight incident in that essay was hypothetical. The obligation to prepare for it applies to every service we ship. ![A proposed workflow proceeds from structured intent through authoritative context, approved capabilities, and build verification to deployment, observation, and recovery. Humans approve consequential intent and releases when required. Platform access controls, policy checks, and traceable actions span the journey; runtime evidence feeds back into context.](/images/blog/2026/09/engineering-journey-request-to-running-service.png) *A proposed platform-supported journey. Human decisions depend on risk and evidence, and operating lessons return to the context that guides the next change.* By [September 1](https://vinny.dev/blog/2026-09-01-the-best-ai-developer-experience-might-be-invisible/), I could describe a practical direction and an honest current boundary. For most failure categories, help was explaining the problem where it occurred. For a narrow set, the platform was handling the failure itself. The August essays set out an agenda for broader intent interfaces and systematic operability checks; they did not report a completed rollout. The ownership rule made the direction concrete. Repair what belongs to the platform. Propose changes to a developer's code and leave the decision with its owner. A successful retry needs a diagnosis, and repeated repairs need to stay visible to the platform team so that temporary recovery doesn't become permanent hidden work. The measurable gains in this account remain specific: the day spent building notifications, the roughly eight-hour port, the shorter local feedback loop. I do not yet have a published before-and-after series showing enterprise deployment frequency, recovery time, or net developer effort attributable to this AI work. That missing evidence determines what I should measure next. The cultural direction is clearer. In my own workflow, corrections increasingly become changes to standards, and autonomy has to keep earning its scope. For teams, the leadership obligation is to make it safe to challenge output, report friction, and ask for help. A dashboard that improves because engineers become reluctant to escalate would be measuring a retreat from trust. ## Give the time back, and prove it came back *Next horizon* The next phase begins with a more demanding unit of progress: a completed, verified journey. Take a developer trying to create and deploy a service. Follow the work through configuration, policy checks, review, platform support, and a deployment that meets its operating requirements. The agent finishing is one event inside that journey, and any saving has to survive what happens afterward. This is where [The AI Operating Ledger](https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/) and [Where the Saved Hour Goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) lead me. Measure elapsed time separately from active human effort. Include verification, rework, coordination, support, model usage, and the cost of maintaining the automation. Compare similar work and keep failed attempts in view. Ask developers whether the experience improved, because interruptions and uncertainty don't always leave useful timestamps. ![A conceptual ledger subtracts additional review, rework, coordination, support, and automation maintenance from avoided implementation effort. Net human capacity may be zero or negative. If capacity is recovered, teams can choose reliability, learning, new work, or fewer interruptions.](/images/blog/2026/09/engineering-journey-where-saved-time-goes.png) *Count changes across all roles, including reductions outside implementation. The added effort is relative to comparable work before the change. A positive remainder creates a choice about how to use it; elapsed time and financial cost need their own measures.* I'd start with one frequent journey and one accountable platform owner. Establish the baseline with the teams using it, fix the most expensive recurring obstacle, and repeat the comparison. Sometimes the remedy will involve an agent. Sometimes it will be a canonical example, a better error, or a clearer decision about ownership. The architectural agenda follows from that discipline. Trusted context needs freshness checks and access controls. Agent capabilities run on bounded permissions and traceable actions, and every model change gets evaluated against real tasks. Legacy modernization waits for behavioral evidence before large-scale replacement, and autonomous delivery moves at whatever pace the service and its operators can sustain. There is an organizational agenda too, and it may be harder. My writing on [apprenticeship](https://vinny.dev/blog/2026-08-03-dont-automate-the-apprenticeship/) identifies a tension we can't solve with better prompts. We want experienced engineers exercising judgment over automated work. Much of that judgment was learned by implementing, debugging, reviewing, and living with consequences. Removing those experiences without replacing their learning value consumes the capability the new system depends on. If an organization delegates all its mundane implementation to models, it risks a seniority cliff. Plenty of senior engineers would be directing agents, with no pipeline producing the ones who spot a generated architecture that is quietly flawed. So give engineers supported opportunities to predict a failure, explain a generated change, inspect a production trace, and practice recovery. Let them work with someone who can challenge their reasoning, and fund that time as part of delivery. Reducing the burden of platform trivia should leave more room to understand systems. The same honesty belongs in the economic conversation. Lower implementation cost changes the price of some work. Where that benefit lands is a separate decision, and the essays about AI economics, open source, and the human bargain keep returning to it. Maintenance, evaluation, and learning still need people and investment. A vendor's attractive price is not an operating strategy. When time does come back, decide with the team what it is for. It might fund reliability work, a modernization experiment, mentorship, or a day with fewer interruptions. Immediately filling every recovered minute with another assignment is a choice about output. We should say so plainly. I began this stretch of writing excited about how much more I could build. I'm still excited, and I know more about what it costs. A correction only compounds when it changes a standard instead of a conversation, and a service is only finished when someone can operate it. I want the measure of this change to be the software we can trust and the engineers who have more room to think. ## Related reading - [The Frame Is the Bottleneck](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/) - [Two Gates and a Night Shift](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/) - [Context Is a Platform Capability Now](https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/) - [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) - [Where the Saved Hour Goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) --- ## The Best AI Developer Experience Might Be Invisible - **Published:** 2026-09-01 - **Tags:** platform-engineering, genai, engineering-leadership - **URL:** https://vinny.dev/blog/2026-09-01-the-best-ai-developer-experience-might-be-invisible/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* "Welcome to PlatformGPT. What can I help you with?" Most platform teams are one sprint away from shipping that sentence. The pieces are lying around: a chat widget or a Slack bot, a model endpoint, and a vector index of the developer docs. Wire them together, drop the result into the developer portal, and the AI box on the roadmap gets checked. I get the appeal, and you'll get points from your leadership for adding AI to your platform. ## The chatbot is the easy checkbox The portal chatbot wins planning meetings because it's legible, demoable, and countable. You can screenshot it for the quarterly review and report how many questions it answered. What the screenshot hides is that the chatbot relocates friction instead of removing it. The developer still has to notice the failure, copy the error, find the chat window, and know what to ask. We moved the search box and called it intelligence. The chatbot also inherits the oldest problem in developer support. It waits. Help that waits to be asked only reaches the developers who ask, and the most expensive friction belongs to the ones who never do. ## The failure that was not yours Start with the least interesting failure your pipeline produces, the one that has nothing to do with the code. The run dies because a registry timed out, a runner got evicted, or a mirror went briefly unreachable. The developer who opened the pull request has no idea any of that happened. What they see is red. The build broke, their name is on it, and the log ends in a stack trace pointing somewhere they've never been. So they do what everyone does. They read the trace, search the error string, and check whether they touched anything nearby. Then they rerun the job to see if it fails the same way twice, and somewhere in that loop they ask in a Slack channel whether anyone else is seeing it. A platform engineer who already knew about the registry problem tells them to retry. Every minute of that is waste, and almost none of it is the developer's to fix. The information that would have ended the loop existed the entire time. It was sitting in the platform, on the wrong side of a question nobody thought to ask. Now run the same failure through a platform that's paying attention. The step fails on an image pull. The platform checks the registry and sees elevated errors in that window. It finds several other runs failing the same way, and it confirms that nothing in this pull request touches that path. That is enough to make a call, so it repairs what it owns, reruns the job, and the run goes green. The developer opens their laptop to a passing build and a note: > This run failed once pulling an image from the shared registry, which reported elevated errors during that window. Several other runs failed the same way. Nothing in your changes touches that path, so the platform switched to the fallback mirror and reran. Tracking as PLAT-2291. Nobody had to notice the failure or ask what it meant. The most valuable thing that platform did was decide the failure was not the developer's, and then act like it. ## Three rungs Most conversations about AI in developer experience are stuck arguing about the first rung of a three-rung ladder. On the first rung, the developer goes to the AI. They notice the failure, carry it to a chat window, and phrase a question well enough to get a useful answer. This is the portal chatbot, and teams ship it first because it's the easiest thing to build. On the second rung, the AI comes to the developer. The failure explains itself where it happened, and nobody has to know what to ask because nothing was asked. On the third rung, the platform handles it and reports what it did. The failure gets diagnosed, the platform-side cause gets repaired, the run goes green, and the developer reads a note instead of a stack trace. I want to be precise about where we are. For most failure categories we're on the second rung, and for a narrow set we're on the third. That narrow set is the interesting part, because it's where the ladder stops being a diagram and starts being a Tuesday. ## Fix what you own, propose what you do not What keeps self-healing honest is asking who owns the failure rather than who could fix it. If the failure belongs to the platform, the platform repairs it and reruns. A registry that flaked, a runner that got evicted, a stale cache, a credential the platform rotates. The developer did not cause any of it and cannot fix any of it, so asking them to participate is theater. If the failure is in the developer's code, the platform proposes and stops. It can be certain, with the diff ready and the tests green, and it still stops, because the branch belongs to the developer and a merge is a decision. The tempting exception is the mechanical fix. A stale lockfile, a formatter violation, a missing license header. The remedy is deterministic, and the platform could apply it without thinking hard. I would still open a pull request instead of pushing the commit, because a deterministic fix is still a change to someone else's branch. Once the platform writes into developer branches because it felt confident, you trade a little friction for a lot of ambiguity about who changed what. ![A decision diagram: a run fails, and the question is who owns the cause. If the platform owns it, the platform repairs the cause, reruns the job, and the run goes green. If the developer owns it, the platform proposes the fix, opens a pull request, and stops for a human to merge](/images/blog/2026/09/invisible-dx-ownership-boundary.png) That line also gives you a clean escalation path. Platform-side failures get quieter over time as the heals accumulate. Developer-side failures get faster, because the proposal arrives before the developer has finished reading the error. ## Where the help belongs Once you start looking for these placements, they're boringly consistent from one platform to the next: - The failed pipeline names the cause in the run output, and repairs it when the cause is ours. - The deployment workflow proposes the compliant fix instead of a link to the policy. - The CLI names the missing permission and drafts the access request. - The control that cannot be satisfied files the exception with its own evidence attached. - The incident tooling correlates the relevant signals before the responder starts hunting. - The platform generates compliant, inspectable configuration from stated intent. Nothing on that list is a destination. The developer never goes to the AI, because the AI is already standing where the developer was about to stumble. ![Three panels: destination AI, where the developer carries the failure to a chatbot; embedded AI, where the platform explains the failure and the developer acts on it; and self-healing, where the platform repairs what it owns and the run goes green](/images/blog/2026/09/invisible-dx-three-rungs.png) ## Two surfaces, on purpose The response belongs in two places, and the split follows the ownership rule. The run output carries the record of what the platform did to its own side. That's where the developer is looking when they're confused, and where a heal has to stay legible after the fact. The pull request carries anything that needs a human decision, because a comment there outlives the log. It's still there tomorrow when someone asks why this branch was retried, and it's there for the reviewer who was never watching the pipeline run. The pattern generalizes past pipelines. Repairs go where the work happened, and decisions go where the owner is standing. ## The platform should know where help is required That is the principle underneath all of it. AI developer experience gets more valuable as the AI stops being a destination and becomes how the platform behaves. A chatbot waits to be asked. A platform knows its own failure points, because they're the same points every week, and it can meet developers there. In [Complexity Is Inevitable. Drag Is Optional.](https://vinny.dev/blog/2026-06-22-turning-complexity-into-leverage/) I argued that good platforms turn unavoidable complexity into defaults and automation, so people can do complex work without absorbing all of its friction. Self-healing is that same conversion, applied to the moment things break. None of it works without the context layer underneath. A platform that cannot see the registry, the recent runs, and this pull request is guessing, and it will guess in complete sentences. That is the argument I made in [Context Is a Platform Capability Now](https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/), and self-healing is the reason it matters more now. Diagnosis needs context, and acting on that diagnosis needs to be right. The pattern holds beyond failures. The [intent interface](https://vinny.dev/blog/2026-08-20-the-golden-path-needs-an-intent-interface/) is invisible AI at the front of the journey, and the self-healing pipeline is invisible AI in the middle. The pre-correlated incident view is invisible AI at the worst moment of the week, which is where it earns the most. ## Nobody argues with the pipeline Self-healing has an ugly cousin that has lived in CI for decades. Blind retry. Rerun the flaky test until it passes, ship it, and let the intermittent defect find a customer instead of an engineer. One rule separates them. Never retry without a reason you can name. A retry that follows a diagnosis is a repair, and a retry that follows a failure is a coin flip you're paying for in compute and in confidence. The trust problem sits underneath that rule. A chatbot answer arrives with skepticism already attached, because the developer knows they're talking to a model and discounts accordingly. A platform action arrives wearing the platform's uniform. It looks like the same tooling that has told the truth about exit codes for decades, so it inherits trust it has not yet earned. Go back to the registry timeout. The platform decided the failure was infrastructure rather than the developer's change, and then acted on that decision without asking. That is the most useful call it can make and the most expensive one to get wrong. If the diagnosis is wrong and the failure was real, the platform cleared the path past a live bug while nobody was in the room. Those risks set the price of admission. Four obligations come with every placement: - Show the evidence behind the conclusion. Name the registry, the window, and the other runs. A developer who can check the reasoning can overrule it. - Say how confident it is, and mean it. Probably infrastructure and definitely infrastructure deserve different actions, and only one of them should trigger an automatic rerun. - Keep the label findable even when it's out of the way. A developer should never have to notice what produced the fix, and should always be able to find out. - Evaluate each placement on its own. Six placements are six products with six failure modes, and one shared model does not give you one shared evaluation. That last obligation is the honest reason teams pick the chat widget. One surface is one thing to test. Six surfaces are six, and the work doesn't get cheaper because the model is the same. ## Invisible to the developer, visible to you There is a second trap, and it's quieter than the first. A platform that heals the same failure every day has stopped reporting a problem it's still paying for. The registry timeout is a real defect somewhere. Someone should fix the registry, add capacity, or move the mirror. If the heal is silent to everyone, the pressure to fix the cause disappears. You've converted a loud, annoying failure into a permanent tax paid in compute, latency, and one more thing your platform quietly carries. The developers are happier and the platform is rotting underneath them. So the heal is invisible in exactly one direction. The developer sees a note. The platform team sees a rate, a trend, and a ranked list of what the platform is absorbing on everyone's behalf. Healed failures belong in your backlog as well as your logs. If the heal rate climbs while the underlying failure rate holds flat, the platform is absorbing a problem instead of solving it. Tracking it that way is what separates a self-healing platform from one that has learned to hide its own defects. ## The part that is hard to count The chatbot hands you a number that measures itself. Questions asked, answers given, thumbs up collected. Self-healing hands you a harder number that points outward: failures diagnosed, failures repaired, reruns that went green without a human, and developer time that was never spent. The last figure is the only one an executive should care about, and it's the hardest to defend rigorously. The instrument for defending it is the subject of the next essay in this series, so I'll leave it there. ## Finding the placements You don't have to guess where the friction lives. Your ticket queue already knows, and so do your failed pipeline runs. Rank the failures by how much developer attention they consume, then work down that list one placement at a time. The queue deserves an essay of its own, and it will get one, because it's the most honest friction map a platform team owns. Start where the failures are frequent, well understood, and cheap to get wrong. Transient platform failures qualify on all three, which is why they're the right first heal. Standards, policy, and compliance decisions qualify on none of them. Those stay on the second rung until your evidence and your risk model justify more. ## The test Here is the test I now apply to every AI feature we consider for the platform. Remove the label. If developers would describe the result as a better platform, the feature is placed correctly. If it only makes sense with the AI label attached, it's probably a demo. Chat still has a job, by the way. It's a good door for open-ended exploration, for onboarding, and for the questions a new engineer doesn't yet know how to phrase. A door is a fine thing to have, and it is not a strategy. The best AI feature in your developer platform may be the failure your developer never had to see. ## Related reading - [The Golden Path Needs an Intent Interface](https://vinny.dev/blog/2026-08-20-the-golden-path-needs-an-intent-interface/) - [Context Is a Platform Capability Now](https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/) - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) - [Nobody Pages the Agent](https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/) - [Complexity Is Inevitable. Drag Is Optional.](https://vinny.dev/blog/2026-06-22-turning-complexity-into-leverage/) --- ## Everyone Is Commoditizing Someone: Battle of the LLMs - **Published:** 2026-08-28 - **Tags:** ai-economics, ai-strategy, engineering-leadership - **URL:** https://vinny.dev/blog/2026-08-28-everyone-is-commoditizing-someone/ In June 2002, Joel Spolsky published a short piece of microeconomics that explains a surprising amount of this month's AI news. [Strategy Letter V](https://www.joelonsoftware.com/2002/06/12/strategy-letter-v/) is about complements: products people usually buy or use together. Gas and cars. Flights to Miami and hotel rooms in Miami. When a complement gets cheaper, demand for the focal product generally rises. A differentiated supplier may capture some of that increased value. Spolsky compressed the strategy into one line: "Smart companies try to commoditize their products' complements." His reading of the early PC market is worth revisiting. IBM built the PC from off-the-shelf parts and documented its interfaces so third-party companies could build memory boards, drives, graphics cards, and printers. Cheap add-ins made PCs more useful. Microsoft licensed DOS to IBM nonexclusively, and IBM sold it as PC DOS. Microsoft kept the right to license MS-DOS to compatible-PC makers, so cheap hardware increased demand for the operating system. IBM eventually sold its PC business to Lenovo. Microsoft remains at the center of the PC ecosystem. Google later ran a cleaner version. Android's primary economic role was not a per-device operating-system license. Google made the Android Open Source Project (AOSP) freely available, expanded the device ecosystem, and then monetized Search, Play, and other proprietary services distributed through it. The operating system was the layer Google made cheap so the rest of the business could grow. Values may be sincere, but they do not explain the timing on their own. Incentives do. Several companies are now running versions of this play on one another at once. Treat the open-weight debate as market strategy as well as a values argument, and it reads differently. Open and closed releases move margin around the AI stack. The price of access keeps falling. The cost of trust holds, and that gap is the whole argument. For enterprise platform teams, the durable assets are the evaluations, context, tool contracts, and audit evidence that let us change models without starting over. One definition before going further: *open-weight* means that the trained parameters are available to download. It does not mean the full training system is open, the license is unrestricted, or the model must be self-hosted. The same artifact can run through a managed endpoint, dedicated hosting, a customer-operated cluster, or a local device. Those are separate architectural and economic choices, and I worked through the local end of that spectrum in [The Frontier on Your Laptop](https://vinny.dev/blog/2026-08-04-the-frontier-on-your-laptop/). ## What each player is trying to make cheap I sit on the buyer's side of these contracts, so I watch model choices turn into cloud commitments, security controls, capacity plans, and exit costs. Six players are running versions of this play on each other right now. | Player | The play | The evidence | | --- | --- | --- | | Hyperscalers (AWS, Microsoft) | Make accelerators and model access cheaper. The durable prize is platform consumption on their own bill and control plane. | Microsoft [introduced Maia 200](https://blogs.microsoft.com/blog/2026/01/26/maia-200-the-ai-accelerator-built-for-inference/) in January 2026 on TSMC's 3nm process, claiming 30% better performance per dollar than its current fleet. AWS made [Trainium3 UltraServers](https://aws.amazon.com/about-aws/whats-new/2025/12/amazon-ec2-trn3-ultraservers/) generally available in December 2025. Anthropic [committed more than $100 billion to AWS](https://www.anthropic.com/news/anthropic-amazon-compute) over 10 years for up to five gigawatts, then [committed $30 billion to Azure compute](https://www.anthropic.com/news/microsoft-nvidia-anthropic-announce-strategic-partnerships) while Nvidia and Microsoft agreed to invest up to $10 billion and $5 billion in the company. | | Nvidia | Make models and cloud capacity plentiful and contestable, so aggregate demand grows faster than serving efficiency cuts compute per task. | [Nemotron 3 Ultra](https://developer.nvidia.com/blog/nvidia-nemotron-3-ultra-powers-faster-more-efficient-reasoning-for-long-running-agents/) ships 550 billion total parameters, 55 billion active, under the permissive OpenMDW-1.1 license. A [revenue-sharing and credit-support model](https://blogs.nvidia.com/blog/nvidia-unlocks-ai-compute-at-scale-capital-partners-to-power-ai-infrastructure-buildout/) for participating AI clouds followed in July. In March it [invested $2 billion in Marvell](https://nvidianews.nvidia.com/news/nvidia-ai-ecosystem-expands-as-marvell-joins-forces-through-nvlink-fusion) and brought Marvell's custom silicon and networking into NVLink Fusion. | | Meta | Make locally deployable intelligence cheap. Its economics still sit in apps, devices, advertising, and developer reach rather than token sales. | Muse Spark arrived closed on [April 8](https://ai.meta.com/blog/introducing-muse-spark-msl/), went metered through the [Meta Model API](https://ai.meta.com/blog/introducing-muse-spark-meta-model-api/) on July 9, and 1.2 stayed closed on August 5. Five days later Meta [released Muse Glimmer](https://research.meta.ai/blog/introducing-muse-glimmer-open-agentic-model), 30 billion parameters under Apache 2.0, tuned for always-on local agents. Zuckerberg committed to opening Muse Spark 1.2 the same day, [repeated in research](https://research.meta.ai/blog/multimodal-intelligence-of-muse-spark-1-2) on August 20. | | Chinese labs (DeepSeek, Qwen, Moonshot, Z.ai, MiniMax) | Substitute for American model APIs outright, which pulls demand toward the clouds, devices, and apps their platform owners run. | Licenses run from MIT to Apache 2.0 to MiniMax M2.7's non-commercial terms, which require written authorization. [Wing Venture Capital estimated](https://www.wing.vc/content/chinas-open-weight-takeover) Chinese-origin models at 56% to 61% of OpenRouter token volume in May 2026, four of the five most-used models, with Xiaomi's MiMo at roughly 21% and Meta below 1%. | | Frontier labs (OpenAI, Anthropic) | Nothing yet. They are annexing the layer above the model instead: coding agents, applications, and workflow surfaces. | Menlo Ventures' [December 2025 enterprise study](https://menlovc.com/perspective/2025-the-state-of-generative-ai-in-the-enterprise/) put Anthropic at 40% of enterprise LLM API spend, OpenAI at 27%, and Google at 21%, with Anthropic's lead driven substantially by coding. | | Stripe | Make the routing layer neutral and cheap, then meter what flows through it. | [Agreed to acquire OpenRouter](https://stripe.com/newsroom/news/stripe-agrees-to-acquire-openrouter) on August 19. | Three things sit underneath that table. Equity investments, compute purchases, and capacity agreements are different instruments, and collapsing them into one headline number flatters the story. Together they still fit one portfolio strategy: secure scarce model supply and differentiated demand while improving infrastructure cost and supplier leverage. Satya Nadella put it plainly. "We're increasingly going to be customers of each other." The second is the move I keep coming back to, because it undercuts the substitution story. AWS [is designing Trainium4](https://developer.nvidia.com/blog/aws-integrates-ai-infrastructure-with-nvidia-nvlink-fusion-for-trainium4-deployment/) to support NVLink 6 and Nvidia's MGX rack architecture. AWS reduces its accelerator dependence while still using Nvidia's scale-up fabric and rack ecosystem. Nvidia's [fiscal 2026 results](https://www.sec.gov/Archives/edgar/data/1045810/000104581026000019/q4fy26pr.htm) report $215.9 billion in revenue at a 71.1% company-wide gross margin, down from 75.0% a year earlier with a $4.5 billion charge on H20 inventory among the causes. Neither figure proves where the surplus settles. Both are consistent with real pricing power at the infrastructure layer today. Reducing dependence on a supplier is hard when your substitute still uses roads the supplier built. The third is where the complement frame only half applies. Chinese open-weight models are substitutes for American APIs, not complements, and their effect is downward price pressure on every workload they can serve. The frame explains why platform owners such as Alibaba and Xiaomi amplify that pressure, since accessible models pull demand toward cloud services, devices, and downstream applications. It does not explain every independent lab's motive. The OpenRouter figure needs the same care, because it counts tokens routed through one marketplace rather than global market share. That marketplace just changed hands. Patrick Collison framed the Stripe deal around helping companies route requests intelligently and spend tokens efficiently. A payments company buying the neutral switching layer is the same play, one level up. ## The asymmetry that decides this Near the end of his letter, Spolsky made an observation that has aged well as a heuristic. Software can make hardware more substitutable by hiding differences behind an abstraction. Hardware has a harder time commoditizing software, because switching costs live in behavior, data, integrations, and learned habits. Modern AI hardware complicates the clean version of that story. The top-level API may look thin. Underneath it, compilers, hand-tuned Triton and FlashAttention kernels, collective communication libraries, quantization formats (FP8, AWQ), memory topology, and serving-runtime optimizations stay tightly coupled to the silicon. That is one reason downloadable weights can still reinforce Nvidia's position. Model access breaks the pattern in another way. A normalized gateway can make a first experiment look like a simple configuration change. Production substitution is harder. Tokenization, prompt formats, tool calling behavior, context limits, safety guardrails, latency distributions, rate limits, and serving topology can all change underneath the endpoint. The cost of access to capable weights is falling faster than the work required to substitute them safely in production. The switching cost did not disappear. It moved into the evaluation suite that proves a model is good enough for your risk tolerance. It lives in the prompts and tool contracts your agents depend on. It lives in the retrieval and context layers that make a general model useful, and in the audit trail your regulators expect. Changing a model identifier can be easy. Re-earning confidence is not. That is the argument I made in [Context Is a Platform Capability Now](https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/), arriving from a different direction. The model gets cheaper, and everything wrapped around it gets more valuable. [The Kill Switch Was Always There](https://vinny.dev/blog/2026-06-13-the-kill-switch-was-always-there/) reached the same place from a government order, where portability gets you out and verification gets you out safely. ## The number that should slow everyone down Here is the finding that complicates every clean narrative about open weights winning. Menlo's late-2025 study estimated that models it labels open source fell from 19% to 11% of enterprise LLM API spend. Those are primarily open-weight artifacts under varying permissive and community licenses. Menlo attributes much of the decline to Llama's stagnation, with no major release since Llama 4 in April 2025. Chinese open-source models account for roughly 1% of total enterprise LLM API usage in the same data. The study surveyed 495 U.S. enterprise AI decision-makers and estimated dollars from respondents' reported shares of production API workloads, weighted by application scale and triangulated with public financials where available. That is relative share, not proof that absolute usage fell. It does not tell us that most enterprises tried self-hosting and rejected it. Menlo's evidence also ends in 2025, even though open-weight capability continued moving through 2026. Set that beside the OpenRouter figure and you do not get a contradiction. You get two signals measured different ways. OpenRouter aggregates prompt and completion tokens processed through its own API, and its rankings do not establish a geographic population of buyers. Menlo estimates U.S. enterprise LLM API dollars from reported production workload shares. The channel, population, unit, and method all differ. A partial bridge exists. CNBC reported in July 2026 that Chinese-origin models accounted for 46% of U.S. enterprise token usage on OpenRouter, a figure that sits between the two. The divergence is still useful. High routed token volume on OpenRouter does not automatically translate into enterprise procurement. Capability, support, indemnity, provenance, managed availability, data residency, security review, and a 2 a.m. escalation path all affect the decision. The constraint is not simply capability or simply cost. It is whether the full operating model can clear the organization's bar. Anyone who has taken a self-managed model through security review has felt that gap firsthand. > The economics of the model layer changed faster than the operating model around it. ## Your switching cost is somebody else's margin Across these examples, companies are making complements cheaper, substituting for suppliers, or moving into stickier adjacent layers. The tactics differ, but each seeks more leverage over where margin accumulates. From the enterprise buyer's chair, the true sovereign asset is our integration, context, and evaluation layer, not the model. Our workflows, proprietary data, evaluations, corrections, permissions, and controls turn a general model into a business system. That is the same asset I called the learning loop in [Paying for Intelligence Twice](https://vinny.dev/blog/2026-07-13-paying-for-intelligence-twice/), and it is the thing the Context Spine was always meant to hold. If those assets live behind one vendor's boundary, the cheap model becomes an expensive exit. ![Open-weight models and closed model APIs both feed into our integration, context, and evaluation layer, which holds evaluations, context, tool contracts, and audit evidence.](/images/blog/2026/08/durable-assets-layer.png) Salesforce wrote up the clearest version of this problem I have seen from a vendor. In [a July 2026 post](https://www.salesforce.com/news/stories/cutting-inference-spend-by-right-sizing-models/), the company described how Agentforce had run entirely on one rented model while its token bill grew with traffic. Salesforce then pulled out five narrower jobs: intent detection and routing, prompt-injection screening, output toxicity screening, answer evaluation, and reranking. It tuned a task-specific open-source model for each, using patterns from millions of jobs its harness had already processed. Two of those models, the classifier and the evaluator, are fine-tuned from OpenAI's gpt-oss-20b. The open weights one lab released are now displacing another lab's rented frontier calls. It did not replace every frontier call. A frontier model still handles core multi-step reasoning, and the harness Salesforce built lets it and its customers swap that model freely. Easy swapping came last in that story. Salesforce could build toward it because it had recurring workload volume to amortize specialization, telemetry to find reusable seams, and a trust layer to deploy into. Portability was the output of that investment rather than a property of open weights. Its result shows that decomposition works under the right conditions, and those conditions are the expensive part. ![Two arrangements side by side. On the left, one rented frontier model handles intent routing, prompt-injection screening, output toxicity screening, answer evaluation, and reranking, and the token bill grows with traffic. On the right, a harness runs five tuned models for those jobs and leaves the frontier model swappable.](/images/blog/2026/08/harness-vs-one-rented-model.png) Shared on-demand APIs usually turn capacity risk into a variable bill. Provisioned throughput and customer-operated clusters move more of that risk to the buyer through hourly reservations, minimums, or fixed or stepwise capacity, though autoscaling and overage terms vary. On unit economics alone, those options win when sustained utilization amortizes idle and high-availability headroom and the organization can absorb upgrades, observability, safety work, and on-call ownership. Teams may still choose them for latency, residency, or control. Compare cost per successful task over the real production distribution rather than price per million tokens. Include retries, failures, idle capacity, and the resources needed to hold the p95 latency SLO at design load. I would not read Salesforce's result as an argument for operating every model yourself. I would not read Menlo's 11% as evidence that most enterprises tried the cheap option and rejected it either. I read both as an argument for keeping the exit affordable. Five practical moves follow, each within a platform team's reach this quarter: 1. Price the exit and the option. Measure engineer-weeks, dual-running, data egress, compliance recertification, replacement capacity, unused commitments, contract termination, and rollback. Run a representative model-switch drill instead of estimating from a diagram, then put the resulting number in front of your finance partner. An unpriced option loses every budget argument it enters. 2. Treat evaluation assets as durable infrastructure. Keep a versioned task corpus, production traces, human labels, rubrics, and explicit acceptance thresholds. Run them in the delivery pipeline, and recalibrate model-based judges when the model changes. 3. Route by evaluated workload class. Choose the least costly option that clears quality, safety, latency, residency, and reliability requirements. The answer may be deterministic software, a small managed model, a tuned open-weight model, or a frontier model. Add canaries, fallbacks, and rollback. 4. Keep the context contract under enterprise control. Own the canonical sources, permissions, provenance, schemas, version history, and reconstruction path. Vendor-managed indexes and caches are fine when they are disposable, exportable, and rebuildable. 5. Budget the full bill. Proprietary APIs still require integration, evaluations, and governance. Customer-operated open weights add capacity planning, serving operations, cloud or hardware cost, power where directly operated, patching, observability, disaster recovery, model refreshes, incident response, and the people who own all of it. Measure cost per accepted outcome under your target SLO. ![Five moves: price the exit and the option, treat evaluations as infrastructure, route by evaluated workload class, keep the context contract in house, and budget the full bill.](/images/blog/2026/08/five-moves-checklist.png) The platform team's job is to absorb this complexity once, so every product team does not have to become expert in model procurement, inference operations, and governance. Portability should be a shared capability rather than another burden handed to developers. ## Where this argument could be wrong The complement frame predicts incentives. It does not read minds, and I would rather name its limits than oversell it. Motives here are genuinely mixed. Some open releases come from research culture, recruiting pressure, and a real belief that broad access makes systems safer. Meta's shifting distribution strategy looks tactical. Google and OpenAI have publicly framed Gemma and gpt-oss around access, research, and responsible deployment, and I take those framings at face value. Strategy and conviction can point the same way. The stronger objection is that enterprise buyers may never value portability enough to pay its option cost. The simplicity of one vendor, one contract, and one accountable party may keep winning even if open weights hold capability parity. That outcome could mean switching risk matters less than I think. It could mean managed accountability is worth the lock-in, or that closed-model capability stays sufficiently differentiated. I do not think leaders should fund portability on faith. Price it, then decide. The evidence that would change my mind is specific. Show me several large, regulated enterprises that repeatedly move production agent workloads across model families in weeks. Assume no prior investment in vendor-neutral evaluations, context contracts, or audit paths. Quality, safety, latency, unit economics, and rollback all hold. That would materially weaken my claim that portability must be built as a strategic platform capability. I have not seen that pattern yet. I would like to. Platform leaders cannot control which layers vendors choose to make cheap. We can control whether our evaluations, context, and audit trail keep those vendors replaceable. Make that choice deliberately, before someone else makes it and sends the invoice. ## Related reading - [The Frontier on Your Laptop](https://vinny.dev/blog/2026-08-04-the-frontier-on-your-laptop/) - [Context Is a Platform Capability Now](https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/) - [The Kill Switch Was Always There](https://vinny.dev/blog/2026-06-13-the-kill-switch-was-always-there/) - [Paying for Intelligence Twice](https://vinny.dev/blog/2026-07-13-paying-for-intelligence-twice/) - [The Modernization Backlog Just Got Repriced](https://vinny.dev/blog/2026-08-01-modernization-backlog-repriced/) - [Where the Saved Hour Goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) - [The More AI We Have, the More Human Judgment Matters](https://vinny.dev/blog/2026-07-26-the-more-ai-we-have/) --- ## Nobody Pages the Agent - **Published:** 2026-08-24 - **Tags:** agentic-sdlc, engineering-leadership, platform-engineering - **URL:** https://vinny.dev/blog/2026-08-24-nobody-pages-the-agent/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* A page still ends at a person's phone. At 3 a.m., a service fails under real load, the graphs are ugly, and the engineer on call opens the code to find out what it does. Nobody on the bridge wrote it. For most of my career, that sentence meant the author had left the company. Now it can mean the author was never a person. That scene is not from our incident log, and my job is to keep it that way. I no longer believe the gates alone will. I left this question open at the end of [The Golden Path Needs an Intent Interface](https://vinny.dev/blog/2026-08-20-the-golden-path-needs-an-intent-interface/). This is the answer I owe it. The new constraint is whether an organization can preserve enough operational understanding to restore generated software when production violates the model the spec described. If intent compiles into implementation, operability has to become part of the intent. ## The diagram ends too early Most of the agentic SDLC argument, mine included, is about getting a change safely to production. The spec defines the work, the standards constrain it, the specialist agents produce it, and the gates verify it. [Two Gates and a Night Shift](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/) put human judgment at the two points where it is cheapest and most consequential. The pipeline carries the change through deployment and live verification, and I stand by every step of it. Then the diagram ends, and the service keeps running. I also went back through my own archive. I've written often about how work gets specified, generated, reviewed, and merged, and barely at all about what happens after that. The run side of my own argument is mostly unwritten, which is a strange gap for someone who carries operational responsibility for a Fortune 100 production estate. Nobody pages the agent. Every production service still needs a human owner, and ownership without comprehension is only a name in a catalog. ![Timeline: spec, standards, gates, deployment, and live verification covered in green, followed by a long gray uncovered stretch ending at a 3 a.m. page](/images/blog/2026/08/nobody-pages-timeline-v2.png) ## The failure hides somewhere else Bad code in the obvious sense already leaves evidence. Syntax errors, type mismatches, and missed null checks show up for a compiler, a test, a linter, or a reviewer. The dangerous change is the one that looks reasonable everywhere we know to inspect and is wrong only when it meets the system we failed to describe. Agents changed the economics of that failure class rather than inventing it. They can produce plausible implementations from an incomplete model faster than a team can discover what the model omitted. If the spec describes success and the tests model success, the output can be coherent and confidently incomplete. In Part III of [the second edition of the book](https://vinny.dev/book/), I gave this failure a name: the confident defect. A confident defect is a failure that ships fluently, with a diff that looks right and tests that pass while the wrong thing reaches production. A gate catches only what its standards and evaluation exercise. The defect lives in the link the system skipped. The shape is easy to recognize. A retry policy looks reasonable in review and passes every test built around returned errors. Under production concurrency, a slow dependency triggers retries, the retries amplify load, and degradation becomes a thundering herd problem. The implementation did exactly what the spec described, and the page comes from everything the spec left out. ## Comprehension debt Recovery time has many inputs. Comprehension is one of them, and it's the one this essay is about. A responder who carries a working mental model can use the failure to test a suspicion, while a responder without one starts from symptoms, at night, under pressure, with no map. When nobody wrote it, nobody remembers it. Nobody should have to memorize generated code to hold a pager. That would rebuild the syllabus the intent interface exists to retire. The human needs a smaller model: what normal looks like, how the service fails, which signal separates one failure from another, and how to return it to safety. The gap between what a team's system does and what the team can explain well enough to maintain it has a name. Addy Osmani calls it [comprehension debt](https://addyosmani.com/blog/comprehension-debt/). It's related to technical debt, but it doesn't live in the code alone. Clean code can carry it, and ugly code can be well understood. It lives in the distance between the system and the people responsible for restoring it. Technical debt usually leaks into normal work through slow features, fragile changes, and familiar grumbling. Comprehension debt can remain silent until an incident calls it due, all at once, with interest. Agents do not create that debt. They let us acquire it at merge speed. ## What agents actually changed Engineers have always operated systems they did not write, and I cannot argue that away. Human authorship never guaranteed shared understanding. It did create repeated chances to build it: the implementation struggle, the design argument, the review comment, and the teammate who remembered why the retry count is four. Agent-produced changes can compress or remove those encounters, arriving faster and with less human contact. A transcript can preserve provenance, but provenance is not a mental model. It records what the agent attempted and what the human accepted, and it cannot guarantee that anyone can explain the system when the symptoms break the script. An agent can join the bridge too, and it should. It can read the runbook, correlate the signals, and propose a first action. The accountable owner is still a person, and the mental model that person needs most is the one that lets them recognize when the agent's suggestion is wrong. The risk is the ratio. Agent-mediated change can outpace the humans who need to reason about it under pressure. Most delivery metrics don't watch that ratio. If code nobody remembers is arriving at merge speed, we have to create and verify operability at the same speed. ## Operability is spec-shaped The fix is convenient for me, because it's the fix I keep proposing: put it in the spec. Operability is a requirement like any other. SLOs, expected failure modes, ownership, the rollback path, and the runbook belong in the specification and travel with the change. A gate that blocks a missing test can block a missing rollback path. An agent that can write the service can draft the runbook for the service. That's useful, and it is not proof, because a generated runbook is still generated confidence. The artifact says what should happen, and an exercise tells you whether it does. Execute the rollback, restore the backup, fire the alert, and inject a failed dependency. Then put enough load through the canary to observe the behavior the spec promised. Chaos engineering already runs experiments like these against a steady-state hypothesis. Here the hypothesis comes from the operability spec, and the experiment runs at the gate, before the change merges. Not every change reruns every exercise. The service carries the baseline, and a risky change refreshes the evidence it can invalidate. Return to the retry policy. Checking that it retries four times after an error is the easy test. The operability spec says what happens when the dependency is slow under representative concurrency. The gate injects the latency, verifies that outbound calls remain bounded, and exercises the rollback. The runbook points to the signal that separates dependency latency from local saturation and names the first mitigating action. Now the spec, the gate, and the person holding the pager share the same model. Here is the minimum service contract I would require before changes merge: - Name an SLI tied to user impact, the SLO target and measurement window, and the error budget implied by them. - Name the accountable owner and the escalation path. - Name the critical dependencies and describe what the service does when each one is slow or unavailable. That's a different question from what it does when each one returns an error. - Carry a rollback path somebody has executed rather than described. - Ship a runbook for the highest-likelihood and highest-impact failures, the signal that separates them, and the first safe action for each. - Define whether the service degrades, rejects work, or fails closed under representative and above-forecast load, because saturation is where plausible defaults become production incidents. Most estates carry hundreds of services that predate any contract like this. The gate applies to their next change, and service owners backfill the baseline by risk tier, starting with the services whose failure would hurt the most. None of that is new reliability practice. In many organizations, pieces already exist on a wiki page written once and opened too rarely. What changed is the cost. An agent can draft the operability package alongside the change, while the task context and evidence are still available, and automation can make the exercises repeatable. Neither makes judgment free, and that's fine, because the expensive part should be proving the service can fail safely, not typing the runbook. The package is now cheap enough that its absence should be indefensible, and the evidence still has to be earned. [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) argued that the spec is the durable asset and the code is regeneratable output. This essay is what durable has to mean. A spec that stops at the happy path is a build artifact. A spec that carries the evidence needed to restore the service is an operational asset. That creates a control loop. Specify operability in the service contract, prove it with exercises, measure what production teaches you, and throttle change to the reliability the service has demonstrated. ![Control loop diagram: four boxes in a cycle labeled specify, prove, measure, and throttle, with the merge marked between prove and measure and the missing requirement feeding back into the next gate, around a human owner at the center](/images/blog/2026/08/nobody-pages-control-loop.png) ## Tag agent involvement in the incident review One form field costs almost nothing, and reliable provenance behind it is harder. Incident reviews should record the degree of agent involvement in every suspected contributing change, whether or not it was the apparent trigger. Start with agent involvement: human-written, agent-assisted, or agent-primary. Record supervision separately, and preserve the originating spec, retained session or build provenance, verification path, and named human owner. Keep the trigger, contributing conditions, and authorship separate. Treat agent involvement as telemetry about the operating model rather than a verdict on the tool. The classification will be imperfect at first, and imperfect provenance is still better than none. The field exists so the questions become answerable. Do changes with heavy agent involvement fail in different ways, and do they take longer to recover? Did the runbook shorten the night, and which missing requirement should become the next gate? Until that field exists, every confident claim about how agent-involved changes behave in your production system is still a story. ## Error budgets are the throttle When agents can produce changes faster than humans can absorb them, something has to set the pace. [Error budgets](https://sre.google/sre-book/embracing-risk/) already connect a service's reliability to its release velocity. Do not invent a separate morality for machine-written code. [Trust the gate, not the actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/), and apply the service's existing policy regardless of who, or what, produced the change. [Burn rate](https://sre.google/workbook/alerting-on-slos/) is established too, as an alerting signal. I would wire the release policy to it, the same way the alerts already are. A service with budget remaining can still be burning it fast enough to justify tighter release rules before it runs out. While the service remains within its SLO and below the agreed burn-rate thresholds, changes follow the normal release policy. When it begins consuming budget too quickly, tighten the policy. When it exhausts the budget for a cause the service can control, freeze non-remediation changes to that service. Rollbacks, urgent security fixes, and recovery work keep moving. This is still policy. The difference is that it's tied to observed service behavior rather than confidence in the actor. Agree on the thresholds, owners, exceptions, and resume conditions before the incident, then encode the parts the pipeline can enforce. That policy needs a mechanism behind it. Cap non-remediation changes per service per change window, require service-owner review, use smaller canaries for necessary changes, and hold net-new work while recovery proceeds. Encode the rule once, where it applies without a debate about whether this particular agent is trustworthy. The system earns throughput by demonstrating that it can absorb and recover from what it ships. That rule also answers the uncomfortable executive question of how fast agents should be allowed to go: as fast as the service can absorb without missing its SLO, and not one merge faster. The gate proves a standard ran. The person holding the pager at 3 a.m. finds out whether we can live with what it let through. ![A pager drawn as a field guide: a one-line read-only screen, an alert light, a single AA battery, a belt clip, read and menu buttons, and an eight-second beep or vibrate alert, captioned that the device retired and the verb stayed](/images/blog/2026/08/nobody-pages-pager-field-guide.png) ## Related reading - [Two Gates and a Night Shift](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/) - [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [The Golden Path Needs an Intent Interface](https://vinny.dev/blog/2026-08-20-the-golden-path-needs-an-intent-interface/) --- ## My Mac Ran Out of Headroom, So I Built Some - **Published:** 2026-08-23 - **Tags:** side-projects, genai, engineering-leadership - **URL:** https://vinny.dev/blog/2026-08-23-my-mac-ran-out-of-headroom/ The fans spun up one morning and never wound down. I had a couple of Claude Code sessions deep in different repos, a local model resident under Ollama so an agent could review diffs without leaving the machine, a llama.cpp experiment I had forgotten about, and another agent grinding through dependency updates in the background. Somewhere under all of that, a headless Chrome that no living process owned had quietly claimed itself as my default link handler. Every URL I clicked opened in a browser with no window. None of these programs was misbehaving, exactly. Each one was doing the job I gave it. The problem was that I could no longer see the whole, and macOS was not helping. Activity Monitor answers "what is my Mac doing" with 400 rows, 14 of them named Google Chrome Helper (Renderer). What I wanted fit in a glance: the top 10 things spending my CPU and memory, each app collapsed to a single line, and a way to stop the runaways that had outlived their purpose. So I built it. It is called [System Headroom](https://macheadroom.com/), it is live on the [Mac App Store](https://apps.apple.com/app/system-headroom/id6794655648) as of this week, and the story of building it is mostly the story of what Apple's App Sandbox will and will not tell you. ## Why I still ship By day I lead cloud, platform, and DevOps engineering for a few hundred engineers. My calendar is mostly architecture reviews, vendor negotiations, and the slow work of keeping a big organization moving. On nights and weekends I [ship my own apps](https://vinny.dev/apps/), and I have since 2014. The habit keeps my judgment honest about what building costs, and it keeps me close to the people who do it all day. I do not pretend a one-person Mac app is equivalent to shipping software inside a large enterprise. It is not. But the mechanics are close enough to keep certain muscles from atrophying: turning an idea into a brief, discovering where the platform disagrees with you, debugging what only appears under real use, deciding what not to ship, and eventually putting something in front of people. Those experiences make me more careful when I ask teams to move faster, simplify a design, or accept a platform constraint. I also wrote [a book](https://vinny.dev/book/) arguing that the bottleneck is never the stack. This project handed the stack a whole summer to argue back, syscall by syscall. ## Ten rows, not four hundred The design brief fit in a paragraph. A menu bar app you glance at and close. The top 10 CPU consumers and the top 10 memory consumers, with every process that belongs to one app folded into a single row. No Dock icon, no accounts, no third-party dependencies, and no network access at all. A system monitor that phones home becomes one more process you have to monitor. ![System Headroom's CPU view: the top consumers grouped by app, Chrome and its helpers collapsed to one row at 24 processes](/images/blog/2026/08/system-headroom-cpu.png) There is a small irony in the build itself. The first file in the repository is [the written brief](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) I handed to Claude Code. The same class of tools that buried my machine in processes helped me build the thing that watches them. It turns out a decade of writing one-page briefs for engineering teams is direct training for writing one-page briefs for agents. An agent is an unforgiving reader, and vague sentences come back as vague software. The stack is deliberately boring: SwiftUI's MenuBarExtra on macOS 14 and later, Swift 6 with strict concurrency checking turned all the way up. The interesting parts were never going to be the UI. ## The sandbox says no, with receipts A Mac App Store app lives inside the App Sandbox, and the sandbox has opinions about process snooping. Before writing any app code, I ran a feasibility spike that called every relevant syscall against every class of process and recorded what came back. That file, SANDBOX_NOTES.md, became the most valuable document in the repository. It settles arguments, mostly with myself. It is the same move I ask of teams at work: when a debate keeps coming back, replace opinion with measurement and let the errno talk. Here is what it settled. A sandboxed process can read the process table through sysctl. For anything running as the same user, proc_pidinfo will report CPU ticks and resident memory size. Root's processes and other users' processes are invisible entirely. And the memory number Activity Monitor shows, physical footprint, comes from an API that returns EPERM for every process except your own. That last one forced the first real product decision. I could not match Activity Monitor's memory column, so I stopped trying. System Headroom reports resident size, the notes document exactly why, and the divergence is a settled decision instead of a recurring bug report to myself. Measured constraints beat aspirational ones. ![System Headroom's Memory view, showing per-app resident memory with each app grouped to one row](/images/blog/2026/08/system-headroom-memory.png) ## Grouping is the product The kernel gives you processes; people think in applications. The gap between the two is the product. The kernel gives you process names 16 characters at a time. That is MAXCOMLEN, the size of p_comm in kinfo_proc, and it is why raw tools show you entries like "Google Chrome He". Any grouping logic has to survive truncation. The engine resolves each process to its owning app in three steps: walk the parent-pid ancestry until it reaches a known app, then strip " Helper" style suffixes from the name, then fall back to treating the process as standalone. It is pure Swift with no syscalls in it, which means the whole thing runs against fixtures in tests. Chrome and its helpers become one row; on my machine this morning, that is 24 processes. So does an agent and the process tree it spawned. That translation matters more than the raw numbers. A system monitor can be perfectly accurate and still be cognitively expensive. I did not want a better process table; I wanted a useful answer to a simpler question: what is consuming my machine right now? ## Bugs that only a live app can teach Three bugs made it past me into a running build, and each one taught me something about the platform. None of them would have reached me in a status update. Bugs like these introduce themselves only when someone is using the software, which is one reason I still hold the keyboard myself. The first was a CPU reading a thousand times too high. The sampler is an actor, and I was capturing the tick timestamp before hopping into it. Under contention the hop got delayed and the elapsed time between samples approached zero. Dividing accrued CPU ticks by almost nothing produced readings in the thousands of percent. The fix was a rule, not a patch: the actor owns the clock and takes every timestamp inside it, next to the sweep. A burst test now hammers the sampler to keep that rule honest. The second was a popover that refused to grow. MenuBarExtra's window style measures its panel once, at open, before the first sample has landed, and never resizes it. My list arrived a half second later into a window sized for nothing. The fix inverts the dependency: the list region has a fixed height whether it holds zero rows or 10, and a layout test asserts that an empty store and a full one measure identically. The third was two copies of the app in the menu bar, because I relaunch constantly during development. Now every launch broadcasts a takeover notice over DistributedNotificationCenter, and older instances quit when they hear it. The newest launch always wins, which turns redeployment into "build and open." ## The ports detour Once the app could tell me who was eating the CPU, I wanted one more view: who is listening on which port. A surprising number of the runaways I care about are development servers somebody forgot. The obvious approach is the lsof one, walking file descriptors per process. The sandbox returns EPERM for every process but your own. My test plan, binding a port myself and checking the app saw it, died the same way: bind() is EPERM outright. What works is asking the kernel for the whole TCP and UDP tables through the net.inet pcblist_n sysctls. Parsing them means structures copied from the xnu headers and packed exactly as the kernel emits them. The live test's oracle is netstat: the app and the tool must agree on the listening set. It is not glamorous code, but it turns another noisy system detail into something I can understand in a glance. ![System Headroom's Ports view listing every local listening port, 36 ports across 21 processes](/images/blog/2026/08/system-headroom-ports.png) ## The feature that could not ship Here is the punchline the sandbox saved for last. The reason I started this project was the kill switch: find the orphan, click, done. The App Sandbox denies every path to terminating another process. The polite AppKit call fails, the POSIX signal fails, the scripting route fails. I measured each one and wrote the results down next to the others. And the sandbox is right. An app you downloaded from a store should not be able to reach over and kill your other software. The security model turned out to be the answer rather than the obstacle, and it split the product cleanly in two. So System Headroom ships as two editions built from one codebase, with a single compile-time flag between them. The Mac App Store edition is fully sandboxed and monitors only; the quit controls are capability-gated and do not exist in that binary. The Direct edition is Developer ID signed, notarized, and unsandboxed. It adds Quit and Force Quit, reports physical-footprint memory that matches Activity Monitor, and updates itself with Sparkle. The Direct build runs on my own Mac today, and the delivery pipeline for everyone else is built and waiting on one more conversation with Apple. ## Rejected for the pun The app was not always called System Headroom. I named it Mac Headroom, because a machine overrun by chattering AI processes deserved a nod to Max Headroom, the stuttering synthetic TV host of the 1980s. I was proud of that name. App Review was not. Guideline 5.2.5: you do not put "Mac" in a product name. The rejection arrived, the rename took a day, and the resubmission went through. Apple applies the rule evenly and I have no complaint. My organization reviews other people's work all day. It is healthy to have a finding land in my own inbox once in a while and to simply fix it. I did keep the domain, though. The pun lives on at [macheadroom.com](https://macheadroom.com/). ## Shipped Version 1.0 is live on the Mac App Store now. The headline number is the one the name promises: how much machine you have left. Below it, the app shows the top 10 CPU and memory consumers grouped by app, lists every local listening port, explains what each mystery daemon is in a built-in glossary, and leaves your network untouched because it has nothing to say to anyone. *The sandbox never shrank this app. It drew the floor plan.* Every constraint that started as an obstacle ended as a product decision: the memory metric, the grouping design, the ports implementation, the two-edition split. If you are building on someone else's platform, measure the walls before you draw anything, write the errno down, and let the platform tell you what the honest version of your idea is. Shipping it also paid the day job back. When an engineer tells me the platform will not allow something, I now know what a measured no looks like. I spent a summer collecting them. The sandbox won nearly every argument we had, and the app is better for each loss. My book claims the bottleneck is never the stack, and this summer the stack agreed. The runaways, meanwhile, have not gone anywhere. As I wrote this, a dependency agent finished its run and left a node process idling where a build once ran. This time I saw it in seconds. That is the whole app. ## Related reading - [Claude Code Is a Build System, Not a Chatbot](https://vinny.dev/blog/2026-04-25-claude-code-build-system/): the six principles behind the daily practice that produced this app's first file. - [The Frontier on Your Laptop](https://vinny.dev/blog/2026-08-04-the-frontier-on-your-laptop/): the local models from this essay's opening scene, and how to run your own. - [Where the Saved Hour Goes](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/): what people do with the time AI hands back. This app is one of my answers. - [The Bottleneck Is Never the Stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/): the thesis the sandbox spent a summer testing. --- ## The Golden Path Needs an Intent Interface - **Published:** 2026-08-20 - **Tags:** platform-engineering, agentic-sdlc, spec-driven-development - **URL:** https://vinny.dev/blog/2026-08-20-the-golden-path-needs-an-intent-interface/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* Here is what our golden path asks of a developer who wants to ship a new service. Pick the right template from a menu of similar-sounding options. Fill in roughly 20 fields, several of which assume you already know our tagging taxonomy. Understand enough Terraform to recognize which module does what, configure the pipeline correctly, and request the right permissions. That path is a real achievement. I have spent years helping build it, and I would defend every control on it. It beats starting from zero by a wide margin. But I have stopped pretending it is simple, because the golden path has a quiet requirement we rarely say out loud. Before a developer can walk the road, we ask them to learn it. ## The golden path is a syllabus Platform engineering earned its keep by paving the road. We took hundreds of decisions that every team used to make badly and differently, and we turned them into templates, defaults, and guardrails. The paved road works. What it never fixed is the interface, which still speaks implementation. To use our platform well, a developer has to hold our taxonomy, our module names, our pipeline stages, and our exception processes in their head. The expensive part of that knowledge does not transfer. A developer who mastered our golden path would still start over at their next company, because what they learned was us. That is the tell. When the expertise a platform demands is expertise about the platform itself, the platform is charging a tax and calling it a curriculum. ## Intent is the new interface With agents in the loop, the interface can move up a level. Instead of a template plus 20 fields, the developer states what they need: > I need a TypeScript API, externally accessible, storing customer-confidential data, deployed in two regions, with a 99.95% availability target. Natural language is not the contract. It is how the developer enters the contract. The platform should normalize that request into structured, reviewable intent: workload type, exposure, data classification, regions, availability target, and whatever else the organization needs to make the request unambiguous. From there, the agent translates that intent into our approved primitives: the right template, the right modules, the right pipeline, the right access requests. Translating a clear specification into approved platform primitives is implementation, and implementation is exactly what agents are getting good at. I argued in [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) that code is becoming the regeneratable output of a clear, versioned specification. [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) made the case that the platform now serves both the developer and the developer's agent. The intent interface is where those ideas meet. The developer expresses the specification. The agent creates the implementation. The platform verifies that the result satisfies its constraints. The golden path does not disappear in this model. It stops being the primary interface and becomes the compiler target. Templates, modules, pipelines, policies, and controls are still there. The developer just no longer needs to learn their names before asking the platform for the right outcome. ![Comparison diagram: the golden path as a gray stack of template, fields, modules, pipeline, and permissions, next to an intent interface where one stated intent compiles through platform capabilities into an approved service](/images/blog/2026/08/intent-path-before-after.png) ## The platform still owns the road Nothing about this loosens control. The platform still owns the standards, the controls, the architecture, the pipelines, and the verification. The gate does not care whether a human or an agent produced the configuration. It checks the result against the constraints and passes or fails it. [Trust the gate, not the actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/). AI changes the interface. The ownership stays exactly where it was. If anything, the intent interface strengthens the platform's hand, because intent that compiles through approved primitives cannot quietly wander off the road the way a hand-edited Terraform file can. ## What a platform team does on Monday Four moves make this concrete. First, publish intent schemas. Decide what a developer must state and what the platform will derive. That line is the most consequential design decision on this list. Everything on the left is cognitive load you have chosen to keep. Everything on the right is a policy you now own and have to defend. | The developer states | The platform derives | | --- | --- | | Workload type | Runtime, base image, service template | | Exposure | Ingress, network placement, edge rules | | Data classification | Encryption, key management, retention | | Availability target | Regions, replication, backup policy | | Team and cost center | Tagging, budget guardrails, chargeback | Draw that line too far left and you have rebuilt the 20-field form with better manners. Draw it too far right and you are quietly deciding things the developer should decide on purpose, like what a second region costs. An intent schema is a contract, and it deserves the same versioning discipline as any API you ship. Natural language can help populate it. The schema is what the platform should trust. Second, make your constraints machine-readable. An agent can only compile intent into compliant primitives if the compliance rules exist somewhere better than a wiki page and a reviewer's memory. This is the argument from [Context Is a Platform Capability Now](https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/): trusted context is canonical, versioned, fresh, attributable, accessible, and safe, and providing it is platform work. Third, keep the compiled result inspectable. Intent in, primitives out, and a diff a human can read. That diff is also your new review artifact. When one stated intent produces 400 lines of Terraform, nobody is really reviewing the Terraform, and pretending otherwise is how teams start approving changes by scroll speed. Review the intent, then review the delta between what the schema would have produced by default and what this request produced instead. The exceptions are where the judgment lives. The moment intent compiles into something nobody can inspect, you have traded a syllabus for a black box, and the black box is worse. Fourth, instrument what fails to compile. Every intent your platform cannot satisfy is a gap in the schema, a gap in the capability catalog, or a policy nobody can defend anymore. All three are worth knowing about. Log the requests that fall back to a human, count them by cause, and work the list in priority order. A schema that cannot express what developers need is a syllabus with extra steps. ## The objection worth taking seriously The pushback I expect: if developers stop learning the platform, they stop understanding their systems. I take the concern seriously, and I think it aims at the wrong target. Knowing which of our nine templates maps to which workload was never engineering. Choosing the right data classification, understanding the failure modes of a two-region deployment, and deciding what 99.95% costs: that is engineering. The intent interface puts those decisions in front of the developer instead of burying them under field 12 of 20. There is a harder question hiding behind this one. When intent compiles to implementation, who understands the running system at 3 a.m. two years from now? That question deserves its own essay, and it gets one soon. The golden path asked developers to learn the road before they could use it. An intent interface asks them where they are going and picks the road. Our job is making sure every road it can pick is one we already paved. --- ## Context Is a Platform Capability Now - **Published:** 2026-08-15 - **Tags:** platform-engineering, agentic-sdlc, ai-strategy - **URL:** https://vinny.dev/blog/2026-08-15-context-is-a-platform-capability-now/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* Watch a developer start an agent session on real enterprise work and you will see a ritual. Before the first useful prompt, they gather. They paste the deployment standard, link the runbook, and explain what the criticality tiers mean. Then they correct the agent's first confident guess about a naming convention the team retired two years ago. Tomorrow they will do it all again, because the agent will not remember. We have quietly decided that this gathering is the developer's job. Every guide to working with AI repeats some version of the same advice: give the model good context. So developers hunt for it, one session at a time, across systems that were never designed to answer an agent's questions. I think that framing is backwards, and I think fixing it is platform work. In [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/), I argued that internal platforms now serve two personas: the developer and the developer's agent. Near the end, I wrote that context is becoming part of the platform. I called it one of the most important developer experience problems of the next few years. That idea got four paragraphs. It deserves an essay, so here is the longer version. ## The gathering is the tax Agents can remember more than they used to. What they cannot reliably accumulate on their own is organizational truth. A new engineer pays the onboarding cost once, then amortizes it over years of context, hallway conversations, and scar tissue. An agent may retain instructions, memory, or project state. None of those automatically tell it which standard is authoritative, which exception still applies, or which decision was reversed six months ago. Whatever it needs to know about your organization still has to come from somewhere. Now multiply that across hundreds of engineers. People rediscover the same standards, fork the same repo, re-paste the same runbooks, and retype the same corrections, day after day. Quality varies too. Your strongest engineers assemble excellent context and get excellent output. Everyone else gets whatever the search index returns first, which is often the wiki page from three years ago that still outranks the current standard. Here is the part that should bother platform owners: the tax grows with adoption. The better your AI rollout goes, the more hand-assembly your organization performs. Success makes the problem bigger. Teams are already voting on the solution with their repositories. Every `CLAUDE.md`, every `AGENTS.md`, every set of AI rules is a developer hand-building a context layer, one repo at a time. When many teams independently build the same scaffolding, a platform capability is sitting there waiting to be claimed. We have watched this movie before with build scripts, deploy tooling, and observability config. Context is next. ## The platform-owner question Here is the question I keep returning to: who makes the organization's knowledge usable by the agent? At most companies, the honest answer today is each developer, per session, which is another way of saying nobody. Consider what an agent needs to do real work inside an enterprise. It needs service ownership and dependency information. It needs the approved architectural patterns and the deployment requirements that go with each application tier. It needs API definitions, security classifications, observability conventions, naming standards, environment details, coding conventions, runbooks, and enough operational history to know which integration test has always been flaky. I listed where all of that lives in the last essay: Git, the developer portal, Confluence, tickets, Slack, and people's heads. The scatter is old news. What changes with agents is the price of the scatter, because an agent cannot walk over to your desk and ask. The platform question is not how developers can gather all of this faster. The platform question is why they are gathering it at all. Platform teams exist to take work that every delivery team would otherwise absorb and turn it into a shared capability. Context assembly now fits that description exactly. Readers of [the book](https://vinny.dev/book/) will recognize the instinct: this is the Context Spine argument, operating at organizational scale. ## Trusted is the load-bearing word Enterprises are drowning in context. The scarce resource is trusted context. The tempting version of this is a crawler, a vector database, and a chat window. Point retrieval at everything the company has ever written and demo it on a Friday. I understand the appeal. It solves discovery, but discovery is not the same as authority. Retrieval without an authority model is just ranking. A retrieval system can find the deprecated standard, the abandoned experiment, and the current requirement side by side. It can even rank them intelligently. What it cannot know on its own is which answer the organization has chosen to stand behind. Feed an agent contradictory guidance and it produces confident contradiction, faster than any human could. So the platform job is curation, and trusted has to mean something specific. I would hold a context layer to six properties. Canonical means the organization has picked one answer per question, on purpose. If five deployment patterns exist in the wild, the layer knows which three are supported and which two are archaeology. Versioned means standards carry history, so an agent knows which rules applied when a service shipped. Fresh means staleness gets measured like uptime instead of discovered during an incident. Attributable means every answer traces to a source and an owner, so a wrong answer becomes a bug report with a recipient. Accessible means machine-readable and queryable through a real interface, so agents ask instead of scraping prose and hoping. Safe means context inherits the access controls of the systems it describes. Security classifications do not stop applying because retrieval got convenient. Read the list again and notice its shape. Those are the properties we already demand from any production API, and that is the point. Context deserves the same engineering discipline we apply to the systems it describes. ![The six properties of trusted context: canonical, versioned, fresh, attributable, accessible, and safe. The properties we already demand from any production API.](/images/blog/2026/08/trusted-context-six-properties.png) ## Context gets an owner and an interface Treating context as a platform capability changes three things. First, context gets an interface. Agents query a service catalog, a standards endpoint, or a policy engine instead of scraping documents. Model Context Protocol servers are one plumbing option, and plain versioned APIs work fine too. The plumbing will change. The authority model behind it is the part only your organization can supply, and the part that lasts. Second, context gets owners. Every canonical answer has a name attached, drift becomes that owner's bug, and deprecation becomes a real operation. Half of this job is demotion and deletion. The old pattern gets marked superseded, with a pointer to its replacement, instead of lingering at the top of search results for another three years. That also lets context survive the people who originally knew it, which is one of the quiet jobs of any good platform. Architects change roles, subject-matter experts leave, and teams reorganize. The best platforms turn what those people knew into inherited capability. The right path stops depending on who happens to remember why a decision was made. Third, context gets enforcement. I wrote in the last essay that standards are more valuable when they live in systems than when they live in documents. The same holds here. Ownership metadata required at deploy time is context with teeth, and so is a policy engine that rejects a noncompliant manifest and names the fix. A wiki page is a suggestion. *Cloud platforms standardized infrastructure. The next platform layer standardizes context.* ![Context gathered by hand, where every session repeats the gathering ritual, compared with trusted context provided by the platform, where the developer and the agent are onboarded once.](/images/blog/2026/08/context-gathering-tax.png) ## The obvious objections *This is documentation with extra steps.* I would flip that: documentation is a context layer with no steps. A document describes, while a context layer answers and enforces. Nobody gets paged when a wiki page goes stale, and no pipeline fails when a README contradicts the automation. The distance between a page about service ownership and a deploy gate that requires ownership metadata is the distance between advice and infrastructure. *Context windows keep growing. Soon the agent can read everything.* A bigger window changes how much you can feed the model. It does nothing about whether what you feed it is true, current, or something the requester is allowed to see. Pour a million tokens of contradictory guidance into a larger window and you get the same contradiction at greater length. Abundance makes curation more valuable, the same way abundant generation makes constraints more valuable. *The vendors will solve this.* Vendors will ship better protocols and better retrieval, and I will happily use both. What no vendor will ever ship is the knowledge that your organization supports exactly three deployment patterns, or what `Tier F` means at your company. Authority does not come in the box. ## Where to start Start embarrassingly small. Write down the 10 questions your agents and your new engineers ask most often. The two lists will overlap more than is comfortable, which is its own lesson: agent readiness and developer experience keep turning out to be the same work. For each question, name an owner and pick the single canonical source. Make that source queryable through whatever interface your agents already use, then demote the copies. Measure freshness the way you measure availability. When an agent pulls a wrong answer from your own context, file it as a platform defect, because that is what it is. One concrete first move: generate the shared sections of your teams' agent instruction files from the platform itself. Teams increasingly hand-write organizational context into `CLAUDE.md`, `AGENTS.md`, and similar files, then rely on someone to keep it current. Ownership, tier, approved patterns, and deploy paths are often facts the platform already knows. Let the platform write that part of the file, let teams keep the local knowledge, and freshness stops depending on anyone's memory. We spent the last decade building platforms so developers would stop hand-assembling infrastructure. The gathering ritual at the top of this essay is the same problem, one layer up. Organizations that treat trusted context as a platform capability will onboard their agents once, through the platform. Everyone else will keep running onboarding by hand, one session at a time. ## Related reading - [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/) - [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [The Agentic SDLC: Uniting the AI Tool Sprawl](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) --- ## Your Platform Has a New User: The Agent - **Published:** 2026-08-13 - **Tags:** platform-engineering, agentic-sdlc, ai-strategy, engineering-leadership - **URL:** https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/ *This essay anchors an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system.* For years, platform engineering has worked from a simple premise: the developer is the customer. Build the paved road, reduce cognitive load, and automate the undifferentiated work. Make the secure path the easy path, so developers spend more time building software and less time learning how the machinery underneath it works. I still believe all of that. What is changing is the customer. The developer increasingly arrives with an agent sitting beside them. Claude Code, Codex, GitHub Copilot, Cursor, and whatever comes next are becoming part of the development environment. Developers are asking agents to understand codebases, diagnose failures, modify applications, generate infrastructure, create tests, review pull requests, and eventually perform larger chunks of the software delivery life cycle. That creates an interesting question for those of us who own developer platforms. What happens when the consumer of your platform is no longer just a human? I think the answer has much bigger implications than adding a chatbot to the developer portal. ## Your platform now has two personas Most internal platforms are designed around a human interaction model. A developer reads the documentation, knows which repository template to use, understands how the pipeline works, and recognizes an internal acronym in an error message. They know that one configuration lives in a wiki page and another is buried three levels deep in a service catalog. When they get stuck, they ask someone. In a mature platform organization, we try to reduce how often that happens. But an enormous amount of organizational context still lives in documentation, conventions, conversations, and tribal knowledge. Humans are surprisingly good at working around that mess. Agents are much less capable of working around that ambiguity. An agent cannot reliably infer that the architecture standard documented three years ago on your wiki is obsolete but still ranks first in search. It does not know that the deployment example in a README is technically valid but discouraged. It cannot walk over to someone on the platform team and ask what `Tier F` means. It knows what we make available to it. That means the internal developer platform increasingly has two personas: the developer and the developer's agent. And that gives platform owners a new design constraint. ![One developer platform serving two consumers, the developer and the developer's agent, providing capabilities, context, constraints, and verification](/images/blog/2026/08/platform-two-users.png) ## The agent-readiness test Here is a simple test I have started thinking about: > If an AI coding agent joined your company tomorrow, could it figure out how to deploy an application correctly without asking someone on the platform team? The bar is higher than producing some plausible YAML. Could the agent discover the approved path, pick the right application pattern, and understand which controls apply? Could it interpret a failed pipeline? Could it find the authoritative documentation instead of a three-year-old example, and could it tell the difference between what is technically possible and what the organization wants developers to do? That is a much harder test, and I suspect most of our platforms would fail it. The failure would say more about the platform than about the AI. If the correct path depends on tribal knowledge, humans struggle with it too. If the documentation contradicts the automation, humans eventually notice too. If five teams implement the same pattern five different ways, developers pay that cognitive tax today. Agents simply make those inconsistencies easier to see. In that sense, agent readiness may become a useful new measure of platform maturity. ![The agent-readiness test as a checklist: discover the approved path, pick the right application pattern, understand which controls apply, interpret a failed pipeline, find the authoritative documentation, and distinguish possible from supported](/images/blog/2026/08/agent-readiness-test.png) ## Machine-readable beats human-readable Platform teams have invested heavily in developer documentation, and rightly so. But an agentic development environment requires us to think beyond documentation pages and ask whether the platform itself is understandable. That means APIs with predictable behavior, schemas that describe themselves, service metadata with clear ownership, versioned standards, structured errors, and discoverable capabilities. The more important something is, the less it should depend on an agent scraping prose and hoping it interpreted the paragraph correctly. This extends a principle I already believe strongly: standards are more valuable when they live in systems than when they live in documents. If every production service requires ownership metadata, enforce it. If every internet-facing application needs a particular security control, encode it. If only three deployment patterns are supported, make those three discoverable through the platform. And if a workload needs additional resilience because of its criticality tier, the platform should know how to translate that tier into infrastructure. Humans benefit from this too, and that is one of the things I find most interesting about designing platforms for agents. Most of the improvements that make the platform easier for an agent also make it better for developers. Clear APIs beat tribal knowledge, deterministic automation beats wiki instructions, and useful error messages beat numeric failure codes. Canonical examples beat 40 slightly different Git repositories. *The agent is not creating the need for good developer experience. It is increasing the cost of bad developer experience.* ## Error messages become an interface Error handling is a small example with outsized implications. Developers encounter platforms through failure as much as through success: a build fails, a permission is denied, a deployment violates a policy, a workload refuses to start. Historically, platform teams have written those errors for themselves. `AccessDeniedException`. `Policy check failed`. `Exit code 1`. Technically accurate and practically useless. A developer translates the error through experience, documentation, Slack history, or a support ticket. Agents will try to do the same thing. The difference is that agents give us a compelling reason to make the error itself useful. Instead of: > Deployment rejected: policy violation. Imagine: > Deployment rejected because this service is classified as customer-facing and requires multi-AZ deployment. Set `availability: multi-az` in `service.yaml`. See the approved customer-facing service pattern. That is a better platform interface, not merely better documentation. The developer understands the failure, the agent understands the failure, and both have enough information to attempt a safe correction. The best support ticket may be the one the platform never requires. ## Give agents capabilities, not just context There is another side to this. It is not enough for agents to understand the platform; eventually they need safe ways to act through it. I do not want an autonomous coding agent reverse-engineering how to create an AWS account, constructing raw IAM policies, inventing Terraform, and calling infrastructure APIs directly. I want the agent consuming the same opinionated capabilities we want developers consuming: create a service, request a database, deploy a workload, add a secret, expose an API, run a security scan, roll back a deployment. Those capabilities should already encode our architecture, security, reliability, financial, and operational expectations. The agent supplies intent, and the platform supplies constraints. The combination produces an approved action. ![Flow from developer intent through the agent, combined with platform capabilities and organizational constraints, passing gates and verification to produce an approved action](/images/blog/2026/08/intent-constraints-approved-action.png) This connects closely to an argument I made in [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/). As execution gets cheaper, describing what we want becomes increasingly important. The developer should be able to say: > I need a TypeScript API that stores confidential customer information, is externally accessible, and needs 99.9% availability. The agent can help translate that intent. But the agent should not invent what 99.9% availability means inside my organization. The platform should know that. It should know which deployment pattern is approved, which network controls apply, what observability is required, how backups work, which regions are allowed, and which security controls are mandatory. AI changes the interface. It should not weaken the architecture. ## The paved road becomes more important, not less There is a temptation to assume that AI makes platform abstraction less important. If an agent can write Terraform, maybe everyone can just write Terraform. If it understands Kubernetes, maybe developers no longer need an abstraction over Kubernetes. If it can debug AWS, maybe the opinionated cloud platform has run its course. I think the opposite is true. Generating infrastructure becomes easier. Generating correct infrastructure for your organization remains difficult. An agent can produce hundreds of technically valid solutions. None of that tells it which solution fits your security model, cost expectations, architecture strategy, operational capabilities, regulatory requirements, or support model. Abundant generation makes constraints more valuable. The paved road therefore becomes more important in an agentic environment, not less. It becomes the boundary between what an agent *can* create and what the organization is prepared to operate. One of the central ideas in my writing about the [agentic SDLC](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) is that we [trust the gate, not the actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/). We do not govern this environment by trusting every actor to make the correct decision. We govern the system through gates, standards, feedback loops, and verification, and the platform is where many of those controls should live. ## Context becomes part of the platform Agents need to understand more than infrastructure APIs. They need architecture standards, application classifications, service ownership, approved libraries, dependency information, security requirements, deployment patterns, operational history, and current documentation. In other words, they need context, and I think platform teams will increasingly inherit the job of providing it. Today, that knowledge is scattered everywhere. Some of it lives in Git, some in a developer portal, some in Confluence, some in tickets, some in Slack, and a surprising amount in people's heads. We have spent years building platforms that standardize infrastructure. I suspect the next phase of platform engineering will include standardizing how organizational context is exposed to developers and agents. That does not mean dumping every document into a vector database and calling it done. Context needs ownership, freshness, provenance, and access controls. It needs to distinguish authoritative guidance from someone's experiment in a repository three years ago. That starts to make context itself a platform capability, and I think it will become one of the most important developer experience problems of the next few years. ## Do not build PlatformGPT The most obvious response to all of this is probably the least interesting one. Build a chat window, connect it to some documentation, and call it PlatformGPT. There will absolutely be useful conversational interfaces to internal platforms, and I expect us to build some. But I do not think that is the end state. The best AI developer experience may become almost invisible. The failed pipeline explains itself, the CLI suggests the compliant fix, and the service catalog already understands the application. The developer expresses intent, the platform translates that intent into the correct capabilities, and the agent discovers what it needs without reverse-engineering the organization. Developers should not have to stop what they are doing, navigate somewhere else, and ask an AI how the platform works. The platform should increasingly explain itself. That is a much higher bar, and a much more interesting one. ## A platform product question None of this changes the core job of platform engineering. Platform teams exist to take complexity that every development team would otherwise absorb and turn it into reusable capabilities. AI gives us another powerful way to do that. It also creates a new consumer with very different strengths and weaknesses. Agents are fast, persistent, and able to consume enormous amounts of information, and they will retry a solution as many times as it takes. They are also perfectly capable of confidently taking the wrong path if the platform makes that path easier to discover than the right one. So the question for platform owners is no longer just whether the platform is easy for a developer to use. We should start asking whether the right thing is easy for both the developer and the developer's agent to discover, understand, and execute. Cleaner interfaces, better metadata, explicit standards, useful failures, trusted context, and strong verification are not new platform engineering ideas. AI raises the stakes on all of them. We spent the last decade building platforms for developers. The next generation of those platforms will still serve developers, but developers will increasingly bring someone with them. Your platform has a new user. It is probably time we started designing for it. ## Related reading - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) - [The Agentic SDLC: Uniting the AI Tool Sprawl](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) - [Complexity Is Inevitable. Drag Is Optional.](https://vinny.dev/blog/2026-06-22-turning-complexity-into-leverage/) --- ## The Accidental Podcast - **Published:** 2026-08-11 - **Tags:** genai, productivity, side-projects - **URL:** https://vinny.dev/blog/2026-08-11-the-accidental-podcast/ I didn't set out to start a podcast. Think of it as a personal blog nobody asked for, except now you can't even skim it. The story starts with [NotebookLM, which Google renamed Gemini Notebook in July 2026](https://blog.google/innovation-and-ai/products/gemini-notebook/notebooklm-gemini-notebook/). I will use the old name here, since that is what it was called while all of this happened. NotebookLM is a research tool built around source grounding. Give it documents, websites, videos, recordings, or other material, and it can synthesize those sources into summaries, reports, and audio and video narratives. For me, one feature carries the whole product. Audio Overview turns your sources into a Deep Dive discussion between two AI hosts. The hosts sound genuinely delighted by whatever you uploaded. Give them a tax document and they will find the drama in it. My blog posts kept getting longer. ["Where the Saved Hour Goes"](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/) ran 2,600 words, which is a lot to ask of anyone's lunch break. So I started attaching an Audio Overview to new essays, usually about 20 minutes of conversation for the commute, the gym, or the dog walk. The hosts have never once complained about my word count, which puts them ahead of nearly everyone I know. Then I did what I always do with a manual step I have repeated twice. I automated it. Every post I publish now kicks off a pipeline. Publishing the Markdown file is the trigger. From there, the workflow submits the essay to NotebookLM, generates the Audio Overview, downloads the finished audio, and attaches the player to the post. Once I publish the essay, I do not have to remember that the audio version exists. ![Terminal output of the publish pipeline: submit the essay to NotebookLM, generate the Audio Overview, download the episode audio, and attach the player to the post.](/images/blog/2026/08/accidental-podcast-pipeline.png) There is nothing especially profound about the plumbing. The interesting part is what the plumbing removed. Automating the step did more than cut the work of producing an audio version; it removed the decision to produce one. That means I built a fully automated podcast production pipeline before I ever decided to have a podcast. I choose to call this foresight. Last week I was reviewing the audio for a new post and opened the folder where the files land. It held 22 episodes going back to April. Same format, same two hosts, no missed deadlines. Somewhere along the way I had accumulated a back catalog. The show was already running. It had just been too polite to announce itself. ![Terminal listing of the audio folder: the five most recent episode files, a count of 22, and the realization that this is a podcast.](/images/blog/2026/08/accidental-podcast-backlog.png) So I am making it official. I named the show Never the Stack. The name comes from the argument that runs through [the book](https://vinny.dev/book/) and much of my writing: the bottleneck in software has never been the stack. The 22-episode archive becomes the launch catalog, and a new episode will arrive automatically whenever I publish. The hosts are AI, the production is a pipeline, and the author mostly stays out of the way, which may be exactly why it works. > I never decided to start a podcast. I lowered the cost of making one until it started itself. That is the part I find more interesting than the podcast itself. We tend to think about automation as a way to do the same work faster. Sometimes that is all it is. But when the marginal cost of creating something falls far enough, the effect changes. Work that once required a deliberate decision becomes cheap enough to happen by default. Artifacts stop waiting for permission and start accumulating. That is the pattern I keep writing about, most recently in ["Where the Saved Hour Goes"](https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/). The saved hour does not simply sit there waiting to be reclaimed. Lower the cost of an activity and we often spend the new capacity before we even notice it exists. In this case, my saved hour went into a pipeline, and the pipeline quietly turned into a show. Never the Stack lives at [vinny.dev/podcast](https://vinny.dev/podcast), with links for Apple Podcasts, Spotify, YouTube, and Amazon Music, plus a plain RSS feed for the purists. If you have ever wanted my writing read to you by two relentlessly upbeat AI hosts, this is your moment. If you have never wanted that, I understand completely. The text version remains fully skimmable. --- ## Where the Saved Hour Goes - **Published:** 2026-08-09 - **Tags:** ai-economics, engineering-leadership, agentic-sdlc, productivity - **URL:** https://vinny.dev/blog/2026-08-09-where-the-saved-hour-goes/ The late [Bill Coleman](https://computerhistory.org/profile/bill-coleman/), co-founder and first CEO of BEA Systems, once told me a story I have not been able to shake. We were a large WebLogic customer, which is how I ended up with an afternoon of his time. Coleman had seen the spreadsheet revolution from the inside. Before BEA, he led product development at VisiCorp during the development of [VisiCalc, the first spreadsheet for personal computers](https://www.computerhistory.org/revolution/personal-computers/17/305). He told me that before spreadsheets, finalizing the quarterly earnings report at a public company could take six weeks. Every change meant recalculating a wall of numbers by hand, so the team spent most of the reporting cycle doing arithmetic. Then VisiCalc and its descendants automated most of the manual recalculation. The reporting cycle should have collapsed to days. It still took six weeks. The time did not disappear. It moved. The team ran more scenarios, stress-tested more assumptions, and asked better questions of the same numbers. Spreadsheets changed everything about the work and nothing about the calendar. AI is running the same experiment on software development right now. The pitch for every AI tool is saved hours, and after a couple of years of daily agentic coding, I know the hours can be real. They do not appear on every task or for every engineer, but they show up often enough to matter. The question I care about is what happens to them. When AI hands you back an hour, where does it go? The question is no longer only whether AI can create capacity. The bottleneck is whether leaders can express what that capacity is for, then build a system that keeps it from disappearing. ## The four destinations Across 150 years of productivity history, I keep seeing the saved hour land in four places. The categories overlap, and most organizations will fund all four. The leadership question is not whether the dividend gets spent. It is whether anyone chooses the mix. ![Four destinations of the saved hour: it buys volume (Jevons, 1865), it raises the bar (Cowan, 1983), it becomes new work (Bessen, 2015), it comes back to you (Keynes, 1930).](/images/blog/2026/08/where-the-saved-hour-goes-destinations.png) It buys volume. William Stanley Jevons observed in [*The Coal Question*](https://energyhistory.yale.edu/w-stanley-jevons-the-coal-question-1865/) in 1865 that more efficient steam engines did not reduce Britain's coal consumption. They made steam power cheaper and expanded its use. Efficiency lowers the cost of an activity, and demand often grows to consume the savings. Spreadsheets ran the same play on analysis. [Planet Money reported](https://www.npr.org/transcripts/389027988) that between 1980 and 2015, the number of bookkeeping and accounting clerk jobs in the United States fell by roughly 400,000 while accountant jobs grew by about 600,000. Analysis got cheaper, and clients who could suddenly afford the what-if game bought far more of it. Steven Levy saw the deeper shift in his 1984 essay, ["A Spreadsheet Way of Knowledge"](https://www.wired.com/2014/10/a-spreadsheet-way-of-knowledge/). The spreadsheet did not merely accelerate calculation. It made modeling a way of working. Code is the cheap resource now. When code gets cheaper, we attempt more software, more variations, more automation, and more work that never cleared the old business case. It raises the bar. Ruth Schwartz Cowan's *More Work for Mother* traced how household technologies did not simply return leisure. Work moved, expectations changed, and standards rose to absorb part of the savings. Software inflates the definition of done the same way, with more tests, more polish, stronger documentation, and more edge cases handled inside the same sprint. The six-week reporting cycle lives here too. The deadline stays fixed while the expected quality climbs. It becomes new work. The economist [James Bessen](https://www.imf.org/external/pubs/ft/fandd/2015/03/bessen.htm) studied what ATMs did to bank tellers. For several decades, tellers per branch fell, cheaper branches multiplied, and total teller employment grew while the job shifted from counting cash toward customer relationships. The machine removed one task and helped create demand for another. AI's version of the new work is verification. Faster generation can create a larger review queue unless evaluation capacity grows with it. Prompting, waiting, reading, testing, correcting, and coordinating do not vanish just because typing gets fast. I made this argument in the book and in [*The AI Operating Ledger*](https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/): evaluation capacity is a real constraint that deserves its own budget line. We saved time writing and spent it reading. It comes back to you. This is the destination John Maynard Keynes promised in 1930. In ["Economic Possibilities for Our Grandchildren"](https://www.hetwebsite.net/het/texts/keynes/keynes1930grandchildren.htm), he imagined that productivity could eventually support a 15-hour workweek. The productivity arrived, but the leisure did not arrive in anything like the form he expected, because we took much of a century's gains as output and consumption instead of time. There are signs that workers would like to claim this destination. A [Zoom-sponsored Morning Consult survey](https://news.zoom.com/take-back-lunch/) found that 76% of AI users reported saving at least 30 minutes a day, and 73% said they would use saved time for a dedicated lunch break. That measures intention, not where the time landed. Still, I hope it holds. History is not on its side. ## The law that decides for you If nobody chooses among those four destinations, the choice gets made anyway. C. Northcote Parkinson named the mechanism in 1955: "Work expands so as to fill the time available for its completion." He wrote it as satire about the British Civil Service, and it reads today like a systems requirement. Oliver Burkeman sharpened the same point in *Four Thousand Weeks* with what he calls the efficiency trap. Getting faster at email does not empty your inbox. It teaches the world that you reply quickly, so the world sends you more email. Because the demands on our attention are effectively infinite, efficiency alone cannot produce free time. The saved hour gets reabsorbed before anyone notices it existed. The reabsorption is already visible. In a before-and-after analysis of 10,584 AI users, [ActivTrak](https://www.activtrak.com/resources/state-of-the-workplace/) found that time spent across every measured work category increased after adoption. Email rose 104%, chat and messaging rose 145%, business-management-tool use rose 94%, and daily focus time declined 9%. The study is observational, so it does not prove that AI caused every change. It does show that adoption did not automatically produce visible slack. An [eight-month UC Berkeley Haas ethnography](https://vcresearch.berkeley.edu/news/does-ai-actually-free-workers-time) at one 200-person technology company found a similar pattern. Through workplace observation and more than 40 interviews, researchers saw employees broaden the scope of their jobs, insert AI work into moments that used to be pauses, and keep multiple workstreams or agents alive at once. The setting was narrow, but the behavior is recognizable. The tool made more work feel possible, so more work became normal. David Brooks gives the allocation problem a useful name in ["The People Who Will Thrive in the AI Age"](https://www.theatlantic.com/ideas/2026/06/ai-open-ai-anthropic/687689/): "When intelligence is plentiful, volition is valuable." The tools create options. Volition, or your power to choose, decide, and take action, decides which options deserve the hour. None of this makes reinvestment the enemy. The spreadsheet story is the happy version, where the same six weeks bought better answers and the deeper analysis was worth every reinvested minute. The trap is unexamined reinvestment, where Jevons buys volume, Parkinson fills the calendar, and the bar drifts upward without anyone deciding it should. Cal Newport's *Slow Productivity* makes the case for one deliberate allocation, doing fewer things at a natural pace with an obsession over quality. Brooks emphasizes another, spending the dividend on effortful work that builds your own capability rather than using AI to avoid thinking. They emphasize different uses of the hour, and they agree it will not go anywhere good by default. ## My own audit I ran this experiment on myself before I had a name for it. AI coding tools have been part of my daily work for several years now, and the time dividend is real. Mine went into more shipped apps, more personal projects completed, and new apps built because the hours got cheap. It went into a book I might not otherwise have finished. It also went into deeper work on the job I already had, though not fewer hours. What the dividend did not buy was a hammock at the beach for me. That is Jevons operating on a small scale, and I do not regret those choices. I am also not sure I made all of them as choices. The demand was sitting right there, the hour got cheap, and the hour disappeared into the demand. Reflection never got a line item. I wrote recently that [the productivity ledger misses what used to happen inside the saved hour](https://vinny.dev/blog/2026-08-03-dont-automate-the-apprenticeship/), including the practice and correction that produce judgment. This essay asks the next question: who gets to allocate the hour itself? ## The dividend is net, not gross Before allocation comes accounting. The hour an agent removes from typing is a gross dividend. Prompting, waiting that blocks other work, review, correction, rework, and coordination are claims against it. Only what remains is allocatable capacity. A team that celebrates gross savings while hiding review debt is counting the same hour twice. That distinction helps reconcile some of the conflicting evidence on AI productivity. In [METR's early-2025 randomized trial](https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/), 16 experienced open-source developers completed 246 real tasks in repositories they knew well. With AI available, they took 19% longer, even though they believed AI had made them 20% faster. The study does not show that AI slows most developers or most software work. It shows how easily interaction and verification overhead can disappear from our perception of time. METR's [late-2025 follow-up](https://metr.org/blog/2026-02-24-uplift-update/) pointed toward speedup in its raw estimates, but the researchers concluded that selection effects and concurrent agent use made the size of that speedup unreliable. Developers who valued AI most were increasingly unwilling to join a study that might require them to work without it. Agentic work also made human time harder to count because people could switch tasks while an agent ran. That reads to me as a warning about accounting by feeling, not a verdict on the tools. The fair objection is that the dividend may be too small or uncertain to manage. In a [Federal Reserve Bank of St. Louis survey](https://www.stlouisfed.org/on-the-economy/2025/feb/impact-generative-ai-work-productivity), generative AI users reported saving an average of 5.4% of their work hours, about 2.2 hours in a 40-hour week. Self-reported savings are not the same as observed savings, but two hours is enough to disappear and enough to matter. A simple time-dividend ledger makes the claims visible: **Net dividend = gross time removed - prompting - blocked waiting - review - rework - coordination.** ![Illustrative waterfall chart: a 10-hour gross time dividend minus prompting, blocked waiting, review, rework, and coordination leaves a 6-hour net dividend.](/images/blog/2026/08/where-the-saved-hour-goes-waterfall.png) | Work item | Gross time removed | AI overhead | Net dividend | Intended destination | Actual destination | | --- | ---: | ---: | ---: | --- | --- | | Illustrative workflow | 10 hours | 4 hours | 6 hours | Modernization | Additional scope | The arithmetic is intentionally boring, and that is the point. Measure the baseline, count the full cost of using AI, then name what happened to the difference. If the dividend turns out to be small, the discipline still holds. Measure first, then allocate. ## Who gets to choose The four destinations answer where the hour goes. They do not answer who gets to choose. When an organization captures every saved minute as more output, that is not a neutral efficiency gain. It is a decision about how productivity gains are shared. Some of the dividend may rightly fund customer value, quality, modernization, evaluation, or learning. Some may need to return to the people creating it as recovery, slack, or a real lunch break. The bargain becomes honest only when the allocation is explicit. This matters because each destination benefits a different constituency. Volume may benefit customers and shareholders. Higher standards may reduce operational risk. New work may build organizational capability. Returned time may improve sustainability for the people doing the work. Leaders rarely get to choose only one, but they should be able to explain the mix and the trade-offs. The worst answer is to call the entire dividend "productivity," absorb it into higher expectations, and pretend no allocation decision occurred. ## Spend it on purpose At work I lead an engineering organization of more than 250 people, and I have started treating the time dividend the way I treat money. I have written before about the AI operating ledger, the cost side and the payment side of buying intelligence. This is the time side of the same ledger, and it deserves the same discipline. Engineering leaders will chase a 4% cloud overage across three vendor calls and never ask where last quarter's saved hours went. Volition is the scarce input now, and an allocation is volition written down, a specification for capacity before the calendar writes one for you. An unallocated dividend gets spent anyway, with Jevons as your default portfolio manager and Parkinson running the calendar. If you want the saved hours to buy something specific, name it. Hold delivery flat for a quarter and bank the surplus against the modernization or refactoring backlog. Fund evaluation capacity as its own line instead of taxing everyone's afternoons with review debt. Reserve part of the dividend for apprenticeship and deliberate practice so short-term speed does not consume long-term judgment. Protect slack that looks unproductive on a status report, because thinking often does. If what your team needs is the Keynes destination, actual recovered time, say that out loud. Nobody claims it by accident. Then inspect the result. Did the time go where you intended? Did quality improve, did the backlog shrink, did capability grow, or did every estimate quietly tighten until the organization was working at the old pace with a higher output expectation? The point is not to defend leisure from productivity or quality from volume. The point is to make the trade visible enough that a leader can own it. So here is the assignment I am giving myself, and I would love company. For one week, every time an AI tool saves real time, write down the gross saving, the overhead required to earn it, and where the net dividend lands: volume, standards, new work, or returned time. Then compare the entries with what you would have chosen on purpose. My guess is that the reporting cycle will still take six weeks. This time I want that to be a decision. ## Related reading - [The AI Operating Ledger](https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/) - [Don't Automate the Apprenticeship Out of Engineering](https://vinny.dev/blog/2026-08-03-dont-automate-the-apprenticeship/) - [The Modernization Backlog Just Got Repriced](https://vinny.dev/blog/2026-08-01-modernization-backlog-repriced/) - [The Bottleneck Is Never the Stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/) ## Research notes - W. Stanley Jevons, [*The Coal Question*](https://energyhistory.yale.edu/w-stanley-jevons-the-coal-question-1865/) (1865) - C. Northcote Parkinson, "Parkinson's Law," *The Economist* (1955) - John Maynard Keynes, ["Economic Possibilities for Our Grandchildren"](https://www.hetwebsite.net/het/texts/keynes/keynes1930grandchildren.htm) (1930) - Ruth Schwartz Cowan, *More Work for Mother* (1983) - James Bessen, ["Toil and Technology"](https://www.imf.org/external/pubs/ft/fandd/2015/03/bessen.htm) (2015) - Oliver Burkeman, *Four Thousand Weeks* (2021) - Cal Newport, *Slow Productivity* (2024) - Steven Levy, ["A Spreadsheet Way of Knowledge"](https://www.wired.com/2014/10/a-spreadsheet-way-of-knowledge/) (1984) - David Brooks, ["The People Who Will Thrive in the AI Age"](https://www.theatlantic.com/ideas/2026/06/ai-open-ai-anthropic/687689/) (2026) - ActivTrak, ["2026 State of the Workplace"](https://www.activtrak.com/resources/state-of-the-workplace/) (2026) - UC Berkeley Haas, ["Does AI Actually Free Up Workers' Time?"](https://vcresearch.berkeley.edu/news/does-ai-actually-free-workers-time) (2026) - Zoom and Morning Consult, ["Take Back Lunch"](https://news.zoom.com/take-back-lunch/) (2026) - Planet Money, ["Episode 606: Spreadsheets!"](https://www.npr.org/transcripts/389027988) (2015) - Federal Reserve Bank of St. Louis, ["The Impact of Generative AI on Work Productivity"](https://www.stlouisfed.org/on-the-economy/2025/feb/impact-generative-ai-work-productivity) (2025) - METR, ["Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity"](https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/) (2025) - METR, ["We Are Changing Our Developer Productivity Experiment Design"](https://metr.org/blog/2026-02-24-uplift-update/) (2026) --- ## The Frontier on Your Laptop - **Published:** 2026-08-04 - **Tags:** ai-economics, ai-strategy, genai - **URL:** https://vinny.dev/blog/2026-08-04-the-frontier-on-your-laptop/ I have spent much of this year writing about what intelligence costs. [Paying for Intelligence Twice](https://vinny.dev/blog/2026-07-13-paying-for-intelligence-twice/) looked at the bill you pay in money and institutional knowledge when your workflows run on someone else's model. [The Instrument and the Ledger](https://vinny.dev/blog/2026-07-04-the-instrument-and-the-ledger/) built the meter. This post walks the other side of the street: models you can download and run on your own hardware. They carry costs of their own. For workloads they can handle, though, they remove the vendor's per-token meter and give you another place to route the work. The trigger is hard to ignore. In April, Google [released Gemma 4](https://blog.google/innovation-and-ai/technology/developers-tools/gemma-4/), an open-weight family under the Apache 2.0 license. Google says it is built from the same research and technology as Gemini 3. In June, Google [added a 12B model](https://blog.google/innovation-and-ai/technology/developers-tools/introducing-gemma-4-12b/) with benchmark performance nearing its 26B sibling. Ollama's default 4-bit artifact downloads at 7.6GB. A model from a frontier lab's research line now runs on a class of laptop many developers already own. The important shift is not that open weights have won, or that hosted prices only move in one direction. Hosted inference keeps getting cheaper while the local capability floor keeps rising, and that creates a routing problem rather than a winner-take-all story. To be clear, treat Gemma 4 12B as a capable mid-size model rather than the closed frontier in miniature. The useful claim is that the local floor has moved far enough to change the economics, the architecture, and the negotiating posture. ## What "open weight" means An open-weight model is one whose maker publishes the trained parameters, the billions of numbers that make it work, for others to download. You can run it on your own hardware, fine-tune it on your own data, and build products on top of it. What you usually do not get is the training data, the full training code, or the complete recipe. That is why the precise term is open weight rather than open source. The distinction matters when you are making commitments to a regulator, a board, or a customer. The license class matters more than the label. Apache 2.0 and MIT sit at the low-friction end, but neither is obligation-free. Both permit commercial use, modification, and redistribution while preserving notice requirements. Apache 2.0 also includes express patent terms. Community licenses can add other conditions. [Llama 4](https://github.com/meta-llama/llama-models/blob/main/models/llama4/LICENSE), for example, uses Meta's custom license. It requires "Built with Llama" attribution for distributed products and a separate license request for organizations above 700 million monthly active users. Several prominent releases have moved toward permissive licenses. [Gemma 4](https://ai.google.dev/gemma/docs/core/model_card_4), [Qwen3](https://qwenlm.github.io/blog/qwen3/), [Mistral 3](https://mistral.ai/news/mistral-3/), and [gpt-oss](https://openai.com/index/introducing-gpt-oss/) use Apache 2.0. [DeepSeek-R1](https://api-docs.deepseek.com/news/news250120/) uses MIT. Gemma 4 is also Google's first Apache 2.0 release in the family. Earlier Gemma generations remain under [Google's own terms](https://ai.google.dev/gemma/terms). Legal review stays on the checklist; permissive licenses just make the terms easier to compare. ## One map of the field The most useful map is deployment shape, not a ranking of model families. At one end are giant open-weight mixture-of-experts models with hundreds of billions of total parameters. The weights may be downloadable, but the deployment still requires data-center GPUs, private cloud capacity, or an inference partner. These models change where inference runs and who controls it. Even relatively efficient models can belong on this side of the map. Meta describes [Llama 4 Scout](https://ai.meta.com/blog/llama-4-multimodal-intelligence/) as a 109-billion-parameter model with 17 billion active parameters. Its 4-bit deployment fits on a single NVIDIA H100, not an ordinary laptop. At the other end are models sized for laptops, desktops, and edge devices. Gemma 4 12B belongs here, along with mid-sized Qwen releases and smaller Mistral models. These models change who can experiment, how quickly they can start, and whether every useful token creates a vendor charge. The two tracks answer different questions. One changes the control plane for production inference. The other changes the local capability floor. I am deliberately not printing a benchmark table. Releases and rankings churn too quickly, and a public leaderboard does not represent your workload. The durable facts are the two deployment shapes, the increasingly permissive licenses, and the need to evaluate models against work you do. ![Chart of open weight models by approximate loaded memory at 4-bit quantization: Gemma 4 12B at about 8GB, gpt-oss-20b about 13GB, Gemma 4 26B A4B about 18GB, Gemma 4 31B about 19GB, Qwen3 32B about 20GB, and Llama 3 70B about 42GB, shown against dashed lines for 16GB, 32GB, and 48GB machines.](/images/blog/2026/08/open-weight-memory-floors.png) ## The cost argument is now a routing argument Why does this matter to the AI ledger? Three reasons hold up under inspection. First, routing economics. The price gap is not moving in only one direction. [Hosted models keep getting cheaper](https://openai.com/index/advancing-the-price-performance-frontier-with-gpt-5-6/), and a stronger model can cost less once review and rework are counted. But when a local model clears your quality bar on a bounded, high-volume task, the marginal vendor charge falls to zero. Zero vendor charge still leaves real costs, but it flips the burden of proof. The question becomes which tasks still need the premium model. Second, data gravity. Self-hosted open weights can bring the model to your data instead of sending your data to a hosted endpoint. I lead engineering in a regulated industry, and that can simplify a data-residency review. It does not settle endpoint policy, software installation, identity, access control, logging, backups, provenance, or software supply chain risk. Local is a deployment property; approved is a governance outcome. Where the weights came from, how they were packaged, and who can invoke them remain separate reviews. ![Flow diagram showing local inference on a device passing through a control review covering data classification, install and endpoint policy, identity and access, logging and backups, provenance and supply chain, and patching and observability, ending in an approved outcome where controls match the intended use.](/images/blog/2026/08/local-vs-approved.png) Third, the learning loop. Satya Nadella's argument, the one I wrote about in July, is that AI workflows generate valuable learning exhaust from your proprietary context and corrections. My edit was to own the learning loop, not necessarily the model. Open weights make the second half of that sentence a genuine choice in a way it was not two years ago. That brings me to the caveat. Capability still buys real things, and the closed frontier remains ahead on the hardest agentic and long-horizon work. For some workloads, that gap is worth every dollar. Self-hosting is never free either. GPUs, electricity, security reviews, patching, observability, and the people who run all of it land on the other side of the ledger. An honest comparison prices both columns. The rational posture is a portfolio, and the entry fee for running one is evaluation capacity. That means a suite of your own tasks with clear pass conditions, so a model swap becomes a measurement instead of a guess. I made that argument at book length, and it applies twice when the weights carry no license fee and local inference carries no per-token API charge. ![Two-panel diagram of a workload routing portfolio: a local self-hosted panel labeled move the model to the work, listing bounded repeatable tasks, high volume after the quality bar clears, data locality, and no per-token vendor charge, and a hosted frontier panel labeled move the work to the model, listing the hardest reasoning and agentic work, long-horizon tasks, managed scale, and premium capability, with your evals routing between them by quality, cost, and control.](/images/blog/2026/08/workload-routing-portfolio.png) ## Getting started: Ollama and Gemma 4 12B The fastest way to calibrate your own opinion is to run one of these models yourself. Production workloads can stay right where they are. This exercise is about feeling the local capability floor firsthand. The easiest on-ramp I know is [Ollama](https://ollama.com/). One command downloads a pre-quantized build, handles the chat template, and includes [Google's recommended sampling defaults](https://ollama.com/library/gemma4:12b-it-q4_K_M): temperature 1.0, `top_p` 0.95, and `top_k` 64. Gemma 4 12B is the model I would start with. It uses Apache 2.0, reads images as well as text, and carries a 256K context ceiling. Google reports benchmark performance near the 26B model. The 4-bit build trades some precision for a much more practical footprint, so your own evaluations still matter. On hardware, I am writing this for Apple Silicon Macs because that is my daily environment. Ollama also ships Windows and Linux installers, and the commands below are the same. Google identifies 16GB of VRAM or unified memory as the minimum for this model. I would treat that as a floor, not a comfort recommendation. The default Ollama artifact downloads at 7.6GB, but download size is not runtime memory. Context length, the multimodal projector, and inference overhead all consume additional memory. A 32GB system leaves more room for the model, the operating system, and your browser's opinion of itself. Install Ollama. Download the installer from [ollama.com](https://ollama.com/) and open it. It installs the `ollama` command-line tool and runs a small local server in the background. Pull and run the model. In a terminal: ```bash ollama run gemma4:12b ``` The first run downloads about 7.6GB, including a pre-quantized Q4_K_M model and its multimodal projector. Subsequent runs load the model from disk. After the download, disconnect Wi-Fi if you want a blunt confirmation that inference is local. For this local model tag, inference stays on your machine unless you deliberately attach external tools or services. Give it real work. Generic test prompts teach you almost nothing. Give it a few pages from a document in your actual week and ask for the decisions, owners, and unresolved questions. Hand it an unfamiliar function and ask what it does, where it can fail, and which tests are missing. Ask it to rewrite a dense note without changing its meaning. Use material you are authorized to process on that device. Local inference does not override data-classification, endpoint, or software-installation policy. To try image input, include a file path in your message: ```text What is happening in this chart? /Users/you/Desktop/q2-costs.png ``` A few commands are worth knowing inside the chat: - `/set verbose` shows token counts and generation speed after each response - `/clear` resets the conversation context - `/bye` exits From the shell, `ollama ls` shows downloaded models, `ollama ps` shows what is loaded, and `ollama rm gemma4:12b` reclaims the disk space. Two tuning notes are worth the extra minute. First, Ollama also offers a 7.2GB quantization-aware-trained build: ```bash ollama run gemma4:12b-it-qat ``` Google designed that build with 4-bit inference in mind. Treat it as another candidate for your evaluations rather than assuming it will win every task. Second, the 256K context window is a ceiling, not a guarantee that Ollama allocates all of it. Ollama currently chooses a default based on available VRAM: 4K below 24 GiB, 32K from 24 GiB to under 48 GiB, and 256K at 48 GiB or above. Check the `CONTEXT` column in `ollama ps` before handing it a long document. Inside an interactive session, you can experiment with a larger window: ```text /set parameter num_ctx 32768 ``` Watch Activity Monitor while you do. Context is where the memory goes. ## What to expect, honestly A 12B model quantized to four bits is not a frontier model, and pretending otherwise would waste your afternoon. I tested it against the bounded work that fills an ordinary engineering week: summarizing a dense document, rewriting a decision note, explaining unfamiliar code, extracting actions from notes, and interpreting a chart. It was useful on those tasks and sometimes surprisingly good. It became less dependable when I asked it to preserve many constraints across a long sequence, reason about obscure facts, or sustain autonomous work over multiple steps. That first pass was calibration, not a benchmark. A useful evaluation would score whether the model found every decision, preserved every constraint, grounded its claims in the source, and produced code that passed the tests. "It felt pretty good" is not an evaluation strategy. The model also does not know what happened this morning. Google's [model card](https://ai.google.dev/gemma/docs/core/model_card_4) lists a January 2025 training-data cutoff. There is no search engine behind the local model unless you wire one up. On the Apple Silicon machine I tested, it streamed fast enough to feel conversational. Use `/set verbose` to capture the exact number for your hardware rather than borrowing someone else's benchmark. That honest split is the point of the exercise. The interesting discovery is how much everyday work falls comfortably inside those limits. ## Run the experiment If you lead an engineering organization, the 15-minute version of this post is worth more than the reading time. The point is calibration. Every vendor renewal now happens in the shadow of a locally run alternative with no per-token API charge that may be good enough for a growing share of bounded work. The size of that share is an empirical question. You cannot answer it without evaluations you own. Leaders who have felt that floor firsthand negotiate differently than leaders who have only read about it. They also make better platform decisions because they understand what the local option can do, where it fails, and which controls production use still requires. The local model does not replace the portfolio. It makes the portfolio real. So run it tonight. Download Ollama, pull Gemma 4 12B, and hand it something real from your week. Then reread your API bill. The meter looks different once you have met the alternative. *Model availability, licenses, and Ollama behavior checked August 3, 2026.* ## Related reading - [Paying for Intelligence Twice](https://vinny.dev/blog/2026-07-13-paying-for-intelligence-twice/) - [The Instrument and the Ledger](https://vinny.dev/blog/2026-07-04-the-instrument-and-the-ledger/) - [The Modernization Backlog Just Got Repriced](https://vinny.dev/blog/2026-08-01-modernization-backlog-repriced/) - [The More AI We Have, the More Human Judgment Matters](https://vinny.dev/blog/2026-07-26-the-more-ai-we-have/) --- ## Don't Automate the Apprenticeship Out of Engineering - **Published:** 2026-08-03 - **Tags:** engineering-leadership, ai-strategy, agentic-sdlc, future-of-work - **URL:** https://vinny.dev/blog/2026-08-03-dont-automate-the-apprenticeship/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* An agent can now finish in minutes the work that used to take a junior engineer half a day. The productivity ledger records the hours saved. It does not record what used to happen inside those hours. The junior read unfamiliar code. They formed a wrong theory about how it worked. A test contradicted them. A senior rejected the first version and explained the boundary they had missed. The junior tried again. The feature shipped, but that was only one of the outputs. The other was an engineer who understood the system a little better than they had that morning. When an agent does the work invisibly, the feature may still arrive. The second output does not. I've been circling this problem for months. In April, after building a design system in two hours, I wrote that AI didn't threaten the best designers. It threatened the work that helped beginners become good enough to join them. The line I used was blunt: [The craft survives. The on-ramp does not.](/blog/2026-04-18-claude-design-disruption-beyond-figma/) At the time, I said I didn't know how to solve it. I know more now. The answer is to recognize that entry-level work had two jobs, production and development, then redesign the development job before automation removes the production one. Preserving junior work in amber doesn't get there, and neither does assigning repetitive tasks a machine can complete safely. Toil doesn't become noble because it used to be manual. If execution is becoming abundant while judgment remains scarce, the system that produces judgment is critical infrastructure. ## The work had two outputs Most automation business cases count the artifact and ignore the apprentice. A ticket closes, a test suite passes, a dashboard ships, a migration finishes. Those are visible outputs, easy to count and easy to price. The invisible output was capability. Someone learned where the sharp edges were. They saw a clean abstraction fail against an ugly production constraint. They learned that a green test suite can still encode the wrong expectation. They sat through a review in which a staff engineer asked a question that looked pedantic until the incident six months later made it look prophetic. Engineering organizations rarely designed that learning system deliberately; we got it almost by accident. Juniors received bounded work because they could safely do it, and they made mistakes because they were new. Seniors reviewed those mistakes because the code had to ship, and repetition and correction slowly turned rules into pattern recognition. The arrangement was imperfect. Some junior work was genuinely developmental, and much of it was just toil with a career ladder attached. Nobody needs to spend three years hand-writing boilerplate to develop character. But the distinction matters: > We should automate toil aggressively. We should stop pretending that all low-level work is toil. Some apparently routine work teaches the shape of a system. Debugging a failed integration teaches more than reading its architecture diagram, and writing a first implementation forces assumptions into the open. Responding to a production alert connects code to consequence, and a first-pass code review teaches what experienced engineers notice and what they miss. Remove the task and you may remove drudgery, but remove the feedback loop and you remove the apprenticeship. A task becomes an apprenticeship when prediction, feedback, explanation, and increasing independence are designed into the work. Assigning it to a junior doesn't make it one. Without those conditions, leaders can relabel any unpleasant task as development and preserve toil under a better name. The productivity calculation has to know which one it's doing. ## The early evidence is uncomfortable This concern is no longer purely theoretical. In a 2026 randomized study, developers learned an unfamiliar asynchronous programming library with or without AI assistance. The AI-assisted group scored 17 percent lower on a test of concepts they had just used. The small speed improvement did not reach statistical significance. The worst learning outcomes came from people who delegated the task most completely. Participants who used AI to ask conceptual questions, request explanations, and test their own understanding retained more. The study was narrow and short-term. It doesn't prove that AI makes engineers worse, and its authors do not claim that. It shows something more useful: [the interaction pattern changes the learning outcome](https://www.anthropic.com/research/AI-assistance-coding-skills). AI can be a tutor, a collaborator, or an escape hatch from thinking. The workflow and incentives decide which one shows up. Another 2026 analysis looked at roughly 400,000 Claude Code sessions. It found that people still made most planning decisions while the agent made most execution decisions. Greater domain expertise correlated with higher success and with getting more useful work from each instruction. [The data shows that expertise still matters](https://www.anthropic.com/research/claude-code-expertise). It doesn't answer how the next generation will acquire it. A separate longitudinal survey found the job itself moving in the same direction. Eighty-two percent of participants reported spending less time writing code, while more of the work shifted toward directing, evaluating, and correcting AI output. The researchers called the emerging category [supervisory engineering work](https://arxiv.org/abs/2605.23135). That sounds like progress until you ask where a new engineer learns to supervise. Put those findings together and the apprenticeship problem becomes visible. The skills that make agentic work successful are still human skills: understanding the domain, framing the task, recognizing a bad turn, and knowing what evidence deserves trust. But the work through which people historically developed those skills is precisely the work agents are beginning to absorb. We're automating the practice field while increasing demand for better players. ## The old ladder broke before the new one existed The old path was inefficient, but it was legible. You wrote a lot of code badly, got corrected, and wrote less code badly. You debugged systems you didn't understand while sitting beside someone who did. You took incident calls and discovered that the elegant diagram left out the part that wakes people at two in the morning. Eventually you accumulated enough scars that certain failure modes began to feel obvious. That path produced uneven results, and it excluded plenty of capable people. I'm not nostalgic for it. The problem is that many organizations are replacing it with no path at all. A junior can now produce a senior-looking artifact before developing a senior mental model. The pull request is tidy and the explanation is confident. The tests are green because the same system that misunderstood the requirement wrote the tests around its misunderstanding. Plausible output arrives before comprehension. The senior still catches the problem because the senior has seen the movie before. Then the senior fixes the prompt, reruns the agent, and moves on because delivery pressure is real. The code gets better, and the junior learns almost nothing about why. Run that loop often enough and the organization gets faster in the quarter while becoming less capable over the decade. Two responses are common. One is to let juniors use agents for everything because AI fluency is the new baseline. That produces output, but without deliberate friction it can outsource the exact cognitive work the apprentice needs. The other is to ban AI for junior engineers until they've learned the fundamentals. That protects an old curriculum for a world that no longer exists. It trains people to perform work manually while their future job is shifting toward directing, evaluating, and correcting machines. The choice underneath both responses is whether learning remains an accidental byproduct of production or becomes an explicit part of the operating model. ## Production mode is not learning mode The mistake is asking one workflow to optimize two different things without saying which one matters. Production mode should optimize for a verified outcome. Delegate aggressively when the work is bounded, the answer key is strong, and the task has little developmental value. If an agent can complete a routine dependency update safely, nobody needs to retype it for educational theater. Learning mode should optimize for cognitive ownership. Make the apprentice predict, choose, diagnose, and explain before the agent reveals the answer. Slow the reveal and require a testable prediction. That preserves the moment when the learner has to commit to what they think the system will do. The tool can be the same. The contract cannot. If the mode stays implicit, delivery pressure will choose production every time. The ticket will close, the dashboard will improve, and the organization will discover much later that speed consumed the practice it depended on. This doesn't mean every ticket must carry a lesson plan. It means leaders should know whether a workflow is harvesting capability, building capability, or intentionally doing only one of the two. ## Judgment is not a seniority badge I define judgment as the ability to combine context, evidence, consequences, and accountability when the rules are incomplete. That capacity is compressed experience, and no title confers it. It comes from making decisions, seeing what happened, receiving correction, and updating the model in your head. This changes what apprenticeship should optimize. The junior doesn't need to type every line the agent could produce. What they need is enough ownership of the reasoning that a wrong line creates dissonance. Predicting what should happen before the test tells them is part of that, and so is identifying the invariant before asking the model to repair the symptom. The habit underneath all of it is deciding what good looks like, then comparing that decision with reality and with someone more experienced. That still requires contact with the machinery. An engineer cannot learn to supervise a system entirely from summaries of what the system did. Before delegating a capability completely, they need enough direct practice to decompose a problem, trace behavior through unfamiliar code, design a meaningful test, debug a failed assumption, and explain a causal chain without borrowing the agent's explanation. The required amount will vary by domain and consequence, though the requirement itself does not. In [The Spec Is the Product](/blog/2026-05-12-the-spec-is-the-product/), I argued that spec review is becoming the new code review. The apprenticeship model has to move with it. Pairing on code still matters, but pairing on frames, specifications, evaluations, and release decisions is where more of the learning now belongs. The unit of apprenticeship is shifting from the keystroke toward the decision, though decisions still need contact with the machinery they govern. The thing worth protecting is understanding, not typing. ## A new apprenticeship loop If I were designing an agentic apprenticeship for an engineering organization today, I would build it around six moves. ### 1. Frame before generation Before the agent writes anything, the apprentice writes the problem frame. What behavior must change, and what must remain true? Which assumptions are being made, what evidence will prove the work is complete, and what is the most likely way this request is misleading? The senior reviews that frame before reviewing any generated code. This moves mentorship to the point where misunderstanding is cheapest. It also keeps the apprentice from inheriting the agent's first interpretation as if it were a fact. The deliverable is a visible reasoning surface a senior can correct, rather than a perfect specification. ### 2. Review before reveal The apprentice should perform the first review without seeing the senior's assessment. Ask them to mark the risky assumptions, identify missing tests, explain the change in their own words, and state whether they would approve it. Only then compare their review with the senior's. That comparison is the lesson. Where did the two reviewers agree, and what did the senior notice first? What did the junior notice that the senior missed, and which signal was real rather than noise? When the senior reviews first, the apprentice learns the answer; when the apprentice reviews first, they practice producing it. ### 3. Diagnose before regenerating When agent-generated work fails, don't immediately ask the agent to try again. Require a diagnosis first. What assumption was wrong, and which invariant was violated? Was the failure in the implementation, the specification, the context, or the answer key, and what new test would fail for the right reason? Regeneration makes fixing cheap, while diagnosis turns the failure into knowledge. The rule should be simple: no retry without a prediction. Name the suspected invariant, the evidence that would falsify the theory, and the test that should change if the diagnosis is right. ### 4. Manufacture practice, not answers The machine removing the old practice field can help build a better one. Give an agent a production incident and ask it to release the evidence in stages. Ask it to generate three plausible pull requests, each wrong in a different way, or to hide one violated invariant inside an otherwise clean change. Give the apprentice an ambiguous specification and make them find the questions the agent should not answer yet. AI can create counterexamples, incident replays, review exercises, and progressively harder failures at a cost no traditional training program could match. But the learning contract matters. The apprentice predicts before the reveal, reviews before the explanation, and diagnoses before the repair. If AI can generate unlimited implementations, it can generate unlimited opportunities to compare, falsify, and explain. The same collapse in cost that made generation cheap can make practice cheap too. ### 5. Narrate the override Experienced engineers make small override decisions constantly. They reject a technically valid abstraction because it creates operational coupling, or keep an ugly boundary because a migration is still in flight. They demand another gate because the rollback path is weaker than the implementation looks. Those decisions often remain tacit, and in an agentic workflow they need narration. When a senior rejects a plausible output, they should explain which signal changed the decision. Then the team should decide whether the lesson belongs in a specification, standard, test, runbook, or evaluation. The goal is to keep valuable judgment from disappearing inside one person's approval click, without turning every judgment into a rule. This is how mentorship and the Context Spine become the same system. ### 6. Increase consequence gradually Apprenticeship requires real responsibility, but responsibility should expand with demonstrated judgment. Start with sandboxed work and reversible changes. Move to pull requests, then bounded production ownership, then higher-consequence decisions with explicit rollback and escalation paths. Don't promote autonomy based only on how much an engineer or their agent can generate. Promote it based on the quality of the frames they write, the failures they anticipate, the defects they catch, and the decisions they can explain. Consequence has at least four dimensions: - Reversibility: Can the action be undone cleanly? - Blast radius: How many systems, customers, or obligations can it affect? - Observability: How quickly will the team know it's wrong? - Recovery cost: How difficult will restoration be after failure? An apprentice may safely own a high-volume change with strong isolation and instant rollback before owning a small irreversible change whose failure stays quiet for a month. Responsibility should expand as the evidence arrives, and the progression runs from smaller consequences to larger ones rather than from less AI to more AI. | Stage | Apprentice owns | Agent contributes | Senior teaches | Evidence of growth | | --- | --- | --- | --- | --- | | Frame | Intent, assumptions, acceptance criteria | Exploration and questions | Problem boundaries | Specs become clearer and more testable | | Build | Decomposition and direction | Implementation and iteration | Tradeoffs and system shape | Fewer misunderstood changes | | Review | First-pass evaluation | Explanations and alternatives | Pattern recognition | Predictions increasingly match independent evidence and outcomes | | Failure | Diagnosis and new hypothesis | Search and candidate fixes | Invariants and causal reasoning | Faster, more accurate recovery | | Release | Risk, rollback, and recommendation | Checks and execution support | Consequence and accountability | Safe independent ownership expands | That's an apprenticeship designed for the work that is arriving instead of the work we remember. ## A better ladder does not matter if the door closes Everything so far assumes the apprentice is already inside the organization. That's not guaranteed. If a senior engineer working with agents can produce more, the immediate economic response may be to hire fewer beginners. A company can build an excellent program for 10 junior engineers while reducing its entry-level class from 100 to 10. The 10 may learn better, and the profession still loses most of its on-ramp. A better curriculum doesn't preserve an apprenticeship if companies stop opening the door. I'm not arguing for a fixed ratio of junior engineers or pretending AI will leave headcount unchanged. Some teams will become smaller. Some entry-level tasks will disappear completely, and some should. The honest claim is narrower: if the industry expects a future supply of people capable of evaluating consequential systems, some organizations have to provide paid access to consequential work before beginners are independently productive. That investment has a structural problem: the skills it produces are portable. A company can fund years of development and watch the engineer leave, while another company hires experienced people without helping create them. [Workforce economists have studied this as a training market failure](https://www.nber.org/papers/w34012): the employer paying the cost may not capture the full return, so the market provides less training than the work ultimately needs. AI makes the temptation stronger. Buy the tool, hire fewer beginners, and recruit experienced evaluators from the companies still producing them. Every individual decision can look rational while the shared talent pipeline empties. This is why apprenticeship cannot survive as the personal generosity of a few engineering managers. It needs an explicit enterprise commitment: real entry paths, rotations through meaningful work, protected learning time, and partnerships where a single company cannot carry the whole cost. The new ladder also has to be more equitable than the accidental one it replaces. Informal mentorship tends to flow toward people who already look confident, share the right networks, or know which senior to ask. When senior attention becomes scarcer, that pattern gets worse unless access is designed. Publish the competencies and rotate the opportunities. Give every apprentice structured feedback, a path to contest a review, and credit for their contributions. Build portable skill instead of dependence on one company's tools or one senior's preferences. Apprentices are people making a career bargain before they are inventory in an evaluation-capacity pipeline. The bargain should give them increasing agency, visible progress, and skills worth carrying elsewhere, even when that portability makes the investment harder to defend on a spreadsheet. ## Senior time is part of the capital plan None of this is free. If AI makes a senior engineer twice as productive, the easiest move is to fill the reclaimed capacity with twice as much delivery. That's rational at the team level and dangerous at the system level. The organization consumes senior judgment without reserving any capacity to reproduce it. The review load can move in the opposite direction from the generation cost. One 2026 observational study examined 22,953 pull requests from lower- and higher-experience AI-assisted contributors. The lower-experience group submitted larger changes, received 4.52 times more review comments, had 31 percent lower acceptance, and remained open 5.16 times longer. The study does not prove that AI caused those differences, but [the operating warning is hard to miss](https://arxiv.org/abs/2602.23905): cheap generation can turn senior attention into the shared bottleneck. Mentorship cannot remain invisible volunteer labor performed after the sprint is already full. If evaluation capacity is a funded constraint, apprenticeship is how that capacity renews itself. Funding it means changing more than the calendar. Team capability has to become an expected senior output, and teaching artifacts must count as durable engineering work. Managers need to own access and progression, which is more than encouraging mentoring. Delivery plans have to reserve development capacity before the backlog consumes it. It also has to scale, because not every lesson requires an hour of one-to-one staff-engineer time. Teams can run cohort reviews, replay incidents, preserve narrated overrides, use peer review before senior review, and build reusable evaluation fixtures. Agents can provide explanations and adaptive practice without revealing the answer too early. The point is to concentrate scarce senior attention on the judgment only experience can currently teach. This belongs on the [AI Operating Ledger](/blog/2026-06-08-the-ai-operating-ledger/). The institutional-memory line should ask whether people learned, and not settle for whether documentation improved. Did the workflow create another person capable of evaluating its output, or did it concentrate more judgment in the few people already carrying it? The measures should change accordingly. Lines of code and tickets closed were always weak proxies. In an agentic apprenticeship, I would watch: - The quality and acceptance rate of apprentice-authored specifications - Defects identified in first-pass review before senior intervention - Calibration between apprentice predictions, independent evidence, and eventual outcomes, including cases where the apprentice correctly challenged a senior - Failure diagnoses that become durable tests or standards - Time to independent ownership of increasingly consequential systems - Senior capacity explicitly spent narrating decisions and reviewing frames The measures exist to make the investment visible enough that delivery pressure cannot erase it without anyone noticing. They are not an attempt to turn human development into another dashboard that pretends to be precise. ## Three objections The strongest objection is that AI can help people learn faster. It can explain an unfamiliar codebase, generate examples on demand, create practice problems, and let a junior explore systems that would otherwise be inaccessible. I believe all of that. I use AI to learn every week. The concern is different: production incentives reward delegation and are indifferent to comprehension. If the only measured outcome is whether the task closed, the fastest path is to let the agent carry as much of the cognitive load as possible. Learning requires a different loop. Another objection is that organizations don't have time for this. The delivery backlog is real, senior attention is scarce, and the whole reason to adopt AI was to increase capacity. That's exactly why the investment matters. An organization that has no time to develop evaluators is choosing to make evaluation capacity scarcer. The bill won't arrive in the current sprint. It will arrive when the people who can distinguish plausible from correct are overwhelmed, leave, or become the bottleneck every agentic workflow shares. A third objection is that agents will soon evaluate other agents, making the human pipeline less important. They will, and they already do. Automated review, adversarial agents, test generation, and machine-graded answer keys should absorb as much repeatable evaluation as they can. But someone still has to decide what good means, test whether the evaluator is grading the right behavior, resolve contested cases, and own the consequence of being wrong. As more judgment becomes encodable, the remaining judgment moves to the seams where context is incomplete and tradeoffs are real. That argues for renewing the smaller pool of expertise the system still depends on, which is a different argument from infinite headcount. ## What would change my mind I may be overestimating how much the old practice field mattered. If agent-native engineers reach independent system ownership faster than prior cohorts, diagnose incidents as effectively, predict failures as accurately, and make equally sound decisions despite performing far less manual implementation, then the new path is already working better than I think. We should measure those outcomes rather than romanticize the route that produced us. I would also revise this argument if machine evaluators begin reliably supervising consequential systems beyond the practical reach of human reviewers, including defining the right criteria and resolving novel edge cases without pushing hidden risk downstream. In that world, the evaluator pipeline matters less because evaluation itself has crossed the same threshold as generation. I haven't seen either result yet. The current evidence points in the other direction: expertise still improves agentic outcomes, while some forms of delegation weaken the learning needed to build that expertise. But I hold this as an operating hypothesis. The apprenticeship system should collect the evidence that tests it. ## Run it for a month Don't start with a curriculum committee. Pick one recurring, agent-assisted workflow on one engineering team. Name a manager accountable for the apprenticeship outcome and a senior engineer accountable for the technical boundary. Put the development capacity into the plan before the delivery work begins. Map each step into three categories: 1. Toil to automate: repetitive work with little learning value and a strong answer key. 2. Practice to redesign: bounded work where prediction, feedback, and correction build judgment. 3. Consequence to supervise: decisions where failure has material cost and an experienced person still owns the outcome. Declare whether each run is in production mode or learning mode. For the next month, make an apprentice the first framer and first reviewer on the practice work. Require a prediction and a falsifying test before every regeneration. Ask the senior to narrate one consequential override each week and encode the lesson where the next person or agent can use it. Expand responsibility only when the evidence supports it. At the end of the month, don't ask whether the apprentice agreed with the senior. Compare both of their predictions with independent evidence and with what happened after release. Preserve the cases where the apprentice was right. They are proof that the ladder is producing judgment rather than obedience. Then review two outputs. Did the work ship? Did another person become more capable of judging the next piece of work? If the first answer is yes and the second is no, the workflow produced software while consuming the future capacity of the organization. That may occasionally be the right bargain. It should never be an invisible one. AI is eliminating accidental apprenticeship, not apprenticeship itself. The replacement has to be designed. The craft can survive, and so can the on-ramp, but only if we stop treating it as incidental labor and start funding it as part of the production system. --- ## Related reading - [I Built a Design System in Two Hours. Figma, We Should Talk.](/blog/2026-04-18-claude-design-disruption-beyond-figma/) - [The More AI We Have, the More Human Judgment Matters](/blog/2026-07-26-the-more-ai-we-have/) - [The AI Operating Ledger](/blog/2026-06-08-the-ai-operating-ledger/) - [The Spec Is the Product](/blog/2026-05-12-the-spec-is-the-product/) - [Two Gates and a Night Shift](/blog/2026-07-06-two-gates-and-a-night-shift/) ## Research notes - Shen and Tamkin, [How AI Impacts Skill Formation](https://arxiv.org/abs/2601.20245), 2026. - Anthropic, [Agentic coding and persistent returns to expertise](https://www.anthropic.com/research/claude-code-expertise), 2026. - Vella and Blincoe, [The Impact of AI Coding Assistants on Software Engineering: A Longitudinal Study](https://arxiv.org/abs/2605.23135), 2026. - Asdaque et al., [Novice Developers Produce Larger Review Overhead for Project Maintainers while Vibe Coding](https://arxiv.org/abs/2602.23905), 2026. - Dillon et al., [Do Workforce Development Programs Bridge the Skills Gap?](https://www.nber.org/papers/w34012), revised 2026. --- ## The Modernization Backlog Just Got Repriced - **Published:** 2026-08-01 - **Tags:** agentic-sdlc, ai-economics, engineering-leadership, architecture - **URL:** https://vinny.dev/blog/2026-08-01-modernization-backlog-repriced/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* The rewrite taboo did not die of old age. It died of a price change. I made that argument in [July](/blog/2026-07-17-everyone-knows-you-never-rewrite/): for systems whose intent lives in an executable oracle, the cost of a full rewrite collapsed. One engineer porting roughly half a million lines of Bun from Zig to Rust in 11 days was the receipt. Thousands of tests and a hard compatibility target meant every generated change faced an examiner that never got tired and never got polite. That argument stopped where the evidence stopped, at one codebase with a conformance suite standing behind it. An enterprise backlog lives at a different scale. It is 40 systems, or 400, many of them older than the teams operating them. Their intent lives in exception queues, hardcoded business rules, regulatory interpretations, production workarounds, and the memory of people who retired. When the repricing reaches that portfolio, the question is no longer simply whether rewriting has become cheaper. It is which systems have become economically eligible for a rewrite, and which have not. The sort key surprised me. > *A system's rewrite price is set by its answer key, not by its code.* Everything in this post follows from that sentence, so the term deserves a real definition before it does any more work. ## What Bun had that your policy administration system does not The July argument used a term from software testing: the executable oracle. An oracle is anything that lets a machine grade the question that decides a cutover: does the new system behave like the old one everywhere that matters? > In software testing, an oracle is whatever supplies the expected result for a given input, so a machine can grade actual behavior as pass or fail. Scale that up to a rewrite and the oracle grades the question that decides a cutover: does the new system behave like the old one everywhere that matters? Conformance suites qualify. So do test suites with real behavioral coverage, reconciliations that must balance to the penny, and recorded production traffic that can be replayed against both systems and diffed. Bun was unusually rewritable because that question had a mechanical answer. Most enterprise systems face no such examiner. Their correctness lives in behavior: the override a team added in 2011, the batch job that runs twice at quarter-end for reasons nobody documented, the field that means one thing to claims and another to finance. The system is often its own only specification. The first person who reviewed this draft read "oracle" and asked what the database company had to do with any of it. It was a fair question about the wrong company, and it convinced me that the testing term does not travel well outside its discipline. From here on, I will use a plainer name for the same idea: the answer key. An answer key can establish equivalence. It can show that the replacement behaves like the system it is replacing. It cannot, by itself, prove that the old behavior is still desirable. That distinction matters. A characterization test can faithfully preserve a defect that downstream systems now depend on. A replay harness can prove that a 30-year-old exception still fires without telling anyone whether the exception should survive. The answer key tells us whether the new system is the same. A specification tells us whether the old system was right. Modernization needs both. ## The answer key inventory Here is the sorting exercise I would run against any modernization backlog this year. Score every candidate system into one of three rewrite-readiness tiers, and be stingy about the first one. The stinginess matters because every incentive in a large organization pushes toward overclaiming. A team that reports 80 percent test coverage is reporting a number about lines, not necessarily a number about behaviors. The paths that sink cutovers hide in a different kind of gap: the quarter-end path, the leap-day path, the retry storm nobody has rehearsed since the incident that created it. Tier placement is a bet on a cutover weekend, so score it like one. Tier 1: the answer key exists. This tier holds calculation engines with golden datasets, protocol integrations with conformance suites, and systems whose outputs already reconcile daily against a trusted external record, such as the general ledger. Teams claim this tier freely because "we have tests" always feels true. The membership test is blunt: would you bet a cutover weekend on green? Systems that pass just became some of the cheapest rewrite candidates in the portfolio, and there are fewer of them than most architecture reviews suggest. Tier 2: the answer key is constructible. The system's behavior is stable and observable even though nothing checks it comprehensively today. These systems reward a specific move: build the answer key before touching the replacement. The toolkit is familiar, just rarely funded as the first deliverable: characterization tests that record what the system does, bugs included; capture and replay of production traffic; and shadow runs in which old and new process the same day while a reconciliation compares their outputs. The modernization project starts life as a verification project, and that inversion is the strategy. For many systems in this tier, the answer key will cost far less than the rewrite it de-risks. It can be built while the old system remains in production, and it retains value even if the rewrite is delayed. A characterization suite can improve ordinary maintenance, incident diagnosis, vendor changes, and future migration work. It is not automatically cheap, especially when the legacy system is poorly observable, but it is one of the few modernization investments that can still pay off when the larger program pauses. Tier 3: the answer key is absent or contested. Nobody agrees on what correct means. Two business units interpret the same field differently, a known defect has become load-bearing, or the behavior itself is the subject of an unresolved policy dispute. The repricing has not reached this tier because the organization cannot yet state what a replacement must preserve, what it should intentionally change, or who gets to decide. These systems need intent recovery first. Someone has to write the specification the system never had, resolve the disagreements hidden inside current behavior, and identify which accidents deserve to survive. That work is human, political, and slow. I made the case for the durability of that artifact in [The Spec Is the Product](/blog/2026-05-12-the-spec-is-the-product/). Tier 3 is where that argument gets expensive. These tiers do not replace portfolio prioritization. A Tier 1 system with little business value may still wait, and a Tier 3 system with an unacceptable security or operational exposure may demand immediate investment. The tiers answer a narrower but newly important question: can a replacement be proven well enough to make the rewrite economically credible? The roadmap still has to combine that readiness with value, urgency, and risk, and the combination changes the conversation from "what should we modernize?" to two better questions: "what must we modernize?" and "what can we now modernize with evidence?" ## The smallest answer key I own I ran a miniature version of this exercise in July on my own laptop, on a project with no enterprise stakes. [MacHeadroom](https://www.macheadroom.com/) is a Mac menu bar app I am building that shows the top CPU and memory consumers, with one twist: it consolidates helper processes into a single row per application, so a dozen Chrome processes appear as Chrome. Every number it displays is a claim about the machine, and a monitoring app that shows plausible wrong numbers is worse than no app at all. The answer key came with the operating system. macOS already exposes process accounting through tools such as `ps` and Activity Monitor. Before polishing the interface, I built the reconciliation: sample the system, consolidate the processes my way, and compare the result against the platform's own accounting every five seconds, with 2 percent as the permitted drift. The comparison lives where the mistakes live, in the consolidation itself, because a dozen Chrome helpers have to sum to what the platform says Chrome is using, every cycle, or the row is wrong. MacHeadroom is greenfield, so I will not dress it up as a rewrite story. It is the answer-key discipline at its smallest useful scale. The checkable truth was sitting there the whole time. The only meaningful decision was to compare my output against it before trusting what I had built. Tier 2 work on a 40-year-old system follows the same principle with more zeros, more stakeholders, and much less forgiveness. ## The budget line moves Put the tiers against a project plan and the old cost model starts to look incomplete. Construction dominated the traditional rewrite estimate, which is why planning centered on lines of code, modules, integration points, and developer-years. Generation is getting cheaper, so the relative weight of the remaining work increases. The expensive questions become: can we recover the intent, build the answer key, reconcile the data, prove the integration behavior, and execute the cutover safely? The dominant cost moved rather than disappeared. The second edition of my book gives this discipline a name: evaluation capacity as a separately funded constraint. Treat the answer key as a capital asset with its own budget line, not as a testing task buried inside the construction plan. The asset case is straightforward. A project's replacement code ships once. Its answer key can gate every future regeneration of the system, every model upgrade, every vendor substitution, and every material change after the cutover. It can also improve maintenance and change confidence in the existing system before the rewrite begins. I made the broader case in [Trust the Gate, Not the Actor](/blog/2026-06-14-trust-the-gate-not-the-actor/) and [The AI Operating Ledger](/blog/2026-06-08-the-ai-operating-ledger/). The modernization backlog is where that accounting becomes operational. A business case that prices the port but hides verification inside it is still using the old curve. ## Score three, pilot one, scale on evidence The first move fits inside a quarter. Pick three candidate systems and score their answer keys against four questions: 1. Does a failing test exist for every behavior that matters? 2. Can a representative period of production activity be replayed against both systems? 3. When old and new disagree, who arbitrates, and against what record? 4. What evidence will risk, audit, and any relevant regulator accept as proof? Write the answers down. The scores will probably disagree with the current roadmap, and that disagreement is useful. The system everyone wants to modernize, the one with the executive sponsor and the conference-slide architecture, may score Tier 3 because its correctness is politically contested. The unglamorous batch process that reconciles to the general ledger every night may score Tier 1, even though nobody has proposed touching it in a decade. That does not automatically send the batch process first; it tells the organization which candidate can produce credible evidence quickly, and which one is still disguising an intent problem as a technology problem. Then run Platform Pilot Zero on one valuable Tier 2 system. Build the answer key first. Use reconciliation as the gate. Cut over only when the difference between old and new is understood, accepted, and quiet enough for the system's risk profile. The book's term for that discipline is evidence-gated scaling: the program earns its next tranche of systems from the pilot's reconciliation record, and that record should be auditable by a skeptic. Enthusiasm scales faster than evidence in every large transformation I have watched, which is precisely why the gate belongs on evidence. ## The honest objection The strongest objection deserves the floor: code volume was never the hardest part. Data migration, integration topology, organizational change, operational readiness, and regulatory validation dominate the cost of many enterprise modernizations. Cheap code generation touches none of them directly. That is correct, and I will not argue otherwise. What the repricing changes is the feasibility threshold. It shrinks one term in the equation enough to reorder which systems can clear the total cost. Projects that failed the old construction math may now pass, provided their verification story holds. The other terms still cost what they cost. The answer key does not make data migration cheap. It turns migration from a subjective project into a measurable convergence problem. It does not untangle integrations. It lets the team observe whether the new topology preserves the outcomes that matter. It does not perform organizational change. It gives operators and business owners concrete evidence to accept or reject the new behavior. Verification leaves the hard parts hard and makes more of them measurable. A second caveat comes with regulated industries, including mine. Green tests rarely satisfy independent validation requirements on their own, and risk teams, auditors, and regulators may require separate controls, traceability, review, and evidence based on the system's materiality. The answer key makes validation faster and stronger without replacing the validator, and anyone selling an agentic rewrite that skips that step is selling you an incident. Two findings would send me back to revise this post. If constructing answer keys consistently costs as much as the rewrites they enable, rising on the same curve, Tier 2 collapses into Tier 3 and the sorting loses much of its economic value. If enterprise ports show cutover failure rates unmoved by serious verification investment, then the gate is theater and the skeptics were right about more than the hard parts. I do not expect either result, but the approach fails safely. Even if the rewrite never proceeds, the organization retains a clearer specification, stronger observability, and a reusable record of how the current system behaves. The program produces answer keys either way, and answer keys keep. So the Monday morning answer is small and concrete. Pick three systems, score their answer keys against the four questions, and combine that readiness with business value, urgency, and risk. Fund the strongest Tier 2 candidate's answer key as its own line, run the pilot, and let the reconciliation record decide what earns the next tranche. The repricing already happened. The sorting is how it reaches your ledger. --- **Related reading** - [Everyone Knows You Never Rewrite](/blog/2026-07-17-everyone-knows-you-never-rewrite/) - [The Spec Is the Product](/blog/2026-05-12-the-spec-is-the-product/) - [Trust the Gate, Not the Actor](/blog/2026-06-14-trust-the-gate-not-the-actor/) - [The AI Operating Ledger](/blog/2026-06-08-the-ai-operating-ledger/) - [Building Cloud From Zero](/blog/2026-05-08-building-cloud-from-zero/) - [Yesterday's Feature Is Today's Bug](/blog/2026-03-15-yesterdays-feature-is-todays-bug/) --- ## The More AI We Have, the More Human Judgment Matters - **Published:** 2026-07-26 - **Tags:** ai-strategy, engineering-leadership, context-spine, genai - **URL:** https://vinny.dev/blog/2026-07-26-the-more-ai-we-have/ Picture two data purge requests landing in a compliance queue on the same afternoon. Both flag a user profile for deletion under the standard privacy policy. An AI compliance agent reviews the criteria it was given: account age, inactivity period, and privacy tags. Both records pass. Both get approved for a hard delete. An engineering leader stops the second one before the deletion runs. To the automated system, the profiles were identical, two inactive records slated for routine cleanup. To the human, they could not have been more different. The first belonged to an ordinary consumer account. The second belonged to a person under an active legal hold. The hold lived in another system, owned by another department. Deleting the first record satisfies a privacy mandate. Deleting the second destroys evidence a regulator expects the company to preserve. Every criterion was valid; the set of criteria was incomplete. The catch came from a person who understood the case because they had sat in the meetings. They knew which of the company's obligations had not yet been written down anywhere a machine could read them. The fix took a week. Legal-hold status is now one of the criteria, and the agent will check for it every time. Hold that fix in mind, because it is the whole story of this essay. I've argued for a while that AI is not changing whether organizations need people. It is changing where people create value. AI will reduce the amount of human labor required for many kinds of work. That upheaval is real. But it is not eliminating the need for people; it is concentrating their value where rules are incomplete, consequences are uneven, and context still matters. In [The Bottleneck Is Never the Stack](/blog/2026-05-13-the-bottleneck-is-never-the-stack/), I argued that software delivery is no longer constrained by infrastructure or even engineering talent. The constraint has moved upstream, toward clarity of intent. This is the human side of that same story. Every major technology wave changes what becomes scarce. Cloud made infrastructure more abundant. Platforms made deployment easier. AI is now doing the same thing for knowledge work. Each generation of capable models continues to lower the cost of generating code, writing documents, analyzing data, and exploring ideas. Execution is becoming abundant, and when execution becomes cheap, competitive advantage moves somewhere else. ![As intelligence becomes abundant, organizational advantage shifts toward judgment, context, verification, and leadership.](/images/blog/2026/07/judgment-thesis-pullquote.png) Judgment is not instinct dressed up as experience; it is the ability to combine context, evidence, consequences, and accountability when the rules are incomplete. That idea explains why AI is both enormously destabilizing and surprisingly human. It also explains why I've become convinced that intelligence itself is becoming infrastructure. Access to capable models will become table stakes. Developers, analysts, designers, architects, and product managers will increasingly rely on them. As access to capable machine intelligence broadens, the differentiator becomes knowing what deserves it. Models can reason, but organizations are built on decades of accumulated context that no model completely possesses. Competitive advantage rarely lives inside a single document or vector database. It lives in relationships, institutional memory, cultural norms, technical debt, customer history, unwritten assumptions, and thousands of decisions that shaped the company long before today's models existed. That context is difficult to copy because it was earned, not generated. AI is remarkably good at answering questions. The harder problem is deciding which question matters. Organizations do not usually fail because they lack answers. They fail because they optimize yesterday's problem, automate the wrong workflow, or mistake a symptom for the actual constraint. That is a leadership problem, not a model problem. This is also why context becomes strategic. In several of my essays, starting with [The Agentic SDLC](/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/), I've described the importance of a Context Spine. That spine is the accumulated understanding of customers, systems, history, incentives, failures, and tradeoffs that lets an organization make consistently better decisions. Models possess enormous amounts of public knowledge. Organizations win because they possess private context, and AI makes that context more valuable, not less. The same pattern appears in software delivery. In [Everyone Knows You Never Rewrite](/blog/2026-07-17-everyone-knows-you-never-rewrite/), I argued that AI dramatically lowers the cost of iteration. Rewriting code, exploring alternatives, and trying new approaches become inexpensive. That amplifies engineering judgment instead of eliminating it, because when generating solutions costs almost nothing, choosing between them becomes the scarce skill. That is also the economic argument behind [Paying for Intelligence Twice](/blog/2026-07-13-paying-for-intelligence-twice/): as intelligence becomes commoditized, proprietary context and institutional learning become the assets worth protecting. The value does not disappear; it moves. The same is true for leadership, starting with relationships. The most important work inside large organizations has never been purely technical. It depends on trust, credibility, influence, and the ability to align people with different incentives. AI can summarize the meeting, but it cannot inherit 20 years of earned trust. Pattern recognition becomes more valuable as well. I do not mean statistical pattern recognition, which models already perform extraordinarily well. I mean organizational pattern recognition. Experienced leaders recognize failure modes before dashboards expose them. They understand which proposals have failed before, why they failed, and which invisible constraints still exist. They know when two situations that appear identical are fundamentally different. The purge queue is that story at machine speed. That is judgment. Humans are not valuable because they are infallible; the leader in the purge queue has missed things too. The advantage comes from accountable people working inside systems that expose uncertainty, require verification, and turn newly discovered context into durable controls. The goal is not heroic intervention but an organization that learns. That is the argument behind [Trust the Gate, Not the Actor](/blog/2026-06-14-trust-the-gate-not-the-actor/): reliable systems should not depend on any one person or model getting everything right. Perhaps the most valuable human skill of all is asking the question nobody else thought to ask. Models can challenge a frame, but they do not own the consequences of choosing one. Leaders do. I made the case for human-led framing at length in [The Frame Is the Bottleneck](/blog/2026-05-24-the-frame-is-the-bottleneck/), and the distinction grows more valuable every year. ## The obvious objection is mine If you have been reading these essays, you can see the problem. I keep telling organizations to write their context down, version it, and feed it to agents. The Context Spine exists to make private context machine-readable. The [gates in my own delivery pipeline](/blog/2026-07-06-two-gates-and-a-night-shift/) exist to encode judgment so it runs at full sharpness even when I am tired. If that program succeeds, the uniquely human share should shrink with every commit. It does shrink, and that is the point. We can add legal-hold status to the purge criteria, and we should. But encoding is itself an act of judgment, all the way down. Someone decided that criterion was missing. Someone will notice when the next one is missing, because an organization creates new obligations, exceptions, and tacit understandings faster than anyone writes them down. Someone also has to know which accumulated context is an asset and which is baggage, because context expires too. The moat is not the context itself but the ongoing act of curating it. Here is what would change my mind. If models begin absorbing organizational context faster than organizations generate it, the value really is migrating into the spine. The same is true if thin-context companies run by agents start consistently beating context-rich incumbents. Either way, I will have overstated the human share, and this essay deserves a correction. I am watching for both. I have not seen either. The more I write about AI, the more I arrive at the same conclusion from different directions. The bottleneck is not the model, the framework, or the programming language. It is not even intelligence itself. The scarce resource is judgment. The organizations that outperform over the next decade will not simply have the best AI. They will have the people who know what deserves attention, what deserves skepticism, what deserves verification, and what deserves to be built. The execution surrounding those choices will become increasingly abundant. The consequences will not. ## Related reading - [The Bottleneck Is Never the Stack](/blog/2026-05-13-the-bottleneck-is-never-the-stack/) - [The Frame Is the Bottleneck](/blog/2026-05-24-the-frame-is-the-bottleneck/) - [Trust the Gate, Not the Actor](/blog/2026-06-14-trust-the-gate-not-the-actor/) - [Everyone Knows You Never Rewrite](/blog/2026-07-17-everyone-knows-you-never-rewrite/) - [Paying for Intelligence Twice](/blog/2026-07-13-paying-for-intelligence-twice/) --- ## Everyone Knows You Never Rewrite - **Published:** 2026-07-17 - **Tags:** ai-economics, ai-strategy, engineering-leadership, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-07-17-everyone-knows-you-never-rewrite/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* Every developer I know keeps the same private tally, and I have been adding to mine for 30 years. The first version of anything you write teaches you the problem. The second teaches you the design. The third is the one you meant to write all along. I learned that the expensive way, by rewriting my own work until it said what I meant. A muddled first pass became a cleaner second, and once in a while I earned a third, the version that comes out close to perfect. The pattern has never failed me, across programming languages, companies, and architectures. And for most of those 30 years, the industry's answer has been firm: you don't get a third version. We even have scripture for this. In April 2000, Joel Spolsky watched Netscape ship the first beta of a browser it had spent almost three years rewriting from scratch. He named the decision ["the single worst strategic mistake that any software company can make."](https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/) There was never a Netscape 5.0, and the market share never came back. His reasoning was airtight. Old code looks ugly because it is dense with hard-won knowledge, and every strange branch may be a bug fix you already paid for. A rewrite trades that learning for years of standing still while competitors move. "Things You Should Never Do" became the restraining order an entire profession served on itself. For a quarter century, when an engineer arrived with a proposal titled "v2 Architecture" and that familiar gleam, my job was to quote Joel and redirect the energy into refactoring. Here is the uncomfortable part: I was enforcing a rule my own tally argued against, and the rule was right anyway. For 26 years, the economics kept it that way. Then the price changed. ## Why we lived in version 1.5 The rewrite taboo was never really about code quality. It was about economics, and underneath the economics sat a problem older than software: we cannot fully say what we mean before we see it. Requirements change because working software is how human beings discover their own intent. You show someone the thing they asked for, and only then do they learn what they wanted. Agile survived by shortening the distance between a statement of intent and the software that tests it. Every delta between what we built and what we meant got a polite name: technical debt. Strip away the euphemism and much legacy code is fossilized misunderstanding, wrapped in the patches that made it survivable. Some reflects rational tradeoffs made under old constraints. All of it carries accumulated behavior, including behavior nobody intended but somebody now depends on. The honest fix was often a third version, written with better knowledge of both the problem and the design. But the industry priced that version at a team-year of frozen roadmap, seasoned with Fred Brooks' second-system effect and a Chesterton's fence 500,000 lines long. Jarred Sumner put the consequence plainly in his own postmortem: until very recently, [choosing a programming language was a one-way decision](https://bun.com/blog/bun-in-rust) for a project of real size. I wrote a book arguing that [the bottleneck is never the stack](https://vinny.dev/book/); it is our ability to express intent. The rewrite taboo was that bottleneck wearing a price tag. We did not refuse third versions because we did not want them. We refused because we had no affordable way to prove that a new implementation still meant everything the old one had learned. ## Eleven days in May On July 8, Sumner published the postmortem of [rewriting Bun from Zig to Rust](https://bun.com/blog/bun-in-rust). Bun is not a toy. It is a JavaScript runtime, bundler, test runner, and package manager whose CLI sees more than 22 million downloads a month. Its 535,496 lines of Zig took five years to accumulate. The disclosure sits at the top of his post, and it belongs at the top of mine. Anthropic acquired Bun in December 2025, Sumner and the Bun team work at Anthropic, and the rewrite ran on a pre-release Claude model. Read every number that follows with that in mind. I did. The numbers still land. One engineer, monitoring about 50 dynamic workflows in Claude Code, ported all 1,448 Zig files to Rust in 11 days. The branch ran from May 3 to a merged pull request on May 14. The run produced 6,502 commits and a final diff of just over 1 million lines. At peak, four worktrees each ran 16 Claude agents, roughly 64 in parallel, writing about 1,300 lines per minute. The compute came to around $165,000 at API pricing, a modeled figure rather than an invoice, since the model's owner also owns Bun. Sumner estimated that a conventional rewrite would have required three engineers with full context for about a year, during which they could fix no bugs and ship no features. The manual version would never have been approved. The realistic alternative was to keep patching forever. Sumner did not prompt Claude to rewrite Bun and hope for the best. He spent three hours defining how Zig patterns and types should map into Rust, serialized the decisions into a porting guide, and created a separately reviewed map of struct lifetimes. He tested the method on three files before committing to all 1,448. He paired every implementing agent with two adversarial reviewers in separate context windows. The reviewers saw the diff, not the implementer's reasoning, with instructions to assume the code was wrong. The Claude that writes the code wants to merge it; the Claude that reviews it wants to find the flaw. That is the same bias split we manage in human teams, engineered into the loop. When agents started running git stash over each other's work, he changed the workflow rules rather than hand-fixing the damage. When compilation broke, roughly 16,000 compiler errors became a literal work queue, divided among the agents crate by crate. He corrected process defects at the source instead of repairing outputs one at a time. Two days after the first CI run, the failing test files had dropped from 972 to 23. Three days later, all six platforms went green. My favorite detail in the writeup is a bug, because it is exactly the kind of bug a 30-year developer feels in their spine. Zig's `assert` is a function, so its argument runs in every build. Rust's `debug_assert!` is a macro, and release builds erase the entire expression. The port translated one into the other faithfully, and an insert into the hot-reload graph vanished from release builds. Hot module reloading broke in production while working perfectly in debug. The two snippets read as twins and behave as strangers. That bug class is why the rewrite introduced 19 known regressions, each since fixed, and why the honest version of this story includes them. The early results are substantial. The Bun v1.4.0 canary fixes 128 bugs that still reproduce in v1.3.14. In a benchmark that rebuilds a project 2,000 times, memory levels off at 609 MB instead of reaching 6,745 MB. Binaries are about 20% smaller on Linux and Windows, and measured workloads run 2% to 5% faster. About 4% of the Rust sits in `unsafe` blocks, mostly single-line calls into C libraries, with 11 rounds of security review and around-the-clock fuzzing layered on since the merge. The strongest evidence is quieter. Claude Code has shipped on the Rust port since mid-June, its Linux startup got 10% faster, and almost nobody noticed. That is what a successful rewrite is supposed to feel like. Not everyone applauded. Andrew Kelley, Zig's creator, published a [blunt response](https://andrewkelley.me/post/my-thoughts-bun-rust-rewrite.html) arguing that Bun's stability problems came from engineering practices rather than from Zig. He also argued that the announcement doubled as marketing for Bun's new owner. I will come back to him, because he deserves better than a dismissal. The 11-day number gets the attention. The test suite explains why it worked. ## The oracle, not the model *A conformance suite is intent made executable.* That sentence is the whole essay, so let me earn it. Bun's rewrite was possible because its test suite happened to be written in TypeScript, which means the tests never cared what language sat underneath them. On the day the port merged, 1.39 million `expect()` calls across roughly 60,000 tests passed, with zero tests skipped or deleted. Five years of user bug reports, edge cases, and 3 a.m. fixes had been continuously converted into executable statements of what Bun means. The agents did not have to rediscover that intent. They inherited it. > In software testing, an oracle is the mechanism that tells you whether a test passed or failed. Put another way, it’s the source of truth that determines the expected result for a given input. A test without an oracle is just an execution. An oracle turns execution into verification. Postgres publishes its oracle outright: a regression suite whose expected outputs encode four decades of corner cases. SQLite, the most rigorously tested database in the world, keeps its deepest suite private. Hold that thought; it is about to matter. This is my book's thesis meeting the news cycle. The constraint on software was never the stack, and it turns out it was never simply the labor either. It was our ability to express intent in a form that survives translation. Specifications do this for the software we are about to build. I have argued that [the spec is the product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/). Conformance suites do it for software we have already built. Schemas, API contracts, production traces, operational telemetry, and formal models can all contribute, but the test suite is usually the richest executable specification a team already owns. Every test your team wrote was tuition converted into transferable knowledge. The exchange rate just moved dramatically in your favor. ## A pattern, not an anecdote If Bun were the only data point, this essay would be a press release with extra steps. It is not the only data point. Earlier this month, a database engineer named Michael Malis announced [pgrust](https://github.com/malisper/pgrust): a Rust rewrite of Postgres, built with collaborator Jason Seibel and a fleet of coding agents. It matches Postgres's expected output across all 46,000-plus queries of the version 18.3 regression suite, passes the isolation tests, and can boot from an existing Postgres data directory. This week Malis published [the honest version of how](https://malisper.me/how-pgrust-was-built-four-attempts-to-rewrite-postgres-in-rust-with-ai/): four attempts over three months, about $100,000 of agent compute by his own accounting, and a graveyard of instructive failures. An early attempt rebuilt Postgres feature by feature from scratch. It reached 96% of the test suite and then died of what Malis calls organ transplant failure. The internals were subtly the wrong shape, in ways no single test revealed until the hardest subsystem rejected them. The attempt that worked went the other direction. A mechanical transpile of Postgres's C into ugly, unsafe Rust passed the full regression suite almost immediately. It then became the base for months of crate-by-crate refinement into idiomatic Rust. His README states the strategy in eight words I would frame on a wall: ["keep the real Postgres tests as the oracle."](https://github.com/malisper/pgrust) He is equally plain about the caveats: the public version is v0.1, it is not production ready, existing Postgres extensions are not generally compatible yet, and by his own measurement it runs about 8x slower than Postgres. Malis says a faster fifth attempt is in development, but it is not yet available for independent scrutiny. Meanwhile, [Turso has been rewriting SQLite in Rust](https://turso.tech/blog/introducing-limbo-a-complete-rewrite-of-sqlite-in-rust) since the end of 2024, with a company behind it and none of the 11-day drama. Turso originally chose to fork SQLite rather than rewrite it, precisely because of the lead time a rewrite demanded. When the team committed to the rewrite, it confronted the fact I asked you to hold: there was no public oracle to inherit. So Turso [built its own verification universe](https://turso.tech/blog/turso-the-next-evolution-of-sqlite): deterministic simulation testing designed in from day one, a partnership with Antithesis to inject faults under a deterministic hypervisor, and public fuzzing against SQLite's own bytecode output. A year and a half in, the engine remains in beta, and the maintainers say plainly that it is not yet production ready. That is not failure. It is the visible cost of building the oracle while building the product. Line the three up and the pattern sharpens. Bun had the owner, a faithful translation strategy, and an exceptional oracle, and it reached production workloads in weeks. Two outsiders with a public oracle and honest limits produced pgrust, a compatible but immature v0.1. Turso had an experienced company and no inheritable oracle, and it has spent years building the verification SQLite never published. What separates the projects is not whether a massive rewrite is technically possible. It is who owns the target, how stable the interfaces are, how rigorous the process is, and, above everything else, whether a trustworthy oracle exists. ## The queue forming in open source Once you see the selection function, you can predict where the economics move first: systems with high memory-safety pain, broad usage, stable behavior, and a public oracle to port against. Some of it has already shipped through largely human effort. Ubuntu made sudo-rs [the default in 25.10](https://www.phoronix.com/news/Ubuntu--Now-Default-sudo-rs), and its 26.04 LTS [runs Rust coreutils as the default](https://www.turbogeek.co.uk/rust-coreutils-sudo-rs-ubuntu-26-04/). Memory-safe rewrites of the most-executed commands on Earth just entered a release supported for over a decade. The traditional implementations remain available for compatibility and fallback. Those ports took years, which is exactly what makes them the baseline the new economics gets measured against. DARPA saw this coming before the tooling existed. Its [TRACTOR program](https://www.darpa.mil/research/programs/translating-all-c-to-rust) exists to automate translating legacy C into Rust using software analysis and machine learning, including large language models. The program's premise is blunt: manual translation takes years and costs sums nobody will approve. The obvious candidates are the C libraries that parse untrusted input for a living: TLS stacks, image and media codecs, compression and archive formats. They carry the industry's scar tissue, most of them have serious public test suites, and every one of them just became portable in the sense this essay cares about. I will not pretend to know which project goes next, and some maintainers will oppose these rewrites on principled grounds. But I no longer bet against the selection function. ## The enterprise estate This is the section I am most qualified to write. I have spent the last eight years leading cloud and platform engineering at a Fortune 100 financial services company. That means I have spent eight years in rooms where someone eventually says, "We can't touch that system." That sentence has been load-bearing in enterprise IT for decades, and it is starting to expire, but not for the reason the demos imply. The enterprise legacy estate makes Bun look like a weekend project: COBOL and PL/I batch systems older than their operators' careers, Java monoliths from the early 2000s, and integration layers nobody fully maps. Estimates of how much COBOL still runs in production vary so widely that the honest summary is that nobody knows, and it is enormous. Enterprise rewrites have failed harder than open-source ones for a reason beyond cost. Open-source projects at least have tests. The typical legacy system's only complete specification is its own running behavior. The documentation drifted, the authors retired, and Hyrum's Law operates at full strength. Somewhere downstream, a process depends on the exact side effects of the 2 a.m. batch job, and nobody wrote that down. There is no oracle. There is only the fence, with no record of why it was built. So the enterprise lesson is emphatically not "point agents at the COBOL." Read the Bun, pgrust, and Turso stories again and the sequence becomes clear: the oracle came first, and each port succeeded to the degree its oracle deserved trust. For a legacy estate, that inverts the modernization playbook. Step one is archaeology: characterization tests that pin down what the system does today, golden files from production runs, shadow traffic, and differential testing between old and new. Record the contracts that exist in production, not only the contracts somebody remembers intending. That work used to be the unaffordable prerequisite buried inside every failed modernization program. The quieter story of 2026 is that the same agents that write the port can help build the characterization tests. Oracle construction itself just became cheaper, and that, more than any porting demo, changes the enterprise math. Three consequences follow for leaders. First, modernization portfolios deserve a re-estimate. A five-year systems-integrator program carries assumptions about translation labor that may no longer hold, and your vendors know it. The conversation should shift from bodies per month to behavior captured, oracles built, risk retired, and evidence produced. Second, the bottleneck moves from writing capacity to verification capacity. In a regulated industry, the real work of an agentic rewrite is provenance, security review, audit trails, operational resilience, and the human judgment that decides what "matches" means. Fund the reviewers and the gates, not just the generation. I have made this argument before about daily delivery, and a rewrite is that argument at maximum intensity: [trust the gate, not the actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/). Third, you can begin to score the estate. Rewrite readiness is oracle quality multiplied by interface stability multiplied by owner commitment, and anything multiplied by zero is zero. That little formula will not survive contact with an architecture review board unmodified, but it will start the right fight. ## The skeptic gets the floor Four objections deserve better than a paragraph of hand-waving, so here they are with my honest answers. Passing tests is not correctness. True, and Bun proves it against itself. Nineteen regressions slipped through 1.39 million assertions, including code that looked nearly identical and behaved differently. Hyrum's Law guarantees the tail exists. The counterargument is not that the tail disappears. It is that human rewrites carry the same tail with less instrumentation, and that the agentic loop fixes the process that produced the bug, not just the bug. Continuous fuzzing, differential testing, production telemetry, and fast rollback create a different posture than hoping the migration team found every hidden dependency. Who maintains a million generated lines? Sumner's answer is that a mechanical port reads like the original, so anyone who understood the Zig can understand the Rust. Malis's failed first attempt is the caution that makes the answer credible: code shaped subtly wrong died because its differences hid where no test looked. Maintainability is a property you select for in the process, not a gift the model hands you. Community and trust do not transfer with the code. This is the sharpest objection, and I have no rebuttal, only a distinction. Postgres is not a codebase. It is a decades-old institution of committers, reviewers, extension authors, operators, and release discipline, and pgrust inherits none of it by passing the tests. A rewrite by a project's owner and a rewrite of someone else's project are different products, whatever the diff says. Bun shipped because Bun's owner did the work and then stood behind it in production. The language was never the problem. Kelley's core argument is that Bun's bugs came from engineering values and practices, and that better discipline in Zig could have improved the system without a million-line rewrite. He is at least half right. Some reported gains came from engineering changes that were not unique to Rust. The rewrite's clearest purchase was moving a class of enforcement from style guides and vigilance into the compiler. Whether that purchase justified the churn is a judgment call, not a law of nature. The marketing gravity matters too. The model's vendor owns the showcase; discount every number accordingly. Three things would change my mind about this essay: Bun v1.4 posting a worse defect rate than the Zig baseline over the next year, oracle-first enterprise pilots losing to incremental modernization on cost and risk, or these generated codebases proving unmaintainable by their second birthday. I will report back either way. ## The taboo was a price tag Return to the tally. The first version teaches you the problem. The second teaches you the design. The third is the one you meant to write, and for my entire career, that third version was a luxury few organizations could justify. Spolsky was right about the risk, and he stayed right while the cost of faithful translation remained prohibitive. AI has now collapsed part of that cost, but only part. What remains is the constraint that mattered all along: saying what we mean in a form a machine can check. The teams that spent years writing tests were not doing chores. They were converting bugs, edge cases, and production scars into institutional memory that survives a change in language, architecture, or implementation. So the leadership agenda writes itself. Audit the estate for oracle quality. Fund conformance suites like the capital assets they are. Price verification, not generation. Re-estimate the modernization programs built on yesterday's labor assumptions. And retire "we can't touch that system" slowly, deliberately, and only as fast as your evidence deserves. Sumner ends his postmortem with a sentence that reads differently depending on your seat: "One engineer can do a lot more today than a year ago." From where I sit, leading a few hundred engineers, it is not really a sentence about the engineer. It is a sentence about the fence between the software we have and the software we meant. For 30 years, the third version was the one we owed ourselves and rarely got to write. That debt just came due, payable in tests. --- **Related reading** - [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [The AI Operating Ledger](https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/) - [The Bottleneck Is Never the Stack, the book](https://vinny.dev/book/) --- ## Paying for Intelligence Twice - **Published:** 2026-07-13 - **Tags:** ai-economics, ai-strategy, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-07-13-paying-for-intelligence-twice/ Every correction you make to an AI system contains a lesson. The question Satya Nadella raised this week is who captures it, who can reuse it, and who gets to keep it. In a [long post on X](https://x.com/satyanadella/article/2076323181154230284), Nadella reached back to Kenneth Arrow's information paradox. Arrow observed that a buyer cannot value information without seeing it, and once they have seen it, they may no longer need to buy it. The seller carries the risk. Patent protection is one conventional response to that tension, letting an inventor disclose an idea without immediately surrendering its commercial value. Nadella argues that AI flips the paradox. Now the buyer carries the risk. To get value from a model, you have to feed it your context: your prompts, your workflows, your standards, and your corrections. The better you want it to perform, the more you reveal. You pay once with money and again with proprietary knowledge, and the second payment may be the larger one. As he puts it, "In consuming intelligence, you are creating intelligence." His conclusion is that what you create should belong to you. ![Two-panel diagram comparing Arrow's information paradox, where the seller discloses knowledge and carries the risk, with the AI-era reversal, where the buyer discloses context and corrections to a model vendor and carries the risk.](/images/blog/2026/07/reverse-information-paradox.png) He is naming something real from a very particular seat. My practitioner's edit is simple: own the learning loop, not necessarily the model. Keep your judgment in portable artifacts that can survive any vendor, runtime, or set of weights. ## The learning exhaust is the asset The sharpest part of Nadella's post is not the Arrow framing. It is the observation about the less visible asset created around the work. That asset is not only the document or database you upload. It is the learning exhaust: the prompts people write, the tools agents call, the eval results they produce, and especially the corrections humans make when a system misses. Those interactions do not automatically retrain a governed enterprise model. But when someone captures and reuses them, they become a compact record of institutional judgment, the kind of knowledge a competitor could never buy and an employee handbook could never fully capture. Generated code can be disposable exhaust. Learning exhaust is different. It records what the organization discovered about what good looks like. *The learning exhaust is not a byproduct of the work. It is the work, compressed.* I have been circling this from the builder's side for months without using Nadella's vocabulary. The [Context Spine](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/), the idea that a versioned spec should travel through the pipeline as the durable artifact, is a learning-loop ownership argument. So is [the claim that the spec is the product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/). When my reviewer agent rejects a pull request against my coding standards document, that rejection encodes a judgment I spent years earning. That standards document is 16 major versions deep, and every version is a correction I made and kept. The uncomfortable question Nadella poses is what happens when those lessons remain trapped in someone else's system, whether or not they train the underlying model. If your accumulated context, evals, traces, and corrections can improve only a vendor-hosted experience, while you cannot export or replay them elsewhere, the asymmetry still compounds in one direction. His phrase for the fix is a trust boundary: a hard perimeter inside which your data, evals, adapted weights, and organizational memory accumulate together. Nothing crosses it without consent. That boundary matters. But the durable asset inside it is not primarily the weight. It is the set of artifacts that encode how your organization judges. ## The five C's, read from the engine room Nadella closes with a framework: Control, Capability, Choice, Cost, and Compound. Frameworks from CEOs usually dissolve on contact with an actual engineering organization. This one mostly survives, so it is worth walking through with a practitioner's eye. Control means owning your evals and your organizational memory, because evals define what good looks like inside your walls. This is the strongest of the five, and it costs the least. An eval is encoded judgment. If you run a platform organization and cannot state, in executable form, what a good deployment, a good pull request, or a good incident response looks like, that gap existed before AI. AI just made it expensive. Capability means building learning environments inside your tenant boundary where models can adapt against real workflows. More on this one in the skeptic's section, because it is where the framework and the median enterprise part ways. Choice is the question I would put on every AI vendor review from now on. If the model you depend on vanished tomorrow, would your capability survive, or was it living in the vendor's weights? I do not have to imagine this test. A government directive [forced Anthropic's newest models offline in June](https://vinny.dev/blog/2026-06-13-the-kill-switch-was-always-there/). The shutdown was temporary, but temporary was enough to make the dependency visible. The organizations best positioned to adapt were the ones that kept their judgment in specs, standards, and gates rather than in a particular model's behavior. Portability got them out. Verification got them out safely. Cost follows from Choice. A decoupled orchestration layer lets you route work to the cheapest model that clears your quality bar. That only works if the bar exists independently of any model. I spent June [itemizing exactly this](https://vinny.dev/blog/2026-06-15-the-subsidy-itemized/): the subsidy math works in your favor only when you can measure verified outcomes rather than tokens. Compound is the payoff claim. Wire the first four together and you get a continuous learning loop that appreciates. This is the right ambition, and it is also where I want to slow the sales pitch down. ## The skeptic's section Consider the incentive. Nadella leads one of the world's largest AI infrastructure vendors, and his prescription naturally expands the role of enterprise learning infrastructure. The post also takes a clean shot at frontier labs that train on public data under fair use, then restrict distillation of their outputs. That critique is fair, and it is convenient for Microsoft's competitive position. Neither point makes the argument wrong. They do mean we should separate the durable principle from the product architecture that happens to benefit Microsoft. Three edits from the engine room. First, the leakage claim overstates the mechanics of governed enterprise use. [OpenAI](https://openai.com/enterprise-privacy/), [Anthropic](https://privacy.claude.com/en/articles/7996868-is-my-data-used-for-model-training), [Google Cloud](https://cloud.google.com/terms/service-terms), and [Microsoft](https://learn.microsoft.com/en-us/azure/foundry/responsible-ai/openai/data-privacy) all state that business customer inputs and outputs are not used to train shared or foundation models by default, or without permission. Consumer products and unmanaged accounts are a different story. Retention, logging, abuse monitoring, feedback settings, and product-specific exceptions still matter. For most governed enterprises, the larger strategic risk is that accumulated context, prompts, evals, and workflow adaptations cannot leave with them. That is more often a dependency problem than a theft problem, and the remedies differ. You do not solve dependency only with a bigger wall. You solve it with portable artifacts. No-training terms keep customer data out of shared-model training; portable artifacts protect choice; evals and standards let the learning compound. ![Diagram of the portability test: a trust boundary containing specs, evals, prompts, agent traces, correction history, and standards labeled yours and portable, next to a dashed vendor-side box containing weights, runtime, and infrastructure, connected by consent arrows.](/images/blog/2026/07/trust-boundary-portability-test.png) Second, the Capability pillar assumes an organization that should operate a proprietary tuning loop. Some should. Most should not. Building one means owning eval infrastructure, data pipelines, model operations, and the specialists who keep all three honest. For most enterprises, owning the evals, prompts, traces, specs, and correction history captures most of the durable value without turning model training into a new platform business. The learning exhaust matters more than the engine. Third, the framework quietly assumes the hard part is infrastructure. It is not. The hard part is having judgment worth compounding. An organization that cannot articulate its standards gains nothing from a private learning loop, because the loop has nothing useful to learn from. [Gates beat actors](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) only when someone has done the unglamorous work of encoding what the gate should check. Nadella quotes Alex Karp saying technical customers want "control over their compute, their models, their data stack, and their alpha." True. But most organizations have not yet written their alpha down. That is the bottleneck, and it is not the stack. ## What I would do Monday morning Three moves, none of which require a platform purchase. Inventory your learning exhaust. Find out where your prompts, agent traces, corrections, and eval results live today. In most organizations, the honest answer is scattered across individual laptops, chat histories, source repositories, and vendor dashboards they do not control. You cannot own what you cannot locate. Write your first private eval this week. Skip the framework and the program. Write one executable definition of what good looks like for one workflow that matters. My [reviewer gate started as exactly this](https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/): a single checklist that hardened into an agent. Evals compound the same way standards documents do, one earned correction at a time. Put a portability test in every AI vendor review. Ask one question: if we walked away in 90 days, what walks with us? Score the answer in artifacts, not assurances. Specs, evals, prompts, traces, and correction histories in formats you can export are stronger than assurances alone. Contracts still matter, but portable artifacts make the promise operational. ## Keep your own lessons Nadella is right that, in the AI era, enterprises accumulate learning the way they once accumulated data, and that the boundary protecting it has to evolve. Where I would sharpen his conclusion is on what sits inside that boundary. The answer is not primarily weights or infrastructure. It is judgment, written down in forms that survive any vendor: specs, standards, evals, and the corrections that improve them. A company should be able to use a model without giving up what makes it unique. It turns out the way to do that is the same discipline that was always required. The bottleneck was never the stack, and it is not the model either. It is the ability to turn judgment into portable, executable artifacts. The learning loop compounds for whoever writes the lesson down in a form the next model can use. ## Related reading - [The AI Operating Ledger](https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/) - [The Subsidy, Itemized](https://vinny.dev/blog/2026-06-15-the-subsidy-itemized/) - [The Kill Switch Was Always There](https://vinny.dev/blog/2026-06-13-the-kill-switch-was-always-there/) - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [The Agentic SDLC: Uniting the AI Tool Sprawl](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) --- ## Two Gates and a Night Shift - **Published:** 2026-07-06 - **Tags:** agentic-sdlc, spec-driven-development, engineering-leadership - **URL:** https://vinny.dev/blog/2026-07-06-two-gates-and-a-night-shift/ *This essay is part of an ongoing series on how enterprise software delivery changes when agents become participants in the engineering system. The series starts with [Your Platform Has a New User: The Agent](https://vinny.dev/blog/2026-08-13-your-platform-has-a-new-user-the-agent/).* Two explicit approval gates. That is my entire footprint in my personal delivery pipeline now. I approve the plan before any meaningful code exists, and I approve the release after I have tested the running preview. Both approvals arrive on my phone. Everything in between belongs to Claude agents and a CI pipeline that treats my laptop as an untrusted actor, which is exactly how I want it treated. This essay documents how the pipeline works, why the two gates sit where they do, and what running it has taught me about where engineering judgment lives. Fair warning: the interesting part is not the automation. The interesting part is what the automation exposed. ## The pipeline, end to end Every change starts as a GitHub issue created from a template that mirrors the agents' planning spec. The template requires acceptance criteria, constraints, out-of-scope notes, rollback considerations, and a risk label: docs, chore, feature, or risky. The issue is the contract, and the template keeps me honest about writing it like a spec rather than a sticky note. A vague issue produces a plausible plan for the wrong problem, so the template raises the floor before an agent ever sees the work. A Claude agent runs on my local machine and scans the repository for open issues. When it finds one, it claims the issue and produces an implementation plan against a standard spec. Plan depth follows the risk label. A docs change or dependency bump gets a lightweight plan that is auto-approved and logged for later audit. A feature or risky change gets the full treatment: approach, files touched, test strategy, and open questions. Then the agent stops and waits for me. ![Flowchart of the plan and build phase. A templated GitHub issue with a risk label flows to the builder agent, which drafts a risk-scaled plan. Feature work waits at gate 1 for plan approval via Roci, low-risk changes take a dashed fast lane past the gate, and approved work builds to coding standards.](/images/blog/2026/07/two-gates-plan-and-build.png) That pause is the first gate, and it travels with me. Roci, my Telegram-connected agent, pushes the plan summary to my phone, and I approve, revise, or reject from wherever I am. Approval latency used to be the pipeline's largest hidden cost. An agent that plans in minutes and then waits hours for a human at a desk is not automated in any way that matters. Now the queue moves at the speed of a glance. On approval, the agent builds the change under my versioned coding standards, which set test coverage thresholds, style rules, and documentation requirements. The standards define done, not the agent's confidence in its own work. When the build meets the standards, the agent commits, pushes to origin, and opens a pull request. CI deploys the branch to an ephemeral preview environment that lives as long as the PR does. Nothing lands on main directly. A separate reviewer agent then evaluates the pull request alongside CI, and if either finds issues, the work goes back to the builder for fixes. When CI is green and the review is clean, the PR moves to release-ready. It does not merge itself. Roci sends me the preview link, the review summary, and the rollback command. I test the running software, approve the release from my phone, and only then does CI merge and deploy to production. ![Flowchart of the review and ship phase. A pull request deploys a preview environment, a reviewer agent checks the code alongside CI, clean work becomes release-ready, gate 2 approves the deploy after testing the preview, production ships with a pre-staged rollback, and a verify-and-measure step feeds telemetry and audits back into the standards.](/images/blog/2026/07/two-gates-review-and-ship.png) That notification is the second gate, and it is not a rubber stamp on a green checkmark. No rollback path means no approval. Once I approve, CI merges, deploys to production, then runs smoke tests and health checks against the live release. The pipeline proves the deploy worked instead of assuming it did. One honesty note before I go further. The gates, the agents, and the night shift below have been running for a while. The risk tiers, preview environments, and telemetry are this month's additions, and the numbers they produce will get their own essay once they have something to say. Two gates, one pipeline, two human decisions. The gate count is complete, but the cast is not. There is a third agent, and it works nights. ## The night shift Pull requests fail for boring reasons: formatting drift, a lint error, a stale lockfile, a merge conflict with main. Left alone, those failures pile up and steal attention from real work. So at 8 p.m. every night, a scheduled Claude Code routine clocks in and triages them, unattended, with no human approving its steps. The routine scans open pull requests, reproduces each failing check, and sorts it into one of three buckets. Safe classes get repaired on a fresh `claude/` branch, verified locally, and submitted as a fix PR targeting the failing branch. Anything requiring judgment about intent gets a `needs-human` label and a written reason instead of a guess. Everything else gets skipped and logged. I review the escalation queue with my morning coffee, which is the correct pairing. ![Flowchart of the nightly maintenance loop. A scheduled Claude Code run checks a soft-stop label, triages failing checks on open pull requests, and routes each into a fix PR on a claude branch, a needs-human escalation, or a skip. Every run ends with a triage report, and fix PRs re-enter the standard review.](/images/blog/2026/07/two-gates-night-shift.png) The constraints define the role more than the goal does. The routine never merges, never force-pushes, never touches a branch it did not create, and never edits CI, deploy, or security configuration. A failing security scan gets escalated, never patched around. It opens at most three fix PRs per run. Its fixes re-enter the same review the daytime work does, so nothing the night shift produces can reach main on its own. Two details in the routine do outsized work. Before acting, it reads a designated triage issue, and a `triage:paused` label makes it post one line and exit. That gives me a kill switch that requires no code change and no SSH session. After acting, it posts a triage report comparing what it did against its written goal and flags any anomaly itself. An unattended agent that files its own incident report is an agent I can leave alone at night. ## Why the gates sit where they do The placement is not arbitrary. It follows the cost curve of catching a mistake. A bad plan caught at gate one costs minutes. The same bad plan caught after implementation costs hours of agent work, a review cycle, and the awkward realization that the tests faithfully verify the wrong behavior. Plan review is the cheapest quality control in the entire pipeline, so meaningful changes get a mandatory human stop there, and the risk tiers protect that stop from drowning in dependency bumps. A gate that fires on everything eventually gets swiped through on autopilot, and a gate on autopilot is not a gate. Gate two works differently. By the time a change reaches production approval, the pipeline has already proven most of what I need to know. I approved the plan, the standards held, an independent reviewer signed off, and CI passed. The preview environment upgrades my final check from trust to evidence, because I approve software I watched run, not a diff I skimmed. I will happily delegate typing. I will not delegate accountability. Everything between the gates is automated, and everything at the gates is judgment. That single sentence is the whole design. ## Separation of duties, but for agents The control I care most about is one I borrowed from decades of enterprise thinking: the agent that writes the code never approves the code. For a solo developer, separation of duties cannot mean separate people. It has to mean separate powers. The builder cannot merge its own work. The reviewer cannot deploy. The night shift can do neither, and it cannot even push to a branch it did not create. Roci routes my approvals but can never grant one. CI cannot ship without my sign-off, and I cannot bypass the pipeline, because main and production are only reachable through it. Each actor in the system holds exactly one kind of power, which means no single failure, human or agent, can push a change from idea to production alone. This is the same pipeline-first principle I push at work, applied to a fleet of personal projects. The scale is smaller and the stakes are lower, but the discipline is identical. If anything, personal projects need the discipline more, because nobody is watching and the temptation to hot-fix at 11 p.m. is real. I have met that temptation. The pipeline wins the argument every time now, mostly because I removed my ability to lose it. ## The standards are the interface The quiet workhorse of the pipeline is the coding standards document. It is versioned, it is explicit, and it is the interface between my judgment and the agents' execution. When an agent makes a category of mistake, I do not fix the code and move on. I fix the standards, and every future build inherits the correction. Each failure gets paid down once instead of rediscovered forever. Over dozens of revisions, the document has accumulated coverage thresholds, a deviations ledger, and rules born from specific mistakes I never want to review twice. The telemetry keeps this loop honest. Every run records cycle time from issue to production, plan revision rate, review findings per PR, and tokens per merged PR. The metrics tell me where the pipeline drags, and audit findings flow back into the standards the same way mistakes do. The point is not to admire the dashboard. The point is to find the next weak gate before it becomes the next escaped defect. This changed how I think about my own output. My durable artifacts are no longer the code the agents produce. They are the issues, the spec, and the standards. The code is downstream of all three, and its quality is a lagging indicator of theirs. ## The skeptic's objection The fair pushback goes like this: agents wrote the code, an agent from the same model family reviewed it, an agent patched the failures overnight, and the human approved from a phone. Is this a delivery pipeline or a rubber stamp with extra steps? I made the general argument in [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/), and this essay is what that principle looks like as running machinery. I have two honest answers. First, what I review changed rather than disappeared. I no longer read every diff, but I read every meaningful plan, and a plan review catches the errors that matter most: wrong problem, wrong approach, missing edge case, unstated assumption. Diffs hide those errors well. Plans expose them. And gate two now includes hands-on time with the running artifact, which catches the category of problem no diff review ever could. Second, the shared-blind-spot risk is real, and I do not pretend otherwise. The builder, the reviewer, and the night shift share a model family, so a mistake one makes can be a mistake the others miss. My defense is a standing audit. I spot-check roughly one in 10 merged pull requests by hand, including the fast-lane merges and the night shift's fixes. A "chore" that touches auth is not a chore. The audit has teeth. Each agent keeps its privileges only while my spot checks stay clean. If audits start surfacing defects the reviewer missed at any meaningful rate, its release-ready call stops counting and human code review returns. The pipeline earns its autonomy continuously, and it can lose it the same way. ## What the pipeline exposed I built this to move faster, and it does. But the speed is not the lesson. The first surprise is structural. The pipeline turned out not to be a line at all. It is three nested loops running at different cadences. The delivery loop moves an issue to production and runs per change. The maintenance loop runs nightly and keeps the delivery loop unclogged, clearing mechanical failures before they cost me attention. The learning loop runs continuously, feeding telemetry, audit findings, and every escalated mistake back into the standards. Each loop protects the ones it wraps, and the standards sit at the center of all three. The second surprise is personal. Once agents handled planning, building, reviewing, triaging, and verifying, my throughput stopped depending on how fast I could type and started depending entirely on how clearly I could ask. A crisp issue flows through the pipeline in one pass. A fuzzy issue generates a plan revision, a rebuild, and sometimes a quiet conversation with myself about what I wanted. The agents did not remove the hard work. They relocated it upstream, to the part that was always hardest. *The bottleneck was never the stack. It was the clarity of the ask.* That is the operating-model story hiding inside a tooling story. The pipeline is three agents and some YAML, and any developer could assemble a version of it in a weekend. The advantage does not come from the assembly. It comes from writing issues like specs, maintaining standards like a product, and knowing which two decisions should never leave human hands. ## Related reading - [Trust the Gate, Not the Actor](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) - [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) - [Spec, Standards, Specialists: How I Actually Build with AI](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/) - [Pipeline-First Is Not a DevOps Initiative - It's a Culture Shift.](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/) - [The Bottleneck Is Never the Stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/) --- ## The Instrument and the Ledger - **Published:** 2026-07-04 - **Tags:** ai-economics, finops, claude-code, side-projects - **URL:** https://vinny.dev/blog/2026-07-04-the-instrument-and-the-ledger/ In June I itemized the subsidy by hand. Twenty-six days of Claude Code came to $2,556 at API rates against a $200 subscription, a 13x gap I sat with for a couple of weeks and eventually [wrote down](https://vinny.dev/blog/2026-06-15-the-subsidy-itemized/). It was a spreadsheet exercise dressed up as an essay: pull the transcripts, sum the tokens, price them, stare at the number. This month I built the instrument that does it for me. It is called Tycho, and it took an afternoon. Here is the part I keep turning over: it was built by the very thing it measures. I opened an empty repository at 11:20 a.m. By 5:28 p.m. I ran `cargo install` on a tagged v0.2.0 with prebuilt binaries, a Homebrew formula, and a live dashboard. Every one of those six hours was spent driving Claude Code, which is to say every one of those hours is a line in the ledger the tool now reads back to me. I built a meter, and the meter's first reading was the electricity I burned building it. ## The instrument Tycho is `iostat` for AI spend. It reads the JSONL transcripts Claude Code already writes to your disk (read-only, no network, no telemetry) and turns them into the numbers I used to assemble by hand: tokens and cost by day, project, session, and model, plus the one report I care about. Run `tycho cache` and it says something like this: ![The Power of Caching](/images/blog/2026/07/tycho-cache-since-june.png) That is "The Subsidy, Itemized" compressed into a command. The essay took me two weeks. The command takes about half a second. Before trusting the command in public, I pointed it at June alone. Tycho reproduced the hand count from the itemized essay, which is the moment a new instrument earns the right to be believed. ## The six hours were the cheap part The speed is the thing everyone wants to talk about, and it is the least interesting thing that happened. Yes: 5,678 lines of Rust, a language I had never shipped before this week, across five phases, with a live dashboard and a release pipeline, in about the length of a transcontinental flight. Execution got cheap. That is not a surprise; it is the thesis of [the book I wrote](https://vinny.dev/book). *Execution got cheaper. Clarity did not.* What did not get cheap was everything the six hours don't show. Deciding what to measure took longer than writing the code to measure it. The decision was that cache *leverage*, not raw token counts, is the number that matters. So did the rule I set for myself and the agent up front: never invent the schema. Every field we parsed had to be observed in a real transcript first, and where the spec disagreed with reality, reality won and the spec got amended. So did the phased gates: stop at the end of each phase, show me what you learned about the data, wait. So did the small disciplines: no `unwrap()` outside tests, because malformed input is normal input for a tool like this, and boring Rust over clever Rust, every time. None of that got faster. It is the same work it has always been. In April I called this the [Hourglass Inversion](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/#the-hourglass-inversion): for decades, implementation was the narrow neck of the delivery pipeline, and abundance has moved the neck upstream to intent. Tycho is that inversion at the scale of a single afternoon. The wide part of the hourglass took six hours. The neck was everything in the paragraph above. The agent collapsed the distance between a clear intent and a running binary to almost nothing, which only made it more obvious that the clear intent was the whole job. ## What the ledger showed Here is what changed when the itemizing stopped being manual. When you do this by hand, you look once, at the number that shocked you, and then you stop. When the instrument does it continuously, you start seeing the structure underneath. ![Pull quote: Caching is the AI saving its notes on your context so it never starts from scratch. You pay once to write the notes, then pennies on the dollar to read them back.](/images/blog/2026/07/tycho-caching-pull-quote.png) Cache reads were more than 95% of my tokens. I knew that abstractly in June; seeing it every day reframed it. The subsidy is less a flat discount the labs are eating than a caching architecture. Almost everything that feels free is free because a machine is re-reading context it already paid to write. Pull caching out of the math and, as I put it before, the economics go from interesting to *please invite finance to the meeting*. Model routing came next. Tycho has a report for per-model spend, and it surfaced something the single big number hid: two days that cost about the same were the same for opposite reasons. One was a volume day; the other was a price day, with a premium tier quietly costing more than double per token. You cannot see that in a subscription. You can only see it in a ledger that breaks the bill apart. Then the report I didn't expect to need: billing blocks. Claude's limits reset on a rolling five-hour window, so Tycho groups usage into activity-anchored five-hour blocks that mirror the reset. For the block you're currently in, it projects where the cost lands if your rate holds: *$2.05 so far, ~$4.10 projected by 17:00.* That is the difference between reading a ledger and steering by one. You cannot manage a subsidy you cannot see, and you certainly cannot manage it after the window has closed. ## The screen that tells you what it doesn't know The most important thing Tycho reports is what it *can't* be sure of. Output token counts in the transcripts can be mid-stream snapshots, so they undercount. History has a horizon, because Claude Code prunes old transcripts on a schedule. And the flagship number carries a label of its own: the no-cache figure is a modeled ceiling, the same tokens priced uncached at list rates, not a bill anyone would actually have paid. The README says it plainly: these are estimates for trend analysis, not an invoice reconciliation tool. I put that front and center on purpose, because it is the same argument the essays kept circling. Value lives in verified outcomes, not tokens. A tool that reported tokens as if they were truth would be a vanity metric in a monospace font. A tool that tells you where its own numbers get soft is doing the one thing that makes measurement worth anything: being honest about the gap between what it counted and what actually happened. That honesty isn't a feature I bolted on. It is the entire reason to trust the meter. The ledger has an hourglass shape of its own. It meters the wide end, execution, the tokens that got abundant, and it does that job well. The neck never shows up. No report captures the two weeks of sitting with June's number, or the decision that leverage, not volume, was the figure worth building around. The most expensive part of the build is the part the meter cannot see, and that is one more reason Tycho is an instrument, not a scoreboard. ## Portability when the stop comes There is a line in the itemized essay I have not been able to shake. Mid-month, a model I had been leaning on, Fable 5, was suspended by an export-control directive. Four days of work, $841, and then it was simply gone. The scariest variable, I wrote, is whether the thing you depend on is still there when the work needs to continue. I built Tycho as though that were a design requirement, because it is. It makes no network calls. It sends no telemetry, ever. It reads files that already live on your machine, prices them from a table embedded in the binary, and it does not care which model wrote them; an unpriced model just shows up in `doctor` and costs nothing until you say otherwise. When a model vanishes, or a lab changes its pricing the week before an IPO, or the subsidy quietly ends, the ledger doesn't go dark with it. You still own the record of what you spent and what you got back. *Portability when the stop comes* isn't a tagline. It is `read-only`, and `no network`, and *your files, your disk*. ## Read your own meter So here is the recursion, resolved. I used the subsidized thing to build the instrument that measures the subsidy, and building it in an afternoon proved the point the instrument then let me watch every day: the code was never the scarce resource. Execution is cheap now, and getting cheaper. What stays expensive, and what you own, is knowing what to measure, being honest about what you measured, and holding the record when the thing you depended on walks out the door. The meter is open source, MIT, built in an afternoon by the thing it measures. If you are burning tokens the way I am, you ought to be able to read your own bill. June's essay ended with the same three words, back when following them meant a spreadsheet and two weeks. Now they fit in a command. Read your own meter. --- *Tycho lives at [github.com/vscarpenter/tycho-cli](https://github.com/vscarpenter/tycho-cli), with prebuilt binaries for macOS, Linux, and Windows shipping with each release. ["The Subsidy and the Severance"](https://vinny.dev/blog/2026-06-02-the-subsidy-and-the-severance/) and ["The Subsidy, Itemized"](https://vinny.dev/blog/2026-06-15-the-subsidy-itemized/) are the earlier ledger. ["The Agentic SDLC"](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) named the inversion. [The Bottleneck Is Never the Stack](https://vinny.dev/book) is the longer argument.* --- ## Barometer: I Chased a New Primitive. I Was Standing on It. - **Published:** 2026-07-01 - **Tags:** aws, cloud, agentic-sdlc, side-projects - **URL:** https://vinny.dev/blog/2026-07-01-barometer-internet-weather-station/ My friend [Zac Wagle](https://www.linkedin.com/in/zac-wagle/) asked me a deceptively simple question: is the internet healthy right now? Not "is my app down." Not "is AWS having a bad day." Not the entire internet in the literal sense, because no one gets that from a side project with a Lambda bill. The practical version: are the major cloud providers, the DNS layer, network services, and AI APIs we all quietly depend on working the way they are supposed to? Nobody could answer that at a glance. You would have to open a dozen status pages, squint at a dozen dashboards that each define "degraded" differently, and assemble the picture in your head. That is a terrible way to answer a simple question, so I built something to answer it for me. Meet [Barometer](https://barometer.vinny.dev/), a weather station for the internet. It is open source, it runs for a few dollars a month, and the story of building it is really a story about mistaking the shiny new thing for the point. ## Leaning into the metaphor Once Zac planted the idea, the weather analogy showed up and refused to leave. A barometer does not predict the future. It reads the pressure right now and lets you infer what is coming. That is exactly the job here. Read the public status of major cloud, network, and AI providers every five minutes, normalize the noise into one number, and answer one question at a glance. Is the internet's pressure holding steady, or is a storm rolling in? The metaphor did more work than I expected. It gave the project a personality instead of just a dashboard. This is not "Provider Status Aggregator 3000." It is a barometer. You glance at it the way you glance at the sky before deciding whether to grab a jacket. ## What I thought I was building it to learn Here is where I have to be honest with you, because you would catch me if I were not. AWS announced [Lambda MicroVMs](https://aws.amazon.com/blogs/aws/run-isolated-sandboxes-with-full-lifecycle-control-aws-lambda-introduces-microvms/) on June 22, 2026, a genuinely new serverless primitive. It hands each user or AI session its own Firecracker-isolated environment with a dedicated endpoint, and it can suspend and resume with state intact for up to eight hours. It is built for things like AI coding assistants and interactive sandboxes, where every session needs its own persistent, isolated bubble of compute. I read that announcement, got excited, and told myself Barometer would be my excuse to go learn it. Then I built the thing, and the honest answer arrived. Barometer does not need any of that. There is no user session to isolate and no state to preserve for eight hours, because the whole job runs for a few seconds and exits. A five-minute cron does not need a bubble. It needs a task that runs, finishes, and gets out of the way. So Barometer runs on a plain, boring, `nodejs24.x` Lambda on an EventBridge schedule. And that is when the more interesting realization hit me. ## The thing I actually learned Chasing the new MicroVMs primitive sent me down a Firecracker rabbit hole, and that is where I found the part that mattered. My "boring" scheduled Lambda has been running on Firecracker microVMs this entire time. So has every Lambda function I have ever shipped since 2018. It is not a feature you turn on. It is the ground I was already standing on. AWS did not just ship a new product on June 22. They took a piece of infrastructure that has quietly powered more than 15 trillion invocations a month and exposed it as a new, user-facing primitive. The announcement taught me more about the platform I was already using than about the platform I was chasing. That is a very ["the bottleneck is never the stack"](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/) moment, and I did not have to go looking for it. It found me while I was busy trying to use the shiny new thing on a job that never needed it. *The stack was never the point. The fit between the tool and the problem was.* That same lesson shaped the monitor itself. The architecture did not need to be impressive; it needed to be honest. Once I stopped trying to make the infrastructure interesting, the real design question became simpler and harder: what should this system do when the signal is missing, ambiguous, stale, or contradictory? ## What one five-minute run does I built Barometer end to end in Claude Code, using my usual [spec, plan, execute](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/) loop. Write the spec first, agree on a plan, then let tests drive the implementation instead of vibes. The whole thing is open source under MIT in the [GitHub repo](https://github.com/vscarpenter/Barometer), Terraform included, so you can see exactly how a small serverless job goes together without over-engineering it. Barometer architecture: an EventBridge schedule triggers a single Node 24 Lambda every five minutes. The Lambda reads the providers' public status feeds, normalizes their different formats into one schema, applies the availability and U.S. region rules to produce one overall reading, and writes tiered JSON to a private S3 bucket. CloudFront and Route 53 serve that JSON to a vanilla-TypeScript dashboard, while CloudWatch alarms page an SNS email alert. At a high level, an EventBridge schedule triggers one Node 24 Lambda every five minutes. That single function fetches every provider concurrently, normalizes their very different status formats into one schema, applies the availability and U.S. region rules, and produces a single overall reading. It writes tiered JSON to a private S3 bucket. CloudFront serves those files over HTTPS behind Origin Access Control, with an ACM certificate and a Route 53 custom domain. The vanilla TypeScript dashboard polls the summary file every 60 seconds. A small alert state machine fires SNS email only on real transitions, debounced so a blip does not wake you. CloudWatch alarms watch the watcher. There are no servers, no API Gateway, and no database, because none of that machinery would earn its keep for a five-minute cron. Here is a detail I like. The project currently reads nine public provider status feeds and runs two active DNS probes, one against Cloudflare's 1.1.1.1 and one against Google's 8.8.8.8. A status page is a vendor's self-report. A direct probe measures what is actually happening, so the DNS layer everything else depends on gets its own independent check. A good barometer does not take the sky's word for it. ## A barometer that lies is worse than useless The most dangerous thing a monitoring tool can do is report "all clear" when it cannot see. A false outage wastes your afternoon. A false all-clear lets a real one run unopposed. So the whole engine is built around one rule: every failure resolves to "I do not know," never to a confident wrong answer. That rule shows up everywhere in the code. An adapter that cannot reach a provider's feed does not throw and does not guess. It returns "unknown," and unknown is excluded from the math instead of counted as healthy. A provider with no data in a given window renders as a dash, never a reassuring 100 percent, because a fake 100 percent is exactly the lie I refuse to ship. Planned maintenance is excluded too, so a provider's score is never punished for a window it told us to ignore. The alerting follows the same discipline. A single bad sample does not page anyone. The state machine waits for two, fires only on a real transition, and holds steady through maintenance and unknowns. And when a status feed goes dark, Barometer does not immediately cry outage. It runs a direct health probe first to confirm the provider is down, rather than trusting the absence of a signal. *A monitoring system earns trust by being honest about what it cannot see.* That is the line between an instrument and a decoration. ## The objection I would raise too Here is the fair version of the skeptic's case, because I would raise it too. Status aggregators are not new. Sites that watch other sites' status pages already exist, and I did not invent the category. This is also a personal project with one writer and no real load, so a clean result proves less than a system under pressure would. Both are true. Two responses. The category was never the point. The point was the discipline of the reading: a measurement that fails to "unknown" instead of lying, and an alert that confirms before it fires. Those choices are where the engineering lives, and they matter whether or not the genre is crowded. And the properties that keep a weekend project honest are the same ones that keep a real system honest, which means they matter more under load, not less. A false all-clear is an annoyance on my dashboard and an incident on yours. The single-writer simplicity, the fail-safe reading, and the debounced alerting are not shortcuts I took because the stakes were low. They are the parts I would keep as the stakes rise. ## Try it, break it, tell me what's wrong [Barometer is live](https://barometer.vinny.dev/) if you want to read the internet's pressure right now, and [the code is on GitHub](https://github.com/vscarpenter/Barometer) if you want to see how it fits together or add a provider I missed. Thanks to Zac for the question that started it, because sometimes the best ideas are just a good question someone asks you over coffee. And if there is a lesson buried in here, it is the one I keep relearning. The newest primitive is not the answer to every problem. The answer is the boring, correct fit between the tool and the job, and more often than not, the capability you were chasing was already running underneath you the whole time. --- ## Related reading - [The Bottleneck Is Never the Stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/). The origin of the idea this whole post keeps circling: what constrains delivery is rarely the technology. - [The Subsidy, Itemized](https://vinny.dev/blog/2026-06-15-the-subsidy-itemized/). What a month of Claude Code actually costs, and why value lives in verified outcomes rather than tokens. - [Still in the Code](https://vinny.dev/blog/2026-06-26-still-in-the-code/). Why I lead engineering at a Fortune 100 company and still ship my own software. --- ## Work Is Hard Enough - **Published:** 2026-06-28 - **Tags:** engineering-leadership - **URL:** https://vinny.dev/blog/2026-06-28-work-is-hard-enough/ In my head, I have a tidy model for how my time should work. Thirty percent for people. Thirty percent for the work in flight. Thirty percent for the future. Ten percent for the administrative machinery that keeps the lights on. It's a clean model. It also falls apart almost every week. ![The calendar tells the truth. Not perfectly, but honestly enough](/images/blog/2026/06/work-is-hard-enough-hero.png) The people part runs past 70 percent more often than I expected. The strategy time gets squeezed. The operational work expands because operational work is apparently filled with gas and will occupy whatever container you give it. The administrative work never disappears, because calendars and approvals have not yet developed empathy. For a while, I treated that as a problem with my discipline. I thought I needed to protect the model better, manage my calendar harder, or be more ruthless about where my time went. I now think the model was trying to teach me something about what the work is. People are how the work gets done, and I deliver value through my teams rather than around them. That belief sits underneath everything else I do as a leader. Work is hard enough on its own. We don't need to make it harder by mistreating each other, hiding the truth, making decisions unclear, or forcing people to spend their energy navigating avoidable human friction. The leader's job is not to make hard work feel easy. Most meaningful work is hard for a reason. The leader's job is to remove the extra tax, the avoidable drag that has nothing to do with the difficulty of the work itself. That's the part we can do something about. ## Kindness is not a vibe I try to lead with humanity, humility, and empathy, and I want kindness and respect to be the defaults rather than the exceptions. But I don't mean kindness as a mood, politeness as a substitute for courage, or avoiding conflict because the conversation might get uncomfortable. That version of kindness is delay. The kind of kindness I care about is operational. It shows up in how we run design reviews, how we make decisions, how we give feedback, how we handle disagreement, and how we talk about problems when the work gets tense. Kindness is one of the conditions that allows rigor to work. A team that cannot disagree safely will eventually disagree quietly. Quiet disagreement is where bad decisions go to compound. People nod in the room, hedge in the hallway, and then spend the next six months proving through passive resistance that the decision never really landed. That's expensive, and it's completely avoidable. The kindest thing a leader can do is make reality easier to tell the truth about. That means building a room where people can say, "I think this design is too complicated," or "We are underestimating the migration risk," or "I do not think this plan will survive contact with the teams who have to implement it," without paying a personal tax for saying it. It also means making sure truth doesn't become theater. The point of creating safety is to make the real tradeoffs visible so the team can make a better decision and move. ## Argue clearly, decide once, move together People sometimes hear "kindness" and picture a team that tiptoes around hard conversations. That is not what I mean. The best teams I have been part of argue constantly. They challenge assumptions, poke holes in designs, pressure-test tradeoffs, and push back with conviction. They are honest with each other, and they are sturdy enough to stay that way. The line I care about is simple: pressure belongs on the problem, not the person. A heated design review can be healthy. Two engineers questioning each other's tradeoffs in front of the whole team can be exactly how the team gets sharper. A product leader challenging scope can protect the organization from fantasy planning. An operations leader forcing the group to look at reliability can keep everyone from mistaking optimism for readiness. That's all productive conflict. But the moment the conversation shifts from the work to someone's worth, we've lost the plot. The debate stops improving the decision and starts damaging the system that has to carry the decision forward. So I try to protect the issue and the people at the same time. You can take apart an idea and still treat the person who offered it with complete respect. You can disagree strongly, leave the room with trust intact, and make a hard call without making someone feel small for having argued the other side. Holding those things together is the job. I've always appreciated the idea behind "disagree and commit," because it solves a real leadership problem. Debate cannot run forever. At some point, someone has to make the call, and not everyone will love it. But the phrase only works when both halves are real. If people are expected to commit but were never allowed to meaningfully disagree, that is compliance wearing a nicer jacket. If they are allowed to disagree forever but never expected to commit, nothing is ever really decided and the work drifts. The norm I care about is this: Argue clearly. Decide once. Move together. Argue clearly means we owe each other honest thinking. We don't hide behind vague concerns, passive language, or hallway commentary. We put the real issue on the table. Decide once means the decision becomes clear enough that people know what changed, why it changed, who owns it, and what tradeoff we accepted. Move together means that once the decision is made, we stop relitigating it through side channels. We may still inspect and adapt as reality teaches us more, but we don't quietly undermine the work because our preferred option lost. That is how trust becomes execution. ## People are the work The older I get as a leader, the more convinced I am that people work is the load-bearing part of leadership rather than a softer category of it. I don't ship most of the work myself anymore. I don't personally build the platform, write the migration plan, debug every pipeline, secure every environment, or make every technical tradeoff. My value comes from helping the people who do that work move with more clarity, confidence, and trust. That can sound abstract until you look at where the leverage lives. A one-on-one can prevent a strong engineer from burning out quietly, and a hard coaching conversation can turn a frustrating pattern into a growth moment. A clear decision can save three teams from spending two weeks optimizing for different versions of reality. A well-run debate can surface a risk early enough that it is still cheap to fix. A leader who makes expectations explicit can remove the low-grade anxiety that makes people guess instead of execute. None of that is "extra." It is how strategy becomes real. There is one more part of this that I hold tightly. I push the credit toward the team that did the work and keep the blame for myself, because the wins belong to them and the losses belong to me. That is less about humility than about making it safe for people to take real ownership, since they know a good-faith miss won't be hung around their neck. It's easy to say people are your most important asset. That phrase shows up in nearly every company values deck ever written, usually somewhere between a stock photo of smiling coworkers and a sentence about excellence. Saying it costs nothing. Living it shows up in the calendar. That's where my tidy model keeps losing. Thirty percent for people sounds reasonable until someone is navigating a hard transition, or a team is stuck between competing priorities, or a leader needs coaching through a decision they've never had to make before. Thirty percent sounds reasonable until you realize that the conversation you almost skipped was the one that opened up the next month of progress. So the people time grows, and honestly, I've made peace with that. ## The trap is real There is a trap here, though, and I don't want to pretend otherwise. "People are the work" can become an excuse to live entirely in the urgent and emotionally available part of leadership. A full calendar of one-on-ones can feel virtuous while the future goes unattended. Being available can become a substitute for being clear, and helping can become a way to avoid the harder work of setting direction. That is not the goal. The answer is to make people time carry more of the strategy rather than to spend less of it. Every coaching conversation should connect to the system we're trying to build, and every one-on-one should build ownership instead of dependency. A debate should leave the decision clearer instead of giving everyone room to perform their position. An escalation should teach us something about where the operating model is unclear. A recurring friction point should make us ask whether we are relying too much on heroic effort and not enough on durable defaults. That is the bridge I keep coming back to in my own thinking. Leadership does not scale through willpower, and neither do culture, quality, or trust. If the system requires everyone to be perfectly brave, perfectly patient, perfectly aligned, and perfectly informed every day, the system is poorly designed. People are capable of extraordinary things, but "everyone must be extraordinary all the time" is a wish. The work of leadership is to build the defaults, rituals, and norms that make the right behaviors easier to repeat. That's true in engineering systems, and it's true in human systems. ## Trust is infrastructure I've been writing a lot lately about the idea that the bottleneck in modern software development is shifting. As tools get faster and AI makes more of the mechanical work cheaper, the constraint moves to clarity. That means clarity of intent, of ownership, of tradeoffs, of what good looks like, and of what we will not do. But clarity doesn't survive in a low-trust system. If people don't trust the room, they sand down the truth. If they don't trust leadership, they wait to be told. If they don't trust each other, they protect their own area and call it accountability, and if they don't trust the decision process, they keep lobbying after the decision is supposedly made. That's why I think trust is infrastructure and part of the delivery system. A high-trust team can move faster because less energy leaks out through interpretation, self-protection, and politics. People can say the hard thing sooner, disagree without creating permanent damage, and commit without needing every decision to go their way. They can recover from mistakes without turning every miss into a courtroom drama. A low-trust team pays a tax on everything. Every decision needs more explanation, every disagreement carries more risk, and every mistake creates more theater. Every handoff gets heavier because nobody is fully sure what will happen on the other side. That is drag. And while some complexity is inevitable, drag is optional. ## The calendar tells the truth I still like my 30/30/30/10 model. It reminds me that I owe the organization more than availability. I owe it direction, operating clarity, and attention to the future as well as responsiveness to the present. I also owe it the discipline to avoid becoming the friendly bottleneck who helps everyone and scales nothing. But the model also reminds me that people are where leadership becomes tangible. The calendar tells the truth. Not perfectly, but honestly enough. If I say people matter but never make time for them, they will believe the calendar. If I say debate matters but punish dissent, they will believe the room, and if I say ownership matters but make every decision myself, they will believe the operating model. If I say kindness matters but tolerate disrespect from high performers, they will believe the exception. People listen to what leaders say, but they organize around what leaders permit, reward, and repeat. That is why the small moments matter more than we like to admit: the tone in a hard meeting, the private coaching conversation instead of the public correction, and the willingness to clarify a decision that felt obvious only to the people in the room. None of those moments look very strategic on a calendar. They are. A while back I tried to make all of this explicit. I wrote a [user guide for working with me](https://vinny.dev/user-guide/), a plain statement of how I make decisions, how to disagree with me, how to earn my trust, and what I owe you in return. Writing it down was the point, because beliefs are easy to claim in an essay and a team will hold you to the version you put in writing. ## Work is hard enough The work will stay hard. The systems are complex, the tradeoffs are real, and the decisions rarely arrive with clean edges. Teams will still disagree, priorities will still collide, and good people will still get tired. Plans will still meet reality and discover reality had edits. Leadership does not remove that difficulty, but it can remove the extra tax: the personal friction, the unsafe disagreement, the unclear decision, the hidden assumption, the fear of speaking plainly, and the culture that makes people choose between being honest and being safe. That's why the people time keeps winning on my calendar. Strategy matters, and people are how it becomes real. Work is hard enough. The least we can do is build teams where the hard part is the work itself. --- ## Still in the Code - **Published:** 2026-06-26 - **Tags:** engineering-leadership, ai-coding, side-projects, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-06-26-still-in-the-code/ Somewhere in App Store Connect, a build of mine is sitting in a review queue, and the reviewer assigned to it has no idea that the person who submitted it runs an engineering organization for a living. That is exactly how it should be. The queue does not read org charts. It does not care about your title, your tenure, or the size of the team you lead. It cares whether your app lets people delete their accounts the way the guidelines require, and whether it crashes on a device you have never owned. After 30 years of building software, I still find that clarifying. GSD, short for Get Stuff Done, is now live as a [native app on iPhone, iPad, and Mac](https://gsdtaskmanager.com/), alongside the [web app it started as](https://gsd.vinny.dev/). It is the same calm Eisenhower matrix on every screen, with sync as a choice rather than a default, and your data living on your device until you decide otherwise. I've already written about [how I built the native version](https://vinny.dev/blog/2026-06-18-native-was-the-long-way-around/), in more architectural detail than most people will ever want. That essay was about the discipline inside the build. This one is about what the build did to my judgment. ![GSD's Eisenhower matrix shown side by side on Mac and iPhone, with the four quadrants Do First, Schedule, Delegate, and Eliminate.](/images/blog/2026/06/gsd-matrix-cross-device.png) *The same calm matrix on a Mac and an iPhone. One model, laid out for whatever screen you are on.* The easy reading is that this is a hobby, and that I am dressing it up as professional virtue after the fact. I want to take that objection seriously, because it is a fair one, and I will come back to it. But the honest answer is narrower and more useful. Staying in the code is calibration rather than nostalgia or proof that I can still do the work the teams I lead do every day. It's how I keep my understanding of how software gets made from drifting quietly out of date. In the AI era, a leader's technical judgment expires faster than it used to. Staying close to the code is how you keep your model of the work current enough to make decisions that matter. ## The map is being redrawn For most of my career, model drift was survivable. Knowledge decayed, but slowly enough that a mental model from three or four years ago was still mostly right. You could keep learning, read widely, listen to your teams, and coast on verified intuition without much risk. The map changed, but it did not redraw itself while you were still in the meeting. That grace period is over. The way software gets built is being redrawn in real time, and the redraw is not cosmetic. [Coding agents](https://vinny.dev/blog/2026-04-25-claude-code-build-system/) have changed the shape of the work itself. The bottleneck is moving off of typing and onto the things that were always harder: stating intent precisely, encoding it into boundaries a machine will respect, and verifying the result fast enough to stay honest. I've argued at length that [the bottleneck was never the stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/), and that the constraint now lives in the human framing of a problem rather than the execution of it. I believe that. But there is a difference between believing it from a deck and knowing it from a keyboard. This is what makes "leaders should stay technical" more than a tired slogan in 2026. The test is whether your model of the work reflects the work as it's being done right now, this quarter, with these tools. If the last time you personally shipped something was before agents could carry a real share of the load, then your intuition about velocity, risk, and what a small team can now accomplish is calibrated to a world that no longer exists. And you are setting strategy with it. I didn't want to be that leader. So I went and shipped something the new way, end to end, and paid close attention to where it broke. ## Leading with both hands None of this is new for me. I started building my [first iOS app in 2014](https://vinny.dev/blog/2025-08-10-Reflecting-journey-continous-learning/), when Swift was brand new and most people were still on Objective-C, and it shipped to the App Store. I've been building on the side ever since, one release at a time. A year ago I finally gave the practice a name: leading with both hands. One hand on the work most people associate with my title, the teams, the strategy, the direction. The other hand still on a keyboard, shipping real things, because there is an empathy you only get from debugging your own code at 11 PM, and it keeps you connected to what your teams do every day. I still believe every word of that. But reading it back now, one line stands out as the part I underplayed. I noted, almost in passing, that the half-life of what I knew kept shrinking, and I treated it as a reason to stay curious. I didn't yet see that it was about to become a reason to stay essential. The argument I made last summer was about empathy and humility. The one I'm making here is sharper, and a little less comfortable. The honest part is that I had the signal a year ago and underweighted what it meant. ## Altitude has a cost Every rung up trades contact for context. You gain a wider view and you lose resolution. The work that used to run through your hands now reaches you as a status update, a roll-up, a slide with a green box on it. You stop reading diffs and start reading dashboards. That is the job. A leader who is still personally merging pull requests for a team of 50 isn't leading; they're hovering, and they've become the bottleneck. But the trade is real, and it's easy to pretend it's free. The further you get from the keyboard, the more your sense of how hard something is, how long it should take, and what could go wrong comes from secondhand accounts. You begin to reason about the work from a model of the work. For a while the model is accurate, because you built it yourself, recently, with your own hands. The danger is that the model keeps feeling accurate long after the ground it describes has changed. I have watched capable leaders make confident calls on a mental map that quietly went stale years earlier. They weren't careless; they were running on the most recent version of reality they had personally verified, and they had no signal telling them the version was old. That is the quiet failure mode of seniority. You don't stop knowing things; you stop noticing when what you know expires. Firsthand contact is what keeps that from happening, and now it's less a nice leadership habit than preventive maintenance. Think of it as changing the oil in your judgment before the engine light comes on, which is much cheaper than explaining later why smoke is coming from the roadmap. ## A personal project with real teeth GSD is a good test rig precisely because it isn't a toy, even though it began as one. [It started as a confession](https://vinny.dev/blog/2025-10-09-a-procrastinators-journey/). I'm a procrastinator, I had tried every task app on the market, and like any reasonable engineer I responded to that frustration by building my own. For two years it was a web app that did exactly one job: put every task on the urgent-versus-important grid and make me decide what mattered. What makes it useful as a calibration instrument is that I refused to let it stay trivial. It's open source, so the claims are checkable. [It now ships](https://gsdtaskmanager.com/) on the web, on iPhone, on iPad, and on the Mac, sharing one model across all four. It has optional sync you can self-host, and an MCP server so an AI assistant can read and write tasks under review. None of that was necessary for a personal to-do list. I built it anyway, because the goal was to walk every mile of shipping a real product, including the miles that have nothing to do with writing features. ![GSD's dashboard on Mac and iPhone, showing active and completed counts, a completion-rate streak, a completion-trend chart, and a by-quadrant breakdown.](/images/blog/2026/06/gsd-dashboard-cross-device.png) *Everything beyond the grid lives one layer down: streaks, completion trends, and a by-quadrant view.* A project you control but refuse to keep trivial is the ideal place to feel the current state of the craft. There's no team to negotiate with and no roadmap to defend, so nothing dilutes the signal. But because I held it to a real bar, App Store and all, it still charged me the full price of shipping. That combination, total control and a refusal to cut corners, is what turned a procrastinator's side project into the most honest feedback I get about how building software feels right now. ## Reality does not grade on seniority A status report is an interpretation, and a demo is a curated slice. Shipping is the unedited thing, and it doesn't care who you are. When I took GSD native, the platform handed me a list of realities that no amount of seniority could shortcut. [Guideline 5.1.1(v)](https://vinny.dev/blog/2026-06-18-native-was-the-long-way-around/) turned account deletion into a feature of its own, and to be fair it is the right rule. Export compliance turned every upload into a questionnaire about encryption, and Mac Catalyst, which markets itself as nearly free, grew its own species of bug. ![Detail of GSD's account settings, showing sync status, Sync Now, Sync History, Sign Out, and a red Delete Account control.](/images/blog/2026/06/gsd-delete-account-detail.png) *The in-app account deletion flow that App Store guideline 5.1.1(v) requires, built like any other feature.* My favorite was a sync bug I've come to be oddly fond of. A device whose clock ran slightly fast asked the server for changes since a moment that hadn't happened yet. The server truthfully answered "nothing," and completed tasks quietly vanished between devices. No crash, no error, just data that evaporated. The fix was conceptually one line, and finding it meant staring at the failure on real hardware. You don't get bugs like that in a roll-up. You get them by holding the thing in your hands while it misbehaves. That is ground truth, and it's worth more to my judgment than a quarter of dashboards. Neither the clock nor the review queue cared about my title, and the compiler has never once been impressed by my tenure. That is exactly why I trust what it tells me. ## Thirty years in, a beginner again There is a second thing shipping GSD gave me, and it's less comfortable than ground truth. It made me a beginner again, on purpose. My professional center of gravity is cloud and platform engineering, and that is the domain I have the deepest reflexes in. Native iOS and the Mac are not that domain. Swift and SwiftUI, App Intents, widget timelines, the precise way an iOS extension is memory-constrained, the exception the system throws when you hold a database locked while suspended in the background: most of that sat outside my daily reflexes when I started. So I did the thing I ask the people I lead to do constantly, which is to be bad at something new for long enough to get good at it. I'll be honest about how that feels at 30 years in. Being a novice is uncomfortable in a specific way when you're senior. You are used to competence being your baseline, and beginnerhood asks you to sit in not-knowing, to be slow, to be wrong in front of a problem that does not care about your résumé. The instinct is to retreat to the domains where you're already expert. Resisting that instinct is the entire point. The discomfort is the sensation of learning, and a leader who hasn't felt it recently has quietly stopped. I was learning the new way of building as much as the new platform. I didn't write most of the lines of GSD. I built it with an AI agent, using a rhythm I've written about elsewhere: [spec, then plan, then execute](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/), one verifiable step at a time, with a test suite fast enough to keep both of us honest. Learning to lead an agent well, to be precise about intent and ruthless about boundaries, is its own skill, and it's exactly the skill I'm asking entire teams to develop. I would rather learn its texture on my own project than theorize about it on theirs. ## What the ship brings back All of this would be self-indulgent if it stopped at the App Store, and it doesn't. The reason a busy leader should spend scarce hours shipping real software is that the calibration comes back to work with you, and it changes the quality of your decisions. Start with credibility, the kind you cannot fake. When I sit with a team navigating the [agentic SDLC](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/), I'm reasoning from a project I shipped rather than a conference talk. I have felt where agents are extraordinary leverage and where they are confidently useless, and I have the scars to say which is which. When a vendor tells me their tool makes the boundaries unnecessary, I know from direct experience that an agent respects the boundaries your tooling enforces and ignores the ones that live only in someone's head. I earned that opinion rather than borrowing it, and people can tell the difference. Then there is the calibration of judgment itself. Having just walked the full distance of shipping, my sense of what is hard is current. It changes which vendor claims I believe, how I hear a team's estimate, and how much confidence I place in a demo that hasn't yet met a gate. I'm less likely to wave off a "small" change that is quietly enormous, and less likely to be impressed by the shiny part of a workflow that hides the unglamorous 90 percent. My estimates have fresh ground underneath them. When someone tells me a thing will take two weeks, I have a recently verified model to check that against, not a memory from a version of the work that no longer exists. And there is the part that matters most to me as a servant leader, which is modeling. I can't credibly ask my organization to embrace continuous learning, to sit in the discomfort of new tools, to ship with discipline rather than enthusiasm, if I'm unwilling to do those things myself. Culture is what people watch you do. Shipping GSD is me doing the thing I'm asking for, in public, with my name on it and the same constraints everyone else faces. That is worth more than any number of slides about a growth mindset. ## The objection, taken seriously I promised I would come back to the skeptic, because I would raise the same objection. This project is a privilege. I rebuilt a personal app I fully control, with no deadline, no stakeholders, and no one to answer to but myself. Most engineering doesn't get to take the scenic route, and a clean result from a project of one proves less than it appears to. Worse, a VP of Engineering has genuinely higher-leverage uses of time. Should you not be developing your people, clearing roadblocks, and setting direction, rather than fighting with Mac Catalyst at night? It's a real question, and waving it away would be exactly the kind of hand-waving I just said I distrust. Two honest responses. First, this runs alongside the leadership work and makes it sharper. The hours are modest, and the return is a calibrated model I use in nearly every technical decision I make. That is one of the higher-leverage things I do. Second, the privilege is real, and it isolates the lesson rather than invalidating it. Nobody needs to build a task manager. The point is that contact with the work keeps a leader honest, and a controlled personal project is simply the cleanest place to get that contact. If you have a better way to stay in touch with how software is made this quarter, use it. The method is negotiable. The contact is not. ## Find your own ship I lead engineering at a Fortune 100 company, with 30 years behind me, and I just shipped a task manager to the App Store on three Apple platforms myself. The world didn't need another to-do app, and I wasn't out to prove I still can. I did it because the org chart doesn't ship the app, and the moment I forget that is the moment my judgment starts running on a map of a city that has already been rebuilt around me. The takeaway is the practice. Pick something real, something you control, and hold it to a bar high enough that it charges you the full price of shipping. Then pay attention to where it breaks, because that is the current state of the craft telling you a truth no dashboard will. Learn a tool that makes you a beginner again, and notice how it feels, because that feeling is the one you're asking your teams to live in. A year ago I closed a post much like this one with an invitation: find your way to stay close to the craft, whether through open source, tinkering with models, or just reading your teams' pull requests. I meant it as encouragement. I'm reissuing it now with more urgency, because the menu itself has shifted. Reading PRs is still worth doing, but it's no longer enough on its own. More and more of those PRs are written by agents, and trying to understand that change from the outside is like reviewing a language you have never spoken. The surest way to know what your teams are living is to go live a small version of it yourself. Every leader needs some version of the App Store queue, a place where the title disappears and the work answers back. --- ## Complexity Is Inevitable. Drag Is Optional. - **Published:** 2026-06-22 - **Tags:** engineering-leadership, platform-engineering, cloud, genai, ai-strategy - **URL:** https://vinny.dev/blog/2026-06-22-turning-complexity-into-leverage/ The change that takes you down is rarely the one you were worried about. I've seen versions of this story more than once. It is the dependency upgrade that should have been boring. It passed code review, it passed the test suite, and it shipped on a quiet afternoon behind a routine change ticket. Then a connection pool that nobody had thought about in years exhausted itself under real traffic, a retry storm turned a small hiccup into a brownout, and a few lines of changed configuration took down checkout for the better part of an hour. A postmortem like that can end where most of them do, with a note about the connection pool and a promise to be more careful. The better teams, or at least the teams trying to learn honestly, end it somewhere more useful. If a routine upgrade could do that, the system was telling them they didn't understand how it behaved under stress. So they start breaking it on purpose: injecting the failures they fear into safe environments, running chaos tests until the way the system behaves under pressure is something they have observed rather than something they assume. An organization reaches that fork every time it learns something expensive, and the answer it gives, over and over, is often what separates a company that compounds from one that just accumulates scar tissue. Most enterprises say they want to move faster. Far fewer are honest about what's slowing them down. The drag is the accumulated weight of modern engineering itself rather than one tool, one platform, one architecture decision, or one team you could point to and fix: cloud complexity, security requirements, cost pressure, legacy systems, regulatory expectations, AI upheaval, funding models, decision rights, handoffs, and the stubborn human reality of how work gets done. That last part is the one we like to understate. A modern technology organization is a living system. It carries history and risk, along with old decisions that made sense at the time and new ones that haven't proved themselves yet. It also carries platforms, vendors, operating models, compliance obligations, budget cycles, and talent constraints, and none of it arrives in neat sequence. So when someone tells me, "We just need to simplify," I usually agree with the intent and push back on the framing. That lesson took me a while to learn. Earlier in my career, I treated simplification like the destination: fewer tools, fewer paths, fewer exceptions. Those things can help, but they aren't enough by themselves. A simple system that ignores how the business works doesn't stay simple for long; it moves the complexity somewhere less visible, usually onto the people least able to absorb it. The goal is to make that complexity usable, and that's what I mean by turning complexity into leverage. ## Complexity is inevitable Some complexity exists because the business is genuinely complex. A large enterprise has real obligations. It needs resilience and security, auditability and cost discipline, and systems that can survive failure, scale under demand, and protect a kind of customer trust that takes years to earn and minutes to lose. That complexity is the price of operating at scale, and trying to wish it away is how you end up with systems that are simple and wrong. Other complexity is self-inflicted. Too many bespoke solutions, too many one-off patterns, too many decisions trapped in meetings, too many teams quietly solving the same problem in slightly different ways. Too many temporary exceptions that live long enough to start collecting furniture. That is where complexity stops being the cost of scale and turns into drag. Drag is what you get when teams have to rediscover the same lesson alone, when security shows up as a late-stage review instead of a default path, and when cloud cost becomes visible only after the bill arrives. It's what you get when delivery depends on a few heroic people who know where the bodies are buried, which scripts still work, and which Slack channel has the real answer. That is institutional archaeology where leverage should be, and while archaeology is fascinating, it is not a delivery model. ## Drag is optional Whether complexity slows an organization down comes down to one decision: what kind of complexity are you willing to live with? Because there is a real difference between complexity that creates capability and complexity that creates confusion. A well-designed cloud platform is complicated underneath and makes life simpler for the teams building on top of it. A strong CI/CD system has a lot of moving parts and turns release risk into repeatable flow, and a good operating model uses its structure to clarify decision rights instead of adding one more committee to the calendar. So the problem was never complexity itself, only the unmanaged, unowned kind that leaks upward and sideways and outward until too many teams are paying the tax. And that tax compounds. A team waits for an environment, a release waits for an approval, and a security question waits for someone to interpret it. Meanwhile a cost spike waits for someone to notice, an architecture decision waits for the right forum, and a production incident waits for the one person who still remembers how the system really works. Each delay, on its own, looks perfectly explainable. Taken together, they quietly become the actual operating system of the company. This is why [the bottleneck is rarely the stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/). The bottleneck is the system around the stack. ## Leverage is designed Leverage shows up only when a platform encodes hard-won lessons into defaults that other teams can reuse without paying for the lesson themselves. A platform is an opinionated system of defaults that helps people make better decisions without asking every person to rediscover the same lesson alone. It says: here is the path we trust, here are the guardrails, here is what we already learned so you don't have to learn it the expensive way. That's the shift. Good platforms turn recurring problems into reusable capability. Good operating models turn ambiguity into ownership, good automation turns toil into flow, and good governance turns risk management into a system instead of a scavenger hunt. Good leadership turns intent into something people can act on without needing a meeting every time the work gets real. None of this makes the work magically easier, but it stops the organization from forcing every team to carry the full cognitive load of the enterprise. The platform carries some of that load, the defaults carry some, and the operating model, the culture, and the durable artifacts carry the rest. When those systems work together, a team can move quickly without having to pretend the risk isn't real. A platform is an opinionated system of defaults that helps people make better decisions without asking every person to rediscover the same lesson alone. ## Platforms are how organizations remember One of the most valuable things a platform does is help an organization remember. Every incident teaches something, and so does every migration, every audit finding, every cost surprise, every deployment failure, and every production recovery at two in the morning. The only question is whether that lesson becomes institutional memory or just another war story told by the people who happened to live through it. Organizations under pressure often rely too much on the people who remember. Better ones try to encode what they learned into systems, so the memory outlasts any individual. Chaos testing is the loud version of that. You turn a someday-failure into a rehearsal, so resilience stops depending on whether the person on call happens to remember. Most of the time the encoding is quieter. It's a default that makes the wrong move difficult, a check that runs before anyone has to remember to run it, a guardrail that holds whether or not anyone has seen this particular failure before. That can sound mechanical, but it's deeply human. Encoded memory protects teams from having to be perfect and lowers the bill for heroics. It makes good decisions easier to repeat, and it hands a newer engineer the hard-won judgment of people they may never meet. This is one reason I care so much about platform engineering. At its best, a platform is empathy, encoded. It says: we know this is hard, we know the enterprise has constraints, we know you're trying to ship, so we built a path that carries more of the complexity for you. Good internal platforms absorb complexity so product teams can spend their energy on customers and business outcomes instead. They make responsibility easier to exercise well, and they leave it with the team. ## AI raises the stakes AI raises the stakes on all of this. There is a tempting story going around that AI is about to strip enormous amounts of complexity out of software delivery. In places, it will. It already accelerates coding, summarization, analysis, testing, documentation, support, and migration work in ways that feel significant on a good day. But AI introduces its own kind of complexity, and we should be honest about that too. More output does not automatically mean more progress, and more generated code does not mean better systems. More agents don't mean more accountability either, because accountability lives in the team or the platform that owns the work. A faster path to a pull request does nothing to fix unclear intent, unclear ownership, shaky architecture, or a missing feedback loop. If anything, AI makes those weaknesses louder, because the system around the work now has to keep up with a much faster source of change. I've watched an agent hand me a clean, confident, well-tested pull request that solved the wrong problem. The code was not the issue. The frame was. When generation gets that cheap, the scarce thing is no longer typing the code. It is the judgment that decides whether the work should ship at all, and the only way that judgment scales is to make it explicit and verifiable: written specs the agent works against, [evaluation gates](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/) that run before anything merges, and a [versioned spec that travels with the work](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/) instead of living in a hallway conversation. That's the part the demos skip. So AI raises the premium on engineering leadership. The organizations that get durable value from AI will pair it with clearer intent, stronger platforms, real verification, and an operating model that can absorb the new speed without losing the thread, rather than bolting it onto a messy delivery system and hoping. AI changes the economics of creation without repealing the need for trust. ## The leadership work is making leverage repeatable This is also why technology leadership is mostly about systems rather than tools. Tools matter, and so do architecture, vendors, and talent, but the job of leadership is turning all of it into a system that helps people make better decisions, over and over, without a meeting each time. That means asking a different set of questions. What decisions does this platform take off teams' plates? Can we deploy fast with the controls, observability, and rollback paths that let us sleep? Where does AI improve flow, and where does it demand stronger verification? And [is ownership clear enough](https://vinny.dev/blog/2026-06-06-your-first-ai-reorg-should-be-the-work/) that work can move without a meeting to interpret the org chart? That last one matters more than it looks. Heroics are inspiring in the moment, and they're also a tell. When delivery depends too heavily on exceptional effort, tribal knowledge, or a few indispensable people, you're getting outcomes without getting leverage. Leverage is what you have when the system itself got better because someone did the hard work once and encoded what they learned, so the next team inherits the judgment instead of repeating the struggle. The human goal is to build systems that let talented people spend less energy navigating avoidable friction and more energy doing the work only they can do, without asking them to carry more to get there. In practice, turning complexity into leverage is a set of specific, unglamorous moves: - Build paved roads for the common patterns. Make the well-supported path the obvious one, so teams opt into your best thinking by default instead of reinventing it. - Make the secure default easier than the custom exception. Security wins when the safe path is also the path of least resistance, not a gate bolted on at the end. - Give teams cost visibility early enough to act on it. I've seen focused FinOps work materially change the shape of a cloud bill, and the bigger win was making the number show up while the decision was still being made. A surprise on the monthly bill is a postmortem. A number in the pull request is a decision. - Make small, frequent changes the safe ones. Deployment systems should reward shipping in small increments, because that's what makes rollback boring and risk legible. - Reduce handoffs by clarifying decision rights. Most delay is waiting for someone to be allowed to decide. - Treat documentation, architecture records, specs, tests, runbooks, and dashboards as durable artifacts rather than administrative residue. They're how the judgment survives the people who created it. - Measure platforms by adoption, friction removed, reliability gained, cost avoided, and confidence built. If the scorecard only counts what you launched, you'll keep launching things nobody adopts. The throughline is leadership that understands the technical system and the human system at the same time. In a modern enterprise, those were never two separate systems, and they shape each other every single day. ## The real goal Notice that the goal here was never simplicity for its own sake. Simple can be good, and simple can also be naive, the kind of clean diagram that quietly ignores how the business works. The real goal is clarity: clarity of intent, of ownership, of the path, of the tradeoffs, and of how the work turns into value. Clarity is what makes complexity navigable. That is how an organization moves faster without getting reckless, and how teams scale without drowning in coordination. It's also how engineering stops being a translation layer between strategy and systems and starts being the thing that accelerates the business. ## Complexity is inevitable. Drag is optional. Leverage is designed. Every serious technology organization is going to face complexity, and the only real question is what it does with it. Shaping complexity into leverage is harder and more useful than chasing simplicity as an aesthetic or wearing complexity as a badge of sophistication, and it's the work I keep coming back to. Because the engineering organizations I respect most do not win by pretending their systems are simple. They win by building systems that let people do genuinely complex work, well. --- ## Native Was the Long Way Around. The Stack Wasn't the Point. - **Published:** 2026-06-18 - **Tags:** ios, ai-coding, architecture, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-06-18-native-was-the-long-way-around/ I already had a working app. I rebuilt it anyway. Twice. [GSD](https://gsdtaskmanager.com/), short for Get Stuff Done, started as a web app and ran that way for a couple of years. It did the one job I built it for. Then I wrapped it as a PWA so it would follow me onto my phone, and that worked too, in the way something works when you've decided not to look at it too closely. Then, knowing almost to the hour what it would cost, I tore the mobile experience down to the studs and rebuilt it as a native iOS and Mac app. The obvious version of this story is vanity. The rebuild looks like a platform story, but the platform only changed the surface. What changed the outcome was the discipline underneath. The stack made the experience possible, and the boundaries made it safe. What I'm keeping from it has little to do with Swift or widgets, or with the warm glow of finally belonging on the phone, though I'll admit the glow is pleasant. It's that one person, with an AI agent doing most of the typing, can ship a real product only when the intent is clear, the architecture enforces the rules, and the verification loop is fast enough to keep everyone honest. [The bottleneck was never the stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/). It was whether the product's intent had been encoded into durable boundaries before the speed arrived. ## The web app that grew up GSD is an Eisenhower-matrix task manager. That is the whole premise. Every task gets placed on two axes, urgent and important, and falls into one of four quadrants: do first, schedule, delegate, or eliminate. The job to be done is *decide what matters, then act*, and keep that decision honest as the day changes. I built it for a reason I [confessed a while back](https://vinny.dev/blog/2025-10-09-a-procrastinators-journey/). I'm a procrastinator who had tried every task app under the sun, and none of them was the one. Every app was either a notebook with checkboxes or a project-management cockpit with 40 buttons. I wanted the 2×2 grid to be the entire surface, and everything else to live one layer down: recurrence, subtasks, dependencies, time tracking, analytics, import, and export. Reachable, but never crowding the one question I open the app to answer: what do I work on next? Over two years it grew the way useful software grows. Natural-language capture came first, so I could type a task and let punctuation do the sorting instead of filling out a form. Then came recurring tasks, subtasks, time tracking, smart views, and a dependency graph, so "ship the release" could know it was blocked by "finish the changelog." Import and export followed, because it was my data and I wanted it to stay mine. It was offline-capable, it was fast, and it was the tool I actually used every day. That last part is the trap. When the thing you built is the thing you use, "good enough" stops being a verdict and becomes a habit. ## The PWA was a polite lie I wanted GSD on my phone, and the honest, cheap, responsible answer in 2023 was a Progressive Web App. Add to Home Screen, a service worker for offline, and a manifest so it got an icon and launched without browser chrome. On paper, a native-feeling app for the cost of a config file. It was fine. It was also a polite lie, and the lie lived in the phrase "native-feeling." A PWA can render almost anything a browser can render, which is nearly everything. What it can't do, at least not in the way this app needed, is belong to the phone. The things that make a mobile task manager frictionless are precisely the things that sit deepest in the operating system: - Capture has to be instant, from anywhere. The whole point of an Eisenhower box is to catch a thought before it evaporates. On a real phone that means a Home Screen widget, a Lock Screen widget, a Share Sheet entry so you can throw a link or a selection straight into the inbox, Siri, Shortcuts, Spotlight, and App Intents. With the PWA, capture meant unlock, find the icon, wait for the web view, tap the box, and by then half the thoughts were already gone. Capture can't be a scavenger hunt. - It never stopped feeling ported. Scrolling had the wrong inertia, the keyboard covered the wrong things, and swipe gestures fought the browser's own. Every interaction was a translation, and you could feel the seams. - The platform kept it at arm's length. Web push and badging exist now, and for many apps that's enough, but notification was never GSD's problem. It needed native capture surfaces that felt like part of the system instead of a detour through a browser. In a task manager, those are the product. All of that is the boundary of the medium. A PWA is a website that has been allowed to sit closer to the Home Screen. That is useful, and sometimes it's exactly the right trade. But a task manager you reach for 30 times a day needs to be a citizen of the device. So the question stopped being whether the PWA was good enough. It was good enough, and good enough turned out not to be what I wanted from the tool I rely on most. ## Native, not ported The temptation, once you decide to go native, is to port. Take the web layouts, the web components, and the web mental model, then transliterate them into Swift. It's faster. It's also how you end up with a native app that feels exactly as ported as the PWA did, just compiled. I set one rule before writing a line of the rebuild: *reimagine around the platform, do not transliterate the web.* Concretely, that meant a few non-negotiables. iPhone and iPad are co-equal, first-class targets. iPhone gets a `TabView`, and iPad gets a `NavigationSplitView` with a sidebar and a detail pane. Each is laid out for its own size class rather than scaled until it stops looking wrong. The interactions are iOS interactions: swipe actions on cards, context menus on long-press, drag-and-drop to move a task between quadrants, a ⌘K command palette on the keyboard, widgets, and App Intents. The capture box is always one tap away. The punctuation shorthand does the classifying, with a bang for priority, an asterisk for a subtask, and a `#tag` to file it, so you never touch a form just to add a task. And one principle shaped the architecture more than any other: *privacy is the product, not a setting.* This wasn't a new idea bolted on for the rebuild. The [first web version](https://vinny.dev/blog/2025-10-09-a-procrastinators-journey/) already kept everything local in the browser, with no tracking, no accounts, and no cloud. The promise was there from day one, and every addition since has honored it. The rebuild is where it stopped being a promise and became something the architecture enforces. GSD is offline-first as a correctness constraint. The app is fully usable with no account and no network, and all your data lives on the device. Cloud sync, bidirectional with [the encrypted backend I built for the web app last year](https://vinny.dev/blog/2025-10-26-task-management-to-mcp/), is strictly opt-in, and your data sits behind passphrase-derived keys that I never hold. The UI is never allowed to imply your data has left the device when it hasn't. That is an engineering specification, and it dictated where every byte was allowed to live. ## The dependency direction is the design This part looks like Swift trivia, and it's load-bearing. If you never write a line of Swift, stay with me, because the principle is portable: [enforce your architectural boundaries in tooling](https://vinny.dev/blog/2026-03-28-coding-standards-skill/), so they can't be crossed by anyone. That includes you, and it includes an agent that has no memory of why the boundary exists in the first place. All of GSD's real logic lives in a layered Swift package, `GSDKit`. The app itself and its two extensions are thin shells on top. The layers are ordered, and the order is the design. Each layer is only allowed to depend downward:
GSDKit dependency diagram. The App and Extensions are thin shells on top. GSDSync sits on GSDStore, which holds the database, while GSDSnapshot is a separate GRDB-free path. Every layer depends downward on GSDModel, the zero-dependency foundation.
GSDKit's layered package. The manifest enforces the arrows, so no layer, and no agent, can depend upward.
`GSDModel` is the domain. The `Task`, the four quadrants, the capture parser, the recurrence engine, and the dependency graph live there. It has zero dependencies, enforced by the package manifest, so you physically cannot `import` the database into it. That constraint is the point. The rules of the product cannot get tangled up with how the product is stored. `GSDStore` owns persistence with GRDB and exposes exactly one way to change a task: a single `TaskStore` that every mutation flows through. There is no other path. When anything changes a task, `TaskStore` stamps its `updatedAt` from an injected clock and enqueues it to the sync queue, in that order, every time. A single mutation path sounds like bureaucracy until you realize it's why sync is trustworthy. There is exactly one place where "a thing changed" is true, so there is exactly one place that has to be correct. `GSDSync` is a pure actor. The pull, push, deletion-reconcile, and last-write-wins logic all live there, unit-tested with no network and no simulator. The untestable glue lives up in the app as a separate coordinator: when to sync, watching the network path, and reacting to the app returning to the foreground. The tested core stays pure. The messy timing stays quarantined. `GSDSnapshot` is the quiet hero. It's a GRDB-free contract that the widgets and the Share extension talk to, so the extensions can share real logic with the app without ever pulling the database into their process. An iOS extension is a tight, memory-constrained little thing, and you don't want a full SQLite stack loading inside your Lock Screen widget. The snapshot layer lets the extensions be first-class without being heavy. The fast feedback loop falls out of this for free. Because the logic has no UI and no backend bolted to it, the entire test suite runs in under a second from the command line, with no simulator boot and no build-and-deploy. I could change the recurrence math and know in a second whether I had broken month-end rollover. That speed is what let me move fast without breaking the tool I use every day. The compiler and the package manifest enforce every one of these boundaries, so none of them depend on my good intentions. That distinction is why the next part of the story worked. ## The clock that lied Let me make the architecture concrete with the bug I'm fondest of. It's the kind of bug you only get to have once you're syncing real devices in the real world. Sync is last-write-wins. Two devices edit, the most recent edit wins, and "most recent" is decided by a timestamp. Simple, until you ask the obvious question: *whose clock?* My first cut trusted the device clock and used it to drive the pull cursor, the marker that says "give me everything changed since X." This works perfectly right up until a device's clock is wrong, which devices' clocks routinely are, by seconds or minutes. The failure mode is silent and nasty. If a device thinks it's slightly in the future, it asks the server for changes since a moment that hasn't happened yet. The server truthfully answers "nothing," and pulled changes quietly vanish with no error and no crash. A task you completed on your phone simply never shows up on your iPad, and you have no idea why. The fix is a one-line idea that takes real care to get right: never trust the local clock for the cursor. Advance the pull cursor using the *server's* stamp on each record, not the device's. The server is the only clock all devices agree on, so it's the only clock allowed to decide what "since" means. Once the cursor follows server time, device clock skew can no longer lose a pull. The worst it can do is resolve a single conflict the wrong way, which last-write-wins is allowed to do, instead of silently dropping data, which it is never allowed to do.
Two sequence diagrams. Without the fix, the device uses its own clock of 10:00:05 as the pull cursor, so a record the server stamped at 10:00:00 is never returned and is silently lost. With the fix, the cursor uses the server stamp of 09:59:58, the record is returned, and the cursor advances to server time.
The sync cursor, before and after. Driven by the device clock it silently drops pulls; driven by the server's stamp it cannot.
That is the whole reason the architecture is shaped the way it is. The sync engine is a pure, testable actor specifically so that a subtle, timing-dependent, data-losing bug like this can be reproduced and pinned in a unit test that runs in milliseconds, instead of being chased across two physical devices and a flaky network. There is a native-only sibling to this story I'll spare you the depth of: `0xDEAD10CC`, the exception iOS throws when an app holds a database file locked while suspended in the background. A widget timeline refresh or a background Siri write can wake just enough of your app to touch the database at exactly the wrong moment. The fix is to observe the system suspending the database and back off gracefully. You don't get bugs with names like that on the web. They're the toll you pay for living on the device. ## Spec, plan, execute, on repeat This is where the earlier boundary point becomes practical. I built almost all of this with an AI coding agent, though not the cliché version where the AI writes your app while you watch. What I did was more deliberate, and more interesting. The mistake people make with coding agents is treating them like [a vending machine](https://vinny.dev/blog/2026-04-25-claude-code-build-system/). Describe a feature, receive a feature, paste it in, repeat. That scales to toys and collapses on anything real, because there's no through-line. Every interaction starts from zero, the architecture drifts, and three weeks in you have a pile of plausible code that doesn't cohere. What worked was imposing a rhythm and never breaking it. Every meaningful chunk of GSD went through the same three beats: 1. Spec. Before any code, write down what we're building and why as a [design document](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/): the behavior, the edge cases, and the constraints. The point was shared ground. The agent and I had to agree on what "done" meant before "how" was on the table. 2. Plan. Turn the spec into an ordered implementation plan, with the steps in sequence and each step small enough to verify on its own. 3. Execute. Work the plan one verifiable step at a time, with the sub-second test suite as the gate between steps. To make that concrete, one loop in the commit log looked like this: a commit reading `docs: sync engine design`, then `docs: sync implementation plan`, then a run of `feat:` commits working the plan one step at a time, then a `test:` commit that pinned the clock bug above so it could never come back. Scroll the whole history and you see that shape repeat. Foundations, then the core matrix, then task depth, then filtering and smart views, then the editorial redesign, then sync hardening, then Sign in with Apple, then widgets and Siri, then the Mac port. Each phase had its own small spec, plan, execute loop. Two things made the difference between this being a force multiplier and being a mess generator. The first is that the architecture did the agent's homework for it. Those rigid layer boundaries are good design for humans. They are also guardrails for an agent: the manifest that forbids importing the database into the domain, the single mutation path, and the pure sync actor. When the compiler and the package manifest enforce the rules, an agent can't drift across a boundary it shouldn't cross, no matter how confidently it tries. *The constraints that make the code testable are the same constraints that make it safe to generate.* The second is that I kept a written record of *why*. The code already says *what*. Alongside the code there is a log of the reasoning behind decisions, the reason each file is shaped the way it is. When you come back two months later, or when the agent comes back with no memory of the last session, that log stops you from re-litigating a decision you already made carefully the first time. I want to be precise about my role, because it's easy to mythologize this in either direction. I did not write most of the lines. I also did not get to stop thinking. I wrote the specs, I made the architectural calls, and I caught the clock bug by asking "whose clock?" That is a question rather than a keystroke, and it's the kind of question the whole thing lived or died on. The agent was extraordinary leverage on clear intent and roughly useless without it. It typed faster than I ever could, and it never once decided, on its own, what the product should *be*. If you want one line to take to work on Monday, take this one. An agent respects the boundaries your tooling enforces and ignores the ones that live only in a senior engineer's head. Build the first kind. ## The unglamorous miles The app is the easy part. Shipping it is a long, unglamorous tail, and native makes you walk every step of it. The web app deploys when I push. The native app has to be archived, signed, uploaded, and reviewed, on two platforms, against rules that exist whether or not they make sense for your app. I automated what I could: a release script bumps the version, archives, exports, and uploads to TestFlight for both the iOS and Mac Catalyst builds. Automation removes the typing. It does not remove the requirements. A sampling of the miles, none of which a PWA would have charged me for: - Mac Catalyst. "Universal" sounds free until you build it. The Mac build needed real menu-bar commands, a sensible minimum window size, an About panel, and a careful exclusion of the iOS-only extensions from the Mac target. It also grew its own species of bug, like a web-auth callback that arrives off the main thread through Catalyst's XPC plumbing. - In-app account deletion. App Store guideline 5.1.1(v) is blunt: if a user can create an account, they must be able to delete it from inside the app. So there is now an ordered remote-then-local deletion flow with a confirmation, an entire feature built to satisfy a rule that, to be fair, is the right rule. - Export compliance. Every upload asks whether your app uses non-exempt encryption. For GSD, the answer was no non-exempt encryption, only ordinary HTTPS, and a single Info.plist key tells App Store Connect that, so builds go straight to testing instead of stalling on the same question every time. - A marketing demo, built like software. Even the promo video became a small engineering project: a seeded demo state behind a launch flag, an automated UI test that choreographs each scene, simulator screen recordings, and ffmpeg stitching it into a captioned 16:9 cut. Of course it did. Once you have the discipline, you point it at everything. This is the part of "native, not ported" that doesn't show up in the demo. Belonging to the platform means living by the platform's rules, and there are a lot of them. I knew that going in, and it's part of what I meant by *on purpose*. ## The objection I would raise too Every word of this is about a personal app I control, and that is the objection I would raise myself. No team, no deadline, no stakeholders, no roadmap to negotiate, and full license to overbuild a tool that serves exactly one user. Most engineering doesn't get to take the long way around, and a clean result from a one-person project proves less than it looks like it proves. All of that is true, and I have two responses. First, the native path was the expensive one on purpose, and I knew there were cheaper ones. A cross-platform native framework would have bought back a lot of time. I skipped it because the integrations I cared about most, widgets, Siri, Spotlight, App Intents, and a Share Sheet that feels native, are the ones those frameworks tend to fight hardest. That was a deliberate trade for this specific tool, not a claim that everyone should make it. Second, and this is the part that matters, the thing that generalizes is the discipline rather than the native craft. The constraints that let me move fast alone are the same constraints that keep a team of 50 from drifting, which means they matter more under real deadline pressure, not less. Point an agent at a clean codebase and you get leverage. Point one at a sloppy codebase and you get the leverage to make a bigger mess faster. The part of this project worth copying is the boundaries, the single obvious path, the fast verification loop, and the written record of why. None of those required unlimited time. They are how you make speed safe. ## The slower path, on purpose I had a working app, and I spent months rebuilding the mobile experience from scratch, in a new language, against two platforms' worth of rules, to arrive at software that does the same job the PWA already did. The PWA answered one question: can I use GSD on my phone? Native answered a better one: does GSD belong on my phone? The gap between those two questions is the reason I did it. Capture is now a widget tap or a sentence to Siri, fast enough that the thought survives the act of catching it. The app scrolls and swipes and feels designed for iOS because it was designed for iOS instead of translated into it. My data lives on my device, provably, with sync as a choice I make rather than a default I have to trust. And the same matrix is now at home on a phone, a tablet, and a Mac, each laid out for what it is. Good enough is a trap precisely because it's true. The PWA was good enough, and I rebuilt it natively anyway, because the tool I reach for 30 times a day was worth it. What I have now is a clean, layered, tested core, and proof of how it behaves under an agent. That is the part worth copying, whether or not you ever take the long way around yourself. Look at the boundaries in your own system and ask whether [your tooling enforces them](https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/), or whether you're simply trusting everyone to remember. --- ## Related reading - [The Frame Is the Bottleneck](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/). Why the constraint moves from execution to the human framing of the problem as agents get better at the typing. - [Spec, Standards, Specialists: How I Actually Build with AI](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/). The working loop behind the spec, plan, execute rhythm in this post: a refined spec, a layer of standards, and coordinated specialists. - [Eleven Years, One Week, and an AI Co-Pilot: Rebuilding TravelTimes for iOS](https://vinny.dev/blog/2026-04-12-one-week-with-ai-copilot/). Another long-lived app rebuilt with an agent in a focused sprint, including the parts the agent got wrong. - [Building My Own Productivity Tools: A Procrastinator's Journey](https://vinny.dev/blog/2025-10-09-a-procrastinators-journey/). Where GSD began. A procrastinator's confession, two privacy-first web apps, and the local-only promise this rebuild finally hardened into architecture. - [From Procrastination to Privacy-First Productivity (Part 2)](https://vinny.dev/blog/2025-10-26-task-management-to-mcp/). The middle chapter. GSD gained the optional encrypted cloud sync this native app now uses, plus an MCP server so the tasks could talk to an AI assistant. --- ## The Subsidy, Itemized - **Published:** 2026-06-15 - **Tags:** ai-economics, finops, claude-code, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-06-15-the-subsidy-itemized/ My $200 Claude subscription produced $2,556 of API-priced work in 26 days. That sounds like the story. It was not even the most interesting number. The interesting number was 95.5 percent: the share of every token that came from cache reads. That is the number that explains why my agentic coding habit feels economically rational while the API-priced meter says it should have been alarming. Three weeks ago, in [The Subsidy and the Severance](https://vinny.dev/blog/2026-06-02-the-subsidy-and-the-severance/), I called tokens-consumed a vanity metric. I said the leaderboard era was ending, and good riddance. I compared it to measuring a book by its page count. Then I ran the leaderboard. I used [ccusage](https://github.com/ryoppippi/ccusage), a local CLI that reads Claude Code session logs and prices every token at API rates. It gave me the number I had sworn off, then made that number useful by showing me what sat underneath it. So treat this as the confession and the correction. I still believe token leaderboards are a weak way to measure engineering value. But a bad headline metric can become useful when it pushes you into better questions. What did the work produce? Which model tier did it really need? How much of the economics depended on cache? Could the same workflow survive if the preferred model disappeared? Those are the questions the meter started asking back. ![A 26-day chart of daily Claude Code spend, with model-era bands, weekend markers, and two identical $256 peaks annotated by cause](/images/blog/2026/06/ccusage-spend-ledger.png) *Twenty-six days of Claude Code, priced at API rates. The amber bars are Opus and Sonnet. The coral bars are Fable 5. Watch where the coral stops.* ## The number I swore off Here is what ccusage reported: across 26 days, my Claude Code sessions moved 2.55 billion tokens and would have cost $2,556 at API rates. That number is real, but it is not value. It is counterfactual spend. It tells me I am a heavy user, which I already knew. It does not tell me whether I shipped better software, produced clearer artifacts, improved verification, or avoided meaningful rework. Those are the numbers that matter, and the meter cannot infer them from token flow. The useful part of the report was hiding one layer down. Of those 2.55 billion tokens, 95.5 percent were cache reads. That single fact explains how 2.55 billion tokens blended down to almost exactly $1 per million. Agentic coding does not run on raw context alone. At this volume, it runs on reuse. Take caching away, and the economics change from "interesting" to "please invite finance to the meeting." So the headline number is a vanity number sitting on top of an operating signal. That gap is the story. ## Two thousand five hundred dollars, two hundred paid ccusage prices my work at API list rates. I do not pay list rates. I pay Anthropic $200 a month for the Max 20x plan. The $2,556 is not my bill. It is what those 26 days would have cost if I rented the same compute by the token. Hold the two numbers next to each other. $2,556 of API-priced usage. $200 paid. That is roughly a 13x gap, and it has a name. I have been calling it the subsidy. The run rate makes it sharper. At about $98 a day, my $200 subscription pays for itself in roughly two days. After that, the economics are less my credit card and more Anthropic's product strategy. To be fair, a subsidy is not a scandal by itself. Flat-rate pricing is a product strategy. Vendors use it to build habits, learn workflows, smooth adoption, and make a tool feel safe enough for people to use heavily. That is not sinister. It is normal software economics with larger GPUs behind the curtain. The risk begins when teams build an operating model around that temporary gap and mistake today's adoption pricing for durable unit economics. That is when the subsidy stops being a bargain and starts becoming an architectural assumption. This is where my own essay turns around and points at me. I am not just the observer of The Subsidy and the Severance. I am the power user burning tokens, the one I said leaders should watch carefully. The open question from that piece applies to me directly. Am I the bargain or the bonfire? ccusage cannot answer that. It can only tell me the meter is running fast. Whether the spend bought value is a different question, and it requires a different ledger. ## I was wrong about the weekends I went in with a hypothesis. I assumed my heavy days were weekends, when the day job steps aside and the side projects take over. The data disagreed. My weekday average was $106. My weekend average was $84. Weekdays ran 26 percent hotter. My single biggest day was a Sunday, so the peak was a weekend, but the mass lives Monday through Friday. That is the quiet, useful function of real measurement. It overrules the story you were about to tell. I would have written the weekend version with total confidence, and I would have been wrong. That matters because leaders do this all the time with AI. We explain spend with vibes. We blame the obvious workflow, the loudest team, the newest tool, or the use case we already suspected. Then the data shows that the cost lives somewhere else. The meter does not make the decision for you. It does something almost as useful. It keeps you honest before the narrative hardens. ## Same bill, opposite cause Two days in the set cost almost exactly the same. May 31 cost $256. June 9 cost $256. Identical bill. The bills lied about the cause. May 31 processed 317 million tokens. June 9 processed 102 million. One day cost that much because of volume. The other cost that much because of price. The price story has a name: Fable 5. For four days in June, I ran Anthropic's new top tier. [Anthropic's pricing table](https://platform.claude.com/docs/en/about-claude/pricing) listed Fable at $10 per million input tokens and $50 per million output tokens, exactly twice the $5 and $25 for Opus 4.8. My dashboard ran a little hotter than that list ratio. Across my actual usage mix, a Fable day cost 2.3 times a normal day per token, for work that was not always 2.3 times better. This is where value per token becomes useful, not as a final KPI, but as a diagnostic. Tokens consumed told me both days were a big deal. Cost per token told me one was a volume problem and the other was a pricing decision. Value per outcome would tell me whether either day deserved the spend. That last distinction matters. The question is not whether the premium model is better. It usually is. The question is whether this task needed the premium model, whether the output survived verification, and whether the workflow would degrade gracefully if that tier disappeared. Without those questions, premium model routing becomes a very expensive form of optimism. I am pro-optimism. I am less enthusiastic when it shows up with line-item pricing. ## The kill switch is in this chart Look again at where the coral stops. The Fable bars end on June 12. The next two days are Opus 4.8. If you did not know better, you would call that discipline. You would assume I stared at four straight days of triple-digit spend and got religion. That is not what happened. The chart alone does not prove causation. It only records the red bars ending on a Friday evening. The source explains why. In [Anthropic's access update](https://www.anthropic.com/news/fable-mythos-access), the company said a U.S. export-control directive forced it to suspend Fable 5 and Mythos 5 for foreign nationals. To comply, it disabled both models for everyone. The directive landed Friday, June 12. By that night Fable was gone, and my next two days ran on Opus 4.8 because nothing else was on the menu. My usage chart recorded the business-continuity event as cleanly as it recorded spend. The four-day Fable run cost $841. That is 4.2 times my entire monthly subscription, spent in four days, on one model. Then the model was gone. That is the subsidy and the severance in a single chart. The expensive tier showed me what metered intelligence really costs. The stop showed me that the meter is not even the scariest variable. The scariest variable is whether the thing you depend on is still there when the work needs to continue. ## The metric I want Strip the report down, and the biggest number is not the most important one. $2,556 is appetite, not value. 95.5 percent cache reads is architecture, not trivia. The Fable run is routing discipline, or lack of it. The kill switch is continuity risk, hiding inside what looked like a productivity tool. The metric that survives all four is not value per token by itself. It is value per verified outcome, with token cost as a diagnostic. That is a small wording change with a large operational difference. A cheap model that produces unreviewed garbage is not cheap. An expensive model that saves a week of expert rework may be worth it. A workflow that depends on one inaccessible model may be fast right up until it is not. The outcome has to pass verification, and the workflow has to be portable enough to survive the stop. That is the AI spend ledger I want. | Question | What it protects you from | |---|---| | What verified outcome did this produce? | Confusing activity with value. | | Which model tier did the work really need? | Premium-model sprawl. | | What was the cache-read ratio? | Missing the architecture underneath the economics. | | What did it cost per accepted result? | Optimizing for cheap tokens instead of useful output. | | Could this run on another model tomorrow? | Treating model access as permanent infrastructure. | This is not a call to ban premium models or celebrate cheap subscriptions. It is a call to operate AI like something that matters. Use the powerful model when the work deserves it. Use the cheaper model when the work does not. Use the cache when reuse is real. Verify the output either way. And please do not confuse today's subsidy with tomorrow's business case. ## Read your own meter Here is the corrected confession. I ran the vanity metric, and the vanity metric earned its keep. The dashboard total was theater. The lessons were everywhere else: in the cache ratio, the weekend assumption I got wrong, the twin $256 days with opposite causes, and the gap between $2,556 of API-priced usage and a $200 subscription. The bottleneck was never the stack. It was not the language, the framework, or the cloud. It is not the token price, even now that the meter is finally visible. It is not even the model, which I learned can vanish between Friday dinner and Saturday coffee. The real bottleneck is knowing which work is worth funding, which work deserves the expensive tier, and which work can survive when that tier disappears. That is the AI meter I care about now: value per verified outcome, cost per accepted result, and portability when the stop comes. I intend to keep reading my own meter. The leaders who are serious about agentic software should probably start reading theirs too. --- ### Sources and further reading - [ccusage, the local usage CLI](https://github.com/ryoppippi/ccusage) - [ccusage documentation](https://ccusage.com/) - [The Subsidy and the Severance](https://vinny.dev/blog/2026-06-02-the-subsidy-and-the-severance/) - [The AI Operating Ledger](https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/) - [The Kill Switch Was Always There](https://vinny.dev/blog/2026-06-13-the-kill-switch-was-always-there/) - [Anthropic, Fable and Mythos access update](https://www.anthropic.com/news/fable-mythos-access) - [Anthropic, Claude API pricing](https://platform.claude.com/docs/en/about-claude/pricing) - [AP, on the export-control action](https://apnews.com/article/anthropic-artificial-intelligence-trump-fable-mythos-d9cc7df5c02e93837d0f0bfb24d5cfd2) --- ## Trust the Gate, Not the Actor - **Published:** 2026-06-14 - **Tags:** agentic-sdlc, engineering-leadership, ai-strategy - **URL:** https://vinny.dev/blog/2026-06-14-trust-the-gate-not-the-actor/ The first useful thing my publishing verifier did was embarrass me. Not publicly, thankfully. It caught me before I published a technical claim I had read six times and stopped seeing. I had written a memory requirement for a local model as if it were a simple property of the model itself, instead of something shaped by model size, quantization, context window, runtime, and machine setup. The sentence felt precise because it had a number in it. That's the dangerous part. A number can make a weak claim look like a receipt. The verifier made me choose: source the details cleanly, rewrite the claim with the right constraints, or remove it. I wanted to override the flag because the post was done, the argument was working, and I was tired of sanding the same paragraph. Instead, I checked the claim. The verifier was right. That was annoying, useful, and exactly the point. The uncomfortable part is that the error did not survive because I was careless. It survived because I was the reviewer, and I had already read the sentence too many times. By the third pass, I wasn't really reading anymore. I was recognizing. Every writer knows this failure mode, and every engineering leader has seen the code review version of it: the large pull request that gets a fast approval because the reviewer sees the shape of correctness instead of the details. For years, my defense against shipping something wrong was attention. Mine, or a colleague's. Check the claims. Check the links. Check the structure. Check the metadata. Check the voice. Check whether the whole thing still says what I think it says. That defense was always a process running in someone's head. It was unversioned, undocumented, and enforced only when the reviewer happened to be sharp, caffeinated, and not rushing to hit publish before a Monday morning meeting. So I did what I would do with any process that fails under load. I stopped trusting the human to run it perfectly and encoded the judgment into a gate. I built a verifier that reviews every post before it ships. This post went through it too. *Proof of Work is a series where I build the argument instead of only making it. Each post documents something I shipped, what broke along the way, and what it taught me about how software gets made now.* ## The bottleneck moved from generation to verification The industry is spending enormous energy trying to make AI generation more useful: better models, better prompts, better context, better retrieval, better agents. All of that helps and I use all of it, but it doesn't solve the hardest part of the problem. When generation was expensive, quality control lived partly inside the act of creation. A senior engineer writing code slowly and carefully was part of the quality system. Code review existed as a backstop: a second set of eyes, a forcing function for documented reasoning, and a gate that could say no. That model worked because the volumes matched. Humans produced work at human speed, and humans reviewed it at human speed. Agents broke that math. Generation is now cheap enough and fast enough that review becomes the constraint. Teams adopting AI tooling discover the pattern quickly. Producing more code, more tests, more documentation, more design options, and more analysis is no longer the hard part. The hard part is verifying that the work is correct, safe, useful, maintainable, and aligned with intent. Piling more human attention onto the problem doesn't scale. It recreates the four-minute code review at higher volume and calls it governance. The answer is more durable human judgment. That means taking the review process out of someone's head and turning it into an artifact that can run every time, at full sharpness, even when the human is tired, rushed, or too close to the work to see it clearly. I've been arguing this in the abstract for a while. The AI Operating Ledger, my framework for measuring what enterprise AI returns, says the metric that matters is value per verified outcome. That sounds good on a slide. It becomes much more uncomfortable when you realize you can't measure verified outcomes without a verifier. At some point, you have to stop describing the gate and build one. So I built one for the production system I ship to most often: this blog. ## What the verifier does The verifier is a Claude Code skill that runs against the final markdown file before publication. A skill, in this context, is a reusable instruction package that Claude Code can invoke consistently. Mine acts less like a chatbot and more like a review pipeline. It doesn't ask what kind of feedback I want, and it doesn't rewrite the post. It doesn't try to make the prose warmer, smarter, punchier, or more likely to perform on LinkedIn, which is good because the internet has enough confident beige rectangles already. It runs a review pass and produces a structured report. The workflow is simple. A draft lands in the blog repo. Before publication, the verifier runs against the final markdown file. It returns blocking issues, warnings, and notes. A blocker requires either a fix or a written override. If I override the flag, the rationale stays with the post. There is no room in it for vibes, for "can you make this better?", or for the conversational drift where the model slowly becomes my co-author, therapist, and brand strategist in the same window. The draft clears the gate, or it does not. The verifier checks four categories. ### Claims and sources Every statistic, date, named event, quoted figure, pricing claim, product claim, and technical assertion gets inspected. The verifier extracts the specific claim and checks whether the post gives it enough support. If I cite a layoff number, a model release, a cloud pricing change, a benchmark, a product capability, or a hardware requirement, the verifier asks a basic question: can this claim be traced? Claims it cannot verify get flagged rather than silently removed. That distinction matters. The verifier doesn't own the essay. I do. But it makes casual confidence more expensive, and that's the feature. A weak claim can still survive if I choose to keep it, but it cannot survive by accident. ### Voice drift My essays often come together across multiple writing sessions, and AI is usually somewhere in the loop. Stitched-together writing has a tell. Sentence rhythm flattens, transitions get too clean, and phrases appear that sound like someone wearing my jacket. The verifier checks for that. It compares sentence rhythm against my usual writing, scans for a banned-phrase list I maintain, flags filler, and catches generic AI phrasing before it settles into the draft. It also hunts down em dashes, which I've banned from my own writing because apparently I needed a constitutional amendment for punctuation. I'm aware of the irony of building an AI-assisted system partly to stop AI from making me sound like AI. It doesn't make the check less useful. ### Structural seams A post drafted in three sessions will often have three openings hiding inside it. Sometimes the argument restarts halfway through, sometimes a section restates the thesis instead of advancing it, and sometimes a transition looks polished but does not bridge the gap. The verifier looks for those seams. This check came directly from assembling my book manuscript, where session boundaries sometimes showed up as visible scar tissue in the text. The verifier isn't perfect at this, and I'll get to that in a minute. But it catches enough to stay in the suite. Instead of replacing editorial judgment, it makes the places that need editorial judgment harder to miss. ### Style enforcement These are the boring checks: AP style, metadata completeness, link hygiene, image alt text, passive constructions, long sentences, weak verbs, banned punctuation, repeated phrases, and missing descriptions. Boring checks are the ones humans skip first, which is exactly why they belong in the gate. A good verifier doesn't need to be glamorous. In fact, if it starts feeling glamorous, I probably built the wrong thing. The job is to stop predictable defects from reaching production just because I had a confident Sunday night. ## Three design decisions that mattered most Every build has a handful of choices that quietly determine whether the thing earns its keep. These were mine. ### A skill, not a checklist I had a publishing checklist for a year. It lived in a markdown file, and I followed it the way everyone follows checklists: completely, until the week I was busy. A checklist is an intention. A skill is enforcement. The difference is the same one that separates a coding standards wiki page from a linter wired into CI. I've spent my career watching that difference decide outcomes. Standards that depend on memory become optional under pressure, and standards that run every time become part of the system. That holds at the scale of one person publishing essays, and at the scale of an enterprise trying to ship safely with more automation than it had last year. The moment the review became executable, the standard changed from something I meant to do into something the system required me to confront. ### The verifier never touches the generator The verifier runs as a separate pass, with separate instructions and separate permissions. It's forbidden from rewriting the post, so it reports and stops there. This was deliberate, and I'd defend it as the most important line in the design. An author cannot grade their own homework, and neither can the model instance that helped draft the work. If the same system generates, reviews, and rewrites the artifact, you get one system with two moods instead of independent judgment. The separation is not perfect. The verifier may still use the same general class of model that helped with the draft, so I'm not pretending this is mathematical independence. The value comes from role separation: different instructions, different permissions, structured output, source tracing, no rewrite authority, and an explicit handoff back to the human. That boundary is what makes the report worth reading. It also preserves authorship. I don't want a system that quietly turns every critique into a rewrite. That feels efficient, but it blurs the most important question: who decided this was good enough to ship? In this workflow, the answer is still me. The gate informs the decision, but it does not launder responsibility. ### Overrides require a written rationale I can ship past a flag, but I have to say why. That felt like bureaucratic theater when I added it, and it turned out to be the feature. Writing "intentional fragment for rhythm" is easy. Writing "I am pretty sure this number is right" is hard, because typing that sentence makes you go check the number. Here is a good override, one that documents intent: ```text FLAG: Sentence fragment. DECISION: Override. RATIONALE: Intentional fragment for rhythm after the opening anecdote. ``` Here is a bad override: ```text FLAG: Unverified statistic. DECISION: Override. RATIONALE: I believe this number is correct. ``` That rationale would have cleared the memory claim that opened this post. The override log became a feedback loop. Recurring strong rationales tell me which checks are too rigid. Recurring weak rationales tell me where I'm trying to route around my own system. Anyone who has run a change-management process at enterprise scale knows that feeling. The gate did its job. The actor went looking for a side door. What I left out matters too. The verifier does not publish, does not fix, and makes no attempt to grade the post's importance or predict whether the essay will perform. It checks whether the post meets the standard I defined, and whether that standard is good enough is still my job. I want a quality boundary, not a ghostwriter with opinions. ## Where this pattern can go wrong This section exists because every AI post that skips the failure mode should be read with suspicion, including mine. The verifier helped immediately. It also failed immediately. ### False positives are real My first version flagged intentional choices constantly: short fragments I use for emphasis, a deliberately long sentence meant to mimic the run-on feeling of a bad meeting, repetition used for rhythm, and simple words that looked too simple to the checker. The verifier read style as drift because I had defined drift too narrowly. That was humbling in a useful way. Encoding judgment means discovering that some of your judgment was fuzzier than you believed. The checks I could not specify crisply were the ones I had never thought through. That is a reason to tune the gate instead of avoiding it. ### Not every check deserves blocking authority The em dash hunt works because it is binary. Either the character is present, or it is not. The structural seam check is different. "This transition papers over a gap" is a judgment call dressed up as a rule, and the verifier cannot always know whether a repetition is accidental or rhetorical. Some checks should block automatically. Broken links, missing metadata, unsourced statistics, and malformed frontmatter are good candidates. Other checks should surface suspicion and force review. Treating every concern like a compiler error is how you build a system people learn to ignore. That is the first counterargument to the verifier pattern: gates can turn into bureaucracy. The answer is to put gates where risk, volume, and repeatability justify them, then measure whether the gate improves outcomes. A verifier that creates noise without reducing defects is theater with a YAML file. ### The gate can create false confidence A verifier can miss things. It can approve work that still contains a bad assumption, a weak argument, a brittle design, or a subtle security issue. Worse, it can make the team feel safer than it is. That is the second counterargument, and it is the serious one. A gate is not proof of truth. It is proof that a defined standard ran. The right conclusion is "the verifier passed the checks we decided mattered enough to encode." That sentence is less magical than "the verifier passed, so the artifact is good," and much more useful. This is why experts still matter. The system can enforce known standards, but it cannot eliminate the need for people who know when the standard is incomplete, stale, or pointed at the wrong risk. ### The gate can encode one person's taste as law This risk is small on a personal blog and much larger inside an engineering organization. If I build a verifier for my own writing, it should encode my standards. If a platform team builds a verifier for hundreds of engineers, it had better encode more than one leader's preferences. Otherwise, "quality" becomes a polite word for "the way I like things," and that is how governance gets brittle. Good gates need ownership, feedback loops, versioning, exception paths, and a way for practitioners to challenge the standard. The goal is to make judgment inspectable enough that it can improve, which is the healthy version of encoded judgment. ## The leadership translation Swap "blog post" for "pull request," "service deployment," "architecture decision," "incident review," "runbook," or "client-facing model output," and this is the problem every engineering organization is running into. Agents have made generation abundant. Verification capacity has not moved nearly as fast. Leaders keep trying to close the gap with review headcount, approval meetings, and escalation paths. Sometimes those are necessary, especially in high-risk domains. But if the work volume is rising because generation got cheaper, attention-based quality control becomes the next bottleneck. The verifier pattern is the alternative: pull the judgment out of your senior people's heads, encode it as durable artifacts, and let the review pipeline enforce the baseline instead of the reviewer's calendar. That makes experts more important, in a better way. Your best people shouldn't spend most of their time inspecting every artifact by hand. They should define the standards, tune the gates, review the exceptions, and improve the system. They move from being the quality control department to being the authors of the quality system. That is a better use of expertise, and it is the only version of this that scales. This is the same idea as pipeline-first delivery applied at a different altitude. We remove direct production access because routing change through an enforced pipeline makes quality structural instead of personal. Building the publishing verifier was me removing my own production access. I no longer ship to my blog directly. I ship through a gate I designed, and the gate does not care how confident I feel on a Sunday night. Trust the gate, not the actor, even when the actor is you. Especially then. ## Where to put the first gate Do not build a giant verifier for everything. That is how good ideas become enterprise wallpaper. Start smaller. Pick one artifact that is high-volume, high-friction, or increasingly AI-assisted. Pull requests are the obvious candidate, but they are not the only one. Architecture decision records, release notes, test plans, incident reviews, cloud change requests, threat models, runbooks, and client-facing AI outputs are all better candidates than most teams realize. Then ask five questions. What defects do we keep catching late? What judgment are senior people applying repeatedly but informally? What parts of that judgment can be made explicit enough to run every time? Which failures should block the work, and which should only require human review? And what does a valid override look like? That last question is where the system becomes real. A gate without an override path becomes brittle, and a gate with lazy overrides becomes decorative. The useful middle is a system that allows exceptions but makes weak exceptions visible. You don't need perfection to start, and in fact you won't get it by starting. The first version will be noisy: some checks will be too rigid, some will be too vague, and some will reveal that the team never agreed on the standard it thought everyone understood. That discovery is the work. The verifier checks the artifact. Underneath that, it tests whether the organization can describe what good looks like. ## Judgment as a durable artifact The argument I keep making, in the book and on this blog, is that the bottleneck is never the stack. It is clarity of intent, encoded in durable artifacts that survive contact with speed, scale, and fatigue. For most of my career, my editorial judgment was a mood with a track record. On good days, that was enough. On rushed days, it was a liability wearing a confident expression. Now the standard is more concrete. It is a versioned file, a repeatable review, and an override log that makes my decisions visible to myself. It's not perfect, but it is inspectable, and that alone makes it better than trusting the best version of me to show up every time. Quality cannot depend on the best version of the human arriving at the exact moment the system needs judgment, whether the work is writing, code review, architecture, or agentic delivery. The work now is to decide which judgments matter enough to encode, which exceptions matter enough to review, and which gates deserve the authority to say no. --- ## The Kill Switch Was Always There - **Published:** 2026-06-13 - **Tags:** ai-strategy, engineering-leadership, agentic-sdlc, architecture - **URL:** https://vinny.dev/blog/2026-06-13-the-kill-switch-was-always-there/ On Friday at 5:21 p.m. Eastern, Anthropic received a letter. By that evening, Fable 5 and Mythos 5 were gone. The U.S. government, citing national security authorities, issued an export-control directive that suspended access to both models by any foreign national, whether inside or outside the United States. Anthropic said the practical effect was immediate and broad: to comply, it had to disable Fable 5 and Mythos 5 for all customers. Access to other Anthropic models was not affected. For customers who built real work on Fable, this felt less like a policy debate and more like a system dependency disappearing on a Friday night. ![Claude Code terminal showing that the selected model, claude-fable-5, may not exist or is no longer accessible](/images/blog/2026/06/fable-model-disabled-annotated.png) That feeling is real, but it's not the story. The story is the off switch. It had an owner all along, and on Friday we watched that owner use it. Sovereign risk is now a design constraint in AI architecture, not a legal footnote or a procurement concern. The question is no longer whether your favorite model is available today; it's whether your system survives the day it is not. ## It wasn't random, and that is worse The government didn't act on a whim. According to [Anthropic's statement][anthropic-statement], the directive appeared to stem from a method for bypassing Fable's safeguards. Anthropic reviewed a demonstration and said it surfaced a small number of previously known, minor vulnerabilities. It also said other publicly available models could discover the same issues without requiring a bypass. Comparable capability, the company said, is widely available from other models, including OpenAI's GPT-5.5. That doesn't settle the merits. Those will be argued by lawyers, regulators, security researchers, and, inevitably, at least one person with a 57-slide deck. But the precedent is easier to see. [The Associated Press called it][ap-offline] the most aggressive step Washington has taken yet to limit foreign access to frontier AI models. That is the line we crossed. The mechanism matters too. Export controls aimed at foreign nationals are broad, and they move fast. Disagree with the decision if you like, but don't miss what it proves. ## The munition you market is the munition they regulate Anthropic did not position Fable and Mythos as ordinary models. Its own [Fable product page][fable-page] described Fable as a "Mythos-level model" built for ambitious, long-running work. It also described safeguards for cybersecurity and biology, automatic routing away from high-risk prompts, and a 30-day data-retention requirement for safety monitoring. The pricing sent the same message. Anthropic's [pricing page][pricing-page] listed Fable at $10 per million input tokens and $50 per million output tokens, roughly twice the standard API rate for Opus 4.8. That narrative is an asset when you raise money and a liability when a regulator reads it. One cybersecurity researcher [put it bluntly][fortune-munition]. Call your model a munition often enough, and a government will eventually treat it as one. You can't tell customers you built strategic infrastructure and then act surprised when a sovereign treats it as strategic infrastructure. The marketing can be true, and it can still become policy evidence. Capability framing sells, and it also attracts control. That is the trap. There is a lesson here for buyers as well as builders. When your vendor's marketing becomes your operational risk, you have outsourced more than compute. ## Not all stops are wrong None of this means governments should never block unsafe model deployments, and some capabilities may deserve hard controls. The point for builders is simpler. Even justified controls can break your dependency, and architecture doesn't get to wait for the policy debate to settle. If a model matters to your business process, you need to know what happens when access changes, degrades, or disappears. The reason matters legally and politically. It matters much less to the workflow that just failed. ## Eleven days Anthropic announced on June 1 that it had [confidentially submitted a draft S-1][anthropic-s1] to the SEC for a proposed IPO. [Reuters reported][reuters-ipo] that Anthropic had recently raised $65 billion at a post-money valuation of $965 billion. Eleven days later, its flagship model went dark. That doesn't mean the IPO is derailed, but customers and investors now have a new kind of risk factor to price. The company was already in a visible conflict with the federal government. Earlier this year, the Pentagon labeled Anthropic a supply-chain risk. A [federal judge temporarily blocked][reuters-pentagon] that designation in late March, and Reuters [later reported][reuters-blacklist] that the administration continued defending the move in court. So the most anticipated AI listing of the year now carries a risk factor it can't paper over. If you plan to build on the soon-to-be-public darling, that risk is yours too. ## What Frankfurt and Singapore just learned Picture a bank in Frankfurt or a ministry in Singapore. On Friday, both learned something concrete. An American model can disappear for them by order of a government they don't elect. European officials reacted along exactly those lines within hours. Tom Tugendhat, a British MP and former security minister, [said sovereignty now turns on who controls the code, not the cannons][euronews-sovereignty]. That used to sound like sovereign AI theater. Now it reads like risk management. Sovereignty, open weights, regional providers, and multi-model architectures stopped being philosophy and became hedges. The problem extends past Anthropic to every U.S. frontier lab. If the export-control logic applies to one American lab, every serious buyer has to assume it could apply to others. U.S. models are still usable; blind dependence on any one of them is reckless. ## Two layers of architecture Single-vendor risk just graduated. It moved from commercial risk to sovereign risk. Your vendor can raise prices, change terms, or suffer an outage; a government can make the dependency unavailable. Chasing a safer lab doesn't help, because every U.S. frontier lab sits under a sovereign control plane. The answer is architecture, and it comes in two layers, though most teams build only the first. The first layer is portability. Use model-agnostic interfaces, and keep prompts, tools, memory, and orchestration out of any single provider's proprietary gravity well. That preserves the ability to route work elsewhere. The second layer, verification, matters more, because swapping models isn't free. Models differ in tool use, refusal behavior, latency, cost, output shape, memory behavior, and judgment. A drop-in replacement is rarely a drop-in. Portability moves the request. Verification proves the replacement behaves. That means specs, evals, golden tasks, guardrail tests, and deployment gates. Without that proof, "we can switch vendors" is a slogan; with it, switching is a capability. This is the bottleneck-is-never-the-stack argument applied to a very bad Friday. The constraint is rarely tokens, GPUs, or SDKs. If your workflow can only survive when one exact model is online, the bottleneck is the lack of verified operating capability. ## The runbook Whether you trust Anthropic is the wrong question. The practical one is, "What breaks if this model disappears at 5:21 p.m. on a Friday?" Every serious AI platform now needs a model dependency register. Know which workflows depend on which models, for which tasks, at what risk level, and don't leave this in architecture folklore. Folklore is terrible at incident response, though it does make excellent campfire material. Then define a model RTO. How long can each workflow tolerate degraded model capability before the business process fails? Then build a fallback path, and test it before you need it. The fallback should include prompts, tools, schemas, retrieval behavior, policy controls, latency expectations, and cost boundaries. Then gate model substitution through evals: golden prompts, tool-use tests, refusal behavior, output contracts, security checks, cost thresholds, and human review where the risk demands it. That is how AI platforms become durable, not because nothing breaks, but because breaking one dependency does not break the business. ## Build for the stop The kill switch was always there. Friday we learned it has an owner, and the owner is neither you nor your vendor. So build like that is true, because it is. Portability gets you out of the vendor contract, and verification gets you out safely. [anthropic-statement]: https://www.anthropic.com/news/fable-mythos-access [ap-offline]: https://apnews.com/article/anthropic-artificial-intelligence-trump-fable-mythos-d9cc7df5c02e93837d0f0bfb24d5cfd2 [fable-page]: https://www.anthropic.com/claude/fable [pricing-page]: https://claude.com/pricing [anthropic-s1]: https://www.anthropic.com/news/confidential-draft-s1-sec [reuters-ipo]: https://www.reuters.com/business/ai-giant-anthropic-confidentially-files-us-ipo-2026-06-01/ [reuters-pentagon]: https://www.reuters.com/world/us-judge-blocks-pentagons-anthropic-blacklisting-now-2026-03-26/ [reuters-blacklist]: https://www.reuters.com/legal/litigation/trump-administration-denies-unlawful-retaliation-anthropic-ai-blacklisting-2026-06-09/ [fortune-munition]: https://fortune.com/2026/06/13/anthropic-disables-fable-mythos-export-controls-national-security-threat/ [euronews-sovereignty]: https://www.euronews.com/2026/06/13/why-anthropic-is-halting-access-to-its-fable-5-and-mythos-5-ai-models --- ## The Agent Era Gets an Invoice - **Published:** 2026-06-11 - **Tags:** engineering-leadership, ai-strategy, ai-economics - **URL:** https://vinny.dev/blog/2026-06-11-the-agent-era-gets-an-invoice/ Two weeks. Four events. One repricing. Microsoft treated agents as the new organizing layer above apps and operating systems. Apple previewed the Siri it promised in 2024. Anthropic and OpenAI filed confidential S-1s with the SEC. And Anthropic released Fable 5, a frontier model that ships with some of its most dangerous capabilities deliberately fenced off. The four are one story. The agent became the interface in the same two weeks the invoice arrived. Capability, economics, identity, and governance all got repriced at once. If you lead an engineering organization, your operating assumptions just changed underneath you. The agent era is now limited by authority, cost, and trust rather than by model intelligence. That is a very different problem, and a much more enterprise-shaped one. ## Microsoft: the agent is the new runtime At Build, Microsoft made the clearest enterprise agent bet of any major platform company. The message wasn't subtle: agents are moving from chatbot sidecars into the center of how work gets done. The announcements were broad. [Project Solara](https://news.microsoft.com/build-2026/) is Microsoft's chip-to-cloud vision for agent-first devices. [Microsoft Scout](https://www.microsoft.com/en-us/microsoft-365/blog/2026/06/02/introducing-microsoft-scout-your-always-on-personal-agent/) is an always-on personal agent for work that can operate across Teams, Outlook, OneDrive, SharePoint, and local device actions. MAI-Thinking-1 is Microsoft's first in-house reasoning model. Agent 365 is the control plane for observing, governing, and securing agents across environments. Azure Container Apps Sandboxes and other isolation patterns point toward a world where autonomous workloads need runtime constraints of their own, beyond clever prompts. Read the announcements as a list and it looks like a product blitz. Read them as a system and the strategy snaps into focus. Microsoft is building the enterprise agent stack from silicon to governance, and it's reducing its dependency on OpenAI's models at the same time. That second part matters more than the keynote demos. The company that owns the governance layer, the identity layer, the productivity graph, and the device layer doesn't need to own the smartest model, only the place where agents get permission to act. That is the enterprise play. Microsoft is not selling intelligence. It is selling control over intelligence. The most important detail is easy to miss because it sounds like plumbing. Microsoft says every agent, Scout included, operates under its own governed Entra identity rather than as a vague bot behind the curtain. That means the work is attributable to a known actor, policies can be applied, and administrators can see what the agent is doing. That is the architecture of the next enterprise control plane. Every serious company is about to face the same question: when an agent takes an action, who did it? The employee, the model provider, the application, or the service account nobody has audited since 2019? Good luck explaining that one to risk, compliance, or your future incident review. Bring snacks. Agents are becoming non-human actors with delegated authority. That means identity, access, approval, telemetry, rollback, and ownership move from supporting concerns to the center of the design. Building an agent stopped being the hard part. The hard part is letting one act safely inside the business. ## Apple: the context moat finally gets a drawbridge Apple has spent two years writing checks that its software couldn't cash. Apple Intelligence launched as a brand before it fully landed as a product, and the personalized Siri promised in June 2024 slipped badly enough to become both a punchline and a legal problem. WWDC 2026 was Apple's attempt to settle the account. [Siri AI](https://www.apple.com/newsroom/2026/06/apple-introduces-siri-ai-a-profoundly-more-capable-and-personal-assistant/) is the assistant Apple sketched two years ago: conversational, aware of what's on your screen, grounded in personal context, able to search across messages, emails, photos, and apps, and able to take actions across the system. The important correction is that Apple announced and previewed this future. It has not yet proven it at full consumer scale. Apple says the new Siri AI features are available for developer testing now (I'm still waitlisted) and will reach users as a beta later this year. That distinction matters because Apple's AI story has already taught us that demos and durable products aren't the same thing. Still, the strategic shape is now clear. Apple's advantage was always context. Your messages, your mail, your calendar, your reminders, your browsing, your photos, your location patterns, and your device habits all sit inside an ecosystem people trust more than most alternatives. A useful personal agent should be table stakes for the company holding that data. The fact that it took until 2026, and that Apple acknowledged in the keynote that the next generation of Apple Foundation Models was built in collaboration with Google and Gemini, tells you how hard the last mile of agentic products is. Owning the context is necessary and nowhere near sufficient. That is the same lesson enterprises should take from Apple's delay. Internal context looks like a moat until you try to operationalize it. Your documents, tickets, pull requests, runbooks, incidents, chats, policies, metrics, and architecture decisions are valuable only if they're findable, current, permissioned, and clean enough for an agent to use. A personal agent with bad context becomes annoying. An enterprise agent with bad context takes the action anyway, under its own identity, and leaves an audit trail proving it. Apple is making the consumer agent bet while Microsoft makes the enterprise one. Two trillion-dollar companies are splitting the addressable market by context layer rather than by model leaderboard. Apple wants the trusted personal context layer and Microsoft wants the governed work context layer. Neither is primarily competing on model quality. ## The S-1s: the subsidy era files its paperwork While the platform companies fought over interfaces, the model companies started the clock on something less glamorous and more consequential. Anthropic [filed a confidential S-1](https://www.anthropic.com/news/confidential-draft-s1-sec) on June 1. OpenAI [followed on June 8](https://openai.com/index/openai-submits-confidential-s-1/), announcing its own filing because, in its words, it expected the news to leak anyway. In the same window, SpaceX was also moving toward the public markets. A staggering amount of private-market valuation is now trying to become public-market accountability. An S-1 is a forcing function. Private companies can subsidize inference, call it growth, and ask investors to believe the curve eventually bends. Public companies report quarterly and answer for gross margin. The story changes when the cost of every miracle has to live in a public filing. The early estimates explain the urgency. Sacra estimates that OpenAI posted a 33 percent gross margin, constrained by inference costs that reached $8.4 billion in 2025 and are projected to rise to $14.1 billion in 2026. Treat those as estimates, not audited S-1 disclosures. But the direction is hard to ignore: frontier intelligence is expensive to serve, and usage isn't free just because the interface feels magical. I wrote in [The Subsidy and the Severance](https://vinny.dev/blog/2026-06-02-the-subsidy-and-the-severance/) that the discount era would end the moment the labs needed to show real unit economics. The S-1s are that moment, with a federal filing number attached. Every enterprise consuming frontier models should expect more of the true cost of inference to migrate from the lab's income statement to yours. It will come gradually and without a memo, through tiering, capacity limits, premium reasoning modes, higher enterprise minimums, retention-policy exceptions, usage credits, and procurement conversations that suddenly feel less like software buying and more like energy trading. The teams that built an operating ledger will negotiate this transition. They will know which AI workflows create verified outcomes, which ones are experiments, which ones are expensive theater, and which ones are quietly eating the budget in the corner. The teams that treated AI spend as an unmetered utility will get a very educational invoice. Calling this "AI is too expensive" is too simple. The shift is that AI cost will become legible, and once cost becomes legible, leaders will ask harder questions. What did we buy, what changed, and what shipped? What risk did we reduce, what manual work disappeared, what quality improved, and what failure modes did we create? Which workflows deserve frontier models, and which ones deserve smaller, cheaper, boring models that do the job perfectly well? Tokens are a measure of spend, and verified work is the business outcome. ## Fable 5: capability becomes a governed resource The fourth event is the strangest and, I think, the most important. Anthropic released [Claude Fable 5](https://www.anthropic.com/news/claude-fable-5-mythos-5), a Mythos-class model it describes as the most capable Claude it has made broadly available. The release architecture is more interesting than the benchmark table. Fable 5 ships with classifiers that detect requests related to cybersecurity, biology and chemistry, and model distillation. The cyber and bio safeguards were visible from day one: flagged requests fall back to Claude Opus 4.8, and the user sees it happen. The distillation safeguard shipped differently. Buried in a 319-page system card, it silently degraded responses for users suspected of frontier LLM development, with no notice and no fallback message, just quietly worse output. The less restricted version, Claude Mythos 5, is limited to Glasswing partners for cyber use and eventually to select biology researchers with some safeguards removed. Anthropic also requires 30-day retention for traffic on Mythos-class models, even for business customers. This is a new pattern. Anthropic is rationing dangerous capability rather than refusing it or releasing it to everyone, using graduated access tiers, trusted programs, government consultation, monitoring, and audit trails as product architecture. Capability is becoming a governed resource, the way cryptography, export-controlled technology, and certain chemicals already are. One detail deserves its own paragraph. [Project Glasswing](https://www.anthropic.com/glasswing) lists Apple as a launch partner, alongside AWS, Google, Microsoft, NVIDIA, CrowdStrike, Cisco, JPMorganChase, the Linux Foundation, and others. The company making the consumer-context bet is also part of the program built around Anthropic's most restricted cyber-capable model family. The consumer and enterprise stories aren't as separate as the keynotes suggest. The backlash matters too. Within 48 hours, Anthropic called the invisible approach "the wrong tradeoff," apologized, and committed to visibility: flagged requests will now route to Opus 4.8 in plain sight, and API calls will return a stated reason for refusal. That is the governance story becoming real. A safety control that users cannot observe may be safer in one dimension and less trustworthy in another. Enterprise buyers will ask whether a model is safe, and then whether the safety behavior is visible, auditable, explainable, and contractually tolerable. Microsoft's own reaction proves the point. The Verge reported, with Reuters following, that Microsoft limited employee use of Claude Fable 5 while its legal teams reviewed Anthropic's data-retention requirements. The model is missing from the internal picker in GitHub Copilot even as Microsoft sells it to customers through Copilot and Foundry. That is the agent era in miniature: the model may be capable, the use case may be valuable, and the distribution may be easy, but governance still gets a vote. In regulated enterprises, the winning model is the smartest one you can safely explain, monitor, approve, and afford. ## What this means if you run engineering Put the four events together and the pattern is unmistakable. The industry's center of gravity moved, in a single two-week window, from "what can the model do" to "who may use it, what may it do, who governs it, and who pays for it." For enterprise engineering leaders, four planning assumptions follow. First, the interface assumption. Agents are no longer a feature bolted onto chat. Microsoft is rebuilding its work platform around them and Apple is rebuilding its consumer experience around them. Your internal platforms, developer portals, identity systems, and change-management processes will be asked to host autonomous actors alongside users. Design for that now. Second, the identity assumption. Every agent needs to be treated like an actor with delegated authority. It needs its own identity, scope, access policy, approval path, telemetry, and owner. Shared service accounts were already a smell. In the agent era, they become a liability with an autocomplete button. Third, the economics assumption. Subsidized inference is a depreciating asset. Model the costs as if discounts can change next year, because public-market scrutiny makes margin discipline inevitable. Measure value per verified outcome. If you can't connect AI spend to shipped, verified work, you are accumulating a liability with a delay on it. Fourth, the governance assumption. Fable 5's tiered release previews the regulatory and enterprise shape of the next five years: trusted-access programs, mandatory retention, capability routing, visible fallbacks, and differentiated access based on use case and trust. Enterprises that already run secure-by-default, auditable AI workflows will qualify for the good tier. Everyone else will be arguing with a fallback model. The capabilities on display these past two weeks are genuinely remarkable, but they were never the constraint, just as the stack never was. What determines who wins is whether your organization can govern, meter, and verify what these systems do. --- ## The AI Operating Ledger - **Published:** 2026-06-08 - **Tags:** engineering-leadership, ai-strategy, agentic-sdlc, ai-economics - **URL:** https://vinny.dev/blog/2026-06-08-the-ai-operating-ledger/ A senior engineer on your team just spent three hours unwinding a brilliant, confident, agentic detour. It looked flawless in the pull request and passed every test in the suite. It had a tidy summary, a reasonable commit history, and the calm confidence of a system that had absolutely no idea it was wrong. Then it broke production. That three-hour rollback won't show up on your OpenAI, Anthropic, Google, or AWS invoice. But it may be the most expensive line item on your real AI bill. The easiest way to make AI look profitable is to leave half the costs off the ledger. Put the subscription in one column and the salary you hope to avoid in the other. Smile at the margin, and tell the board the operating model changed. That math works beautifully until the first production incident, the first customer exception, the first rework loop, the first compliance question, or the first multi-hour unwind of a confident agentic detour that looked impressive right up until it mattered. The model cost is one line inside the AI cost, and the prompt is one step inside the workflow. The output is not the outcome. If the last phase of enterprise AI adoption was about capability, the next phase is about accounting. I mean operating accounting rather than the finance-department kind. It asks whether a workflow got cheaper once you include inference, context preparation, review, rework, escaped defects, evaluation, governance, institutional memory, and the human judgment required to make the machine useful. Once you stop pretending a [salary-to-subscription comparison](https://vinny.dev/blog/2026-06-02-the-subsidy-and-the-severance/) is an AI strategy, the next question is harder and more useful. How do you account for AI work from prompt to verified outcome? I've started thinking of this as the *AI Operating Ledger*. Every serious engineering organization is going to need one. ## The spreadsheet version is too clean Most AI ROI conversations still begin with a clean comparison. A human does a task, an AI system does the same task faster, and the AI system costs less than the human. Therefore, productivity goes up and cost goes down. That is a magic trick, not analysis. AI creates real value, and I use it every day. I build with it, write with it, review with it, test with it, and use it to compress work that used to take days into focused sessions measured in hours. The problem is that the visible cost of the tool is only one line item. A coding agent does more than "write code." It consumes context, makes assumptions, calls tools, edits files, runs tests, fails tests, retries, summarizes its work, and hands a human a diff that still has to be understood. Sometimes that workflow is wildly profitable. Sometimes it is an expensive way to generate plausible nonsense. Neither the subscription price nor the token bill tells you which one happened. That's the first mistake. Leaders are starting to treat token usage as the AI version of cloud spend, when token spend is closer to fuel consumption. Fuel consumption is useful, measurable, and impossible to ignore once the meter is visible. But it doesn't tell you whether the trip was worth taking. A team can burn a million tokens and ship a critical application refactor while another team can burn a million tokens turning a vague Jira ticket into a beautifully formatted catastrophe. The question worth asking is "What value survived review?" rather than "How many tokens did we use?" ## What belongs on the ledger A serious AI Operating Ledger needs more than the model invoice. At minimum, it needs to account for the full path from request to trusted result. | Ledger line | What to measure | Why it matters | | --- | --- | --- | | Inference | Model calls, model tier, context size, retries, cached and uncached tokens | Tracks the visible machine cost | | Context preparation | Time spent gathering requirements, repo state, logs, designs, constraints, acceptance criteria, and institutional knowledge | Shows whether ambiguity moved upstream or downstream | | Review | Reviewer time, reviewer seniority, review depth, and approval cycles | Captures the human judgment tax | | Rework | Bounce count, failed attempts, rejected diffs, prompt retries, and misunderstood requirements | Exposes hidden loops | | Escaped defects | Incidents, support tickets, remediation hours, customer impact, and operational interruption | Measures downstream cost | | Evaluation | Test coverage, eval coverage, golden examples, regression checks, and drift signals | Shows whether the workflow is improving or degrading | | Governance | Auditability, access controls, data boundaries, policy exceptions, vendor risk, and retention requirements | Captures the cost of operating in the real enterprise | | Institutional memory | Knowledge retained, documentation improved, junior engineer learning, and judgment built or bypassed | Measures long-term capability gain or loss | The first line is inference, and it is the obvious one. It covers the model calls, the context window, the retries, the long-running agent sessions, the cached and uncached tokens, and the premium model multipliers. This is the line item everyone is learning to notice. But inference is just the top line. Someone has to gather the issue, the repo state, the logs, the designs, the constraints, the acceptance criteria, and the institutional knowledge the model doesn't magically have. If that context is missing, the cost moves downstream into rework instead of disappearing. Every useful AI workflow also has a human judgment point. The more consequential the output, the more expensive that review becomes. A senior engineer reviewing an agent-generated authentication change isn't free just because the code was cheap to produce. In fact, it introduces a unique cognitive tax. Instead of skimming an agent's diff, a reviewer has to hunt for subtle, highly confident mistakes. This line item is high-focus, high-fatigue time. Then comes rework, which is where bad AI economics go to hide. The agent solves the wrong problem, and the first draft looks right but violates an invariant. The test suite passes because the test suite reflects the same misunderstanding. The reviewer catches it, sends it back, and the system loops. If a defect escapes, the ledger expands again. A defect generated quickly is still a defect. If it reaches production, the real cost includes incident response, customer trust, support load, remediation, and whatever opportunity cost came from stopping other work. If the workflow matters, you also need evaluation. That means test fixtures, golden examples, regression checks, and an owner who notices when the workflow starts drifting. Then governance enters the room, usually wearing sensible shoes and carrying a clipboard. Security, compliance, auditability, access control, data boundaries, vendor risk, retention, and explainability don't become optional because the interface got conversational. In regulated environments, this line item is the cost of admission rather than a footnote. Finally, there's institutional memory. This is the strange one, and maybe the most important. When people do work manually, they learn. When agents do work invisibly, the organization may get output without learning. That can be a bargain for repetitive toil. It's dangerous when the work is how your next generation of engineers builds judgment. By outsourcing middle-tier execution, the precise work junior engineers traditionally use to cut their teeth, you risk trading tomorrow's engineering judgment for today's delivery velocity. I'm not arguing for character-building theater, where humans grind through every repetitive task on principle. The answer is to [be deliberate about which work teaches judgment](https://vinny.dev/blog/2026-06-06-your-first-ai-reorg-should-be-the-work/) and which work is just toil wearing a cardigan. That's a real operating cost, and it belongs on the ledger. ## The hidden variable is ambiguity Here is the uncomfortable part. The same AI tool can be cheap or expensive depending on the quality of the work you put in front of it. Give an agent a clear spec, real constraints, known interfaces, testable acceptance criteria, and a narrow path to verification, and the economics can be excellent. The machine moves fast because the search space is bounded, and the reviewer moves fast because the intent is explicit. The rework loop stays short because deviations are visible. That matters, because some AI workflows really are cheap, fast, and valuable. If the task is bounded, the data is available, the expected output is clear, and verification is straightforward, AI can be an extraordinary accelerator. Nobody needs a 47-slide governance framework for summarizing a well-structured meeting transcript or generating a first draft of a test fixture. But give the same agent a vague request and the ledger changes immediately. "Fix the flaky tests." "Modernize this service." "Improve the dashboard." "Make this production ready." Those prompts feel normal because humans have been filling in those gaps for years. AI exposes how much *[smuggled intelligence](https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/)* those requests depended on. The senior engineer knew which flaky tests were hiding a real race condition. The staff engineer knew the service had a migration constraint. The designer knew the dashboard had accessibility debt. The platform lead knew "production ready" meant observability, rollback, ownership, cost controls, and a pager path that wouldn't ruin someone's weekend. The model doesn't know those things unless the organization writes them down. This is where the AI Operating Ledger connects back to a truth we often try to avoid: [the bottleneck is never the stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/). AI taxes bad engineering management in real time rather than fixing it. A fuzzy spec used to cost time. Now it costs time plus tokens plus review plus rework plus trust. The meter did not create the cost. It made the cost visible. ## Value per verified outcome I like the phrase *value per token* because it forces the right discomfort, but it can mislead if you take it too literally. Minimizing token usage would be like optimizing a delivery route by refusing to buy gas. Some valuable work requires a lot of context, and some hard problems deserve the expensive model. Some agent runs are worth every penny because they collapse a week of tedious exploration into an afternoon of reviewed progress. The goal is to stop pretending all usage is equal. A high-token session that produces a verified architectural migration may be cheap. A low-token session that creates a subtle security flaw may be expensive. The denominator matters, but the numerator matters more. The better metric is value per verified outcome. That word *verified* is doing the work, as opposed to generated, summarized, or demoed. Verified means the output matched the intent, the constraints held, and a competent human or automated gate checked the result against something more durable than vibes. Verified also means the organization can explain why it trusts the work. That is the difference between AI theater and an AI operating model. ## How to open the ledger If you lead an engineering organization, I would start with three moves. First, conduct a Ledger Audit on one workflow. Don't try to audit the whole enterprise or build a massive transformation deck. Pick one recent, agent-assisted feature that has been merged and track its lifecycle backward. How many times did it bounce back from review? How many tokens did the agent consume spinning its wheels on a vague requirement? How long did the engineer spend preparing context or fixing context boundaries compared to just writing the code? What broke after the merge? Write down every cost from prompt to verified outcome. Second, separate generation metrics from outcome metrics. Track token spend and agent runs, yes, but don't confuse activity with value or outcomes. Add review time, rework rate, acceptance rate, defect escape rate, and cycle time from approved spec to verified delivery. Third, move investment upstream. [Better specs](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/), clearer standards, stronger evals, and tighter review loops will usually improve the ledger faster than another tool rollout. They also put judgment where it belongs. The meter showing up makes AI more serious, not less important. The free-lunch phase made experimentation easy, and the accounting phase will make discipline valuable. That's good, because it means the market is starting to separate real advantage from subsidized noise. The companies that understand this will keep investing. They will use agents aggressively, automate real toil, and redesign workflows around human judgment instead of nostalgia for manual work. They will drop the fake math, stop comparing a salary to a subscription and calling it strategy, and build the ledger. Once they do, many AI business cases will get smaller, sharper, and much more believable. The organizations that win will be the ones that can open the ledger and show, honestly, what value survived review. --- ## Your First AI Reorg Should Be the Work, Not the People - **Published:** 2026-06-06 - **Tags:** engineering-leadership, ai-strategy, agentic-sdlc, future-of-work - **URL:** https://vinny.dev/blog/2026-06-06-your-first-ai-reorg-should-be-the-work/ The fastest way to look serious about AI is to redraw the org chart. It's also the easiest way to avoid redesigning the work. Something predictable happens when an AI mandate lands on an executive's desk. Within a meeting or two, someone produces a new org chart. Boxes move, boxes vanish, a headcount number gets smaller, and the slide looks decisive. It feels like leadership, and it photographs well in a board deck. I want to argue that it's almost always the wrong first move, and that the order of operations here matters more than the courage of the cut. A few days ago I wrote about the economics of this moment in [The Subsidy and the Severance](https://vinny.dev/blog/2026-06-02-the-subsidy-and-the-severance/). The short version is that the salary-for-subscription swap is usually fake math, because the real cost of AI includes inference, supervision, rework, and the institutional knowledge you only notice once it walks out the door. Jack Dorsey's plan to cut Block by nearly half was the loudest version of the bet. Klarna is the early warning sign: automate the visible work too aggressively, and the invisible work comes back as quality problems, support load, and human rework. That essay was about why the math is fake. This one is about what to do instead, and specifically about what to do first. Your first AI reorg should redesign the work. Before you touch the org chart, redesign four things: the workflows, the decision rights, the ownership, and the evaluation loops. The org chart comes last in that sequence. It should describe a system you have already designed rather than one you are hoping to discover on the far side of a layoff. ## The org chart is a downstream artifact The org chart is such a tempting place to start because it is legible. Headcount is the most legible lever an executive owns. It is a single number, it moves in one direction, and it fits on one line of a board update. Workflows, decision rights, ownership, and evaluation loops are none of those things. They are messy, they resist a clean headline, and they take real work to change. So leaders reach for the legible lever, and legibility quietly gets mistaken for correctness. In 1968, Melvin Conway observed that organizations build systems whose structure mirrors their own communication patterns. We usually quote Conway's Law to explain why our software ends up shaped like our org chart. The same logic runs in reverse, and right now the reverse is the useful direction. If your structure ends up mirroring your system, then you should design the system first and shape the structure to fit it. Redrawing the org chart before you have redesigned the work is rewiring the building before you know where the rooms go. You can do it. You'll just be guessing. So before the boxes move, here is the actual work. ## Workflows: redesign the path before you remove the people on it Most teams have never mapped how their work flows. They have a Jira board, which isn't the same thing. Before you decide who is redundant, trace the real path of a unit of work from request to production. Mark every place where it waits, where it gets handed off, and where it queues behind a scarce human reviewer. AI changes which steps on that path are expensive, and that's the whole reason a reorg is on the table in the first place. For 20 years we optimized workflows around the assumption that writing the code was the slow part, so we protected senior engineers and routed everything through them. When an agent can produce a credible first draft of the implementation in minutes, the slow part moves to specification on the way in and review on the way out. A workflow tuned for scarce production is the wrong shape for abundant production, and no amount of headcount math fixes a path that's pointed in the wrong direction. Consider the vague-ticket failure I described in the last essay, where a confident pull request from an agent lands on a senior engineer who has to unwind it. That is a workflow problem. The path had no clear specification at the front and no real acceptance gate at the back, so removing the senior engineer would only remove the person who caught it. Redesign the path, and that same agent becomes genuinely useful. Cut the person and keep the broken path, and all you've done is automate the confusion. ## Decision rights: write down who decides, including the machines Every workflow contains decisions, and most organizations have never written down who gets to make them. The decisions happen anyway, quietly, in the heads of experienced people who know that this kind of change needs a second set of eyes and that kind of change can ship on a Friday. That tacit authority is invisible right up until you remove the person holding it. An AI reorg forces the question into the open, because now some of the actors aren't people. You have to decide, explicitly, what an agent is allowed to decide versus what it is only allowed to recommend. An agent can open a pull request, and whether it may merge to main is a call someone has to make on purpose. The same question sits behind every customer reply it drafts and every schema change it proposes. Sending the reply and applying the change to production are different rights from writing them. Those are policy questions, and the policy needs to exist before you change who is in the room. Map the decision rights across the redesigned workflow first. Decide which calls a human must own, which an agent may make inside guardrails, and which require a human to confirm a machine's recommendation. Do that honestly, and you'll often discover that the reorg you needed was a clarification of authority rather than a reduction in people. ## Ownership: an agent without an owner is a production system with no on-call Decision rights tell you who makes a call. Ownership tells you who is accountable when the call goes wrong and who maintains the thing over time. The two are easy to blur and expensive to confuse. This is where agent ownership becomes the quiet center of the whole exercise. When you deploy an agent into a workflow, you are deploying a production system. It has prompts that drift, guardrails that need tuning, dependencies that shift underneath it, and failure modes that surface at the worst possible moment. Someone has to own all of that. An agent without a named owner is a production system with no on-call rotation, which is to say it is an incident with a delay timer. The trap in a headcount-first reorg is mechanical. You remove the person who implicitly owned a workflow, you hand the workflow to an agent, and you never assign the agent an owner. Now the work has no human accountable for it at all. You did not save a role. You orphaned one. The honest version of an AI reorg often adds ownership work even as it changes the shape of the team, because every agent in production should have a named human owner, a written spec, defined guardrails, and a rollback path. That work is the line between an operating model and a liability. ## Evaluation loops: instrument the work before you bet the org on it The fourth redesign is the one most often skipped, and it's the one that protects you from your own optimism. Before you make a structural bet on AI-augmented work, you need a way to tell whether the work is getting better or just getting cheaper to produce while quietly getting worse. This is the Klarna lesson restated as an instrument. Klarna's support quality eroded gradually, under a story everyone wanted to believe, until the gap grew large enough to force a reversal. An evaluation loop is what catches that erosion in week three instead of quarter three. It means setting a baseline before the change, then watching the measures that correlate with value: accepted output rather than generated output, escaped defects, cycle time, rework, operational load, and customer outcomes. In the new economics, value per token replaces tokens consumed as the number worth organizing a team around. The sequencing here is the part that matters most. If you reorganize first and instrument later, you have no baseline, so you can't tell the difference between a workflow that is working and one that is failing slowly. You'll be reading the boomerang's flight path from memory. Put the evaluation loop in place first, let it run against the redesigned workflow, and your eventual structural decisions get to rest on evidence instead of on a narrative that happened to test well in a meeting. ![AI reorg sequence: redesign the work before the org chart](/images/blog/2026/06/ai-reorg-sequence.png) ## Redesign, run, then reshape Put those four together and the order of operations almost writes itself. First, redesign the work. Map the workflows, assign the decision rights, name the owners including the owner of every agent, and stand up the evaluation loops. Second, run it. Let the redesigned workflows operate long enough, and the instruments collect enough, to show you where the work concentrates and where it genuinely thins out. Third, reshape the org to match the work that emerged. Now the org chart is doing its real job, describing a validated system rather than gambling on a hypothetical one. If I were putting this into an operating review, the table would be simple. | Layer | Question to answer before the reorg | | --- | --- | | Workflow | Where does work wait, loop, hand off, and require judgment? | | Decision rights | Which decisions can an agent make, recommend, or never touch? | | Ownership | Who owns every workflow, agent, guardrail, rollback path, and failure mode? | | Evaluation loops | What baseline tells us whether the work is improving or only getting cheaper to produce? | | Org shape | What structure reflects the validated work instead of the hoped-for savings? | This is the inverse of the headcount-first reflex, and it produces a very different kind of decision. When the structural change finally comes, and some of it will, it's legible for the right reason. You can point to the workflow it reflects, the decision rights it encodes, the ownership it assigns, and the evaluation data that justified it. That is a reorg you can defend to your board, to your team, and to yourself at two in the morning when the first big incident lands. ## What I am not saying This is not an argument that headcount never changes. Some roles will genuinely disappear, some teams will get smaller, and some work is going to move permanently to machines. It is also not an argument for studying the problem forever while your competitors move. The redesign I am describing is measured in weeks, not years, and most of it is work you should have done regardless of AI. Unclear workflows, undocumented decision rights, orphaned ownership, and missing evaluation loops were quietly taxing you long before anyone said the word agent. The argument is only about order. Do the work before the people. Design the system before you draw the boxes that are supposed to describe it. ## The bottleneck is never the org chart either I keep coming back to the same line because the economics keep proving it. The bottleneck has never been the stack, and the headcount is just the newest candidate. The constraint has always been whether the work is designed well enough for someone, or something, to do it well. AI didn't change that. It just raised the price of getting it wrong and moved the bill to the front of the room. The leaders who win the next few years will be the ones who redesigned the work first, measured it honestly, and let the org chart follow. That is slower than a dramatic announcement and a 24 percent stock pop. It is also a great deal harder to boomerang. --- ### Sources and further reading - Vinny Carpenter, "The Subsidy and the Severance": - Vinny Carpenter, "The Frame Is the Bottleneck": - Vinny Carpenter, "The Spec Is the Product": - Vinny Carpenter, "The Bottleneck Is Never the Stack": - Melvin Conway, "How Do Committees Invent?", Datamation, 1968, the origin of Conway's Law - Matthew Skelton and Manuel Pais, *Team Topologies*, IT Revolution Press, 2019, on designing teams around the flow of work --- ## The Subsidy and the Severance - **Published:** 2026-06-02 - **Tags:** genai, agentic-sdlc, software-engineering, engineering-leadership, ai-economics - **URL:** https://vinny.dev/blog/2026-06-02-the-subsidy-and-the-severance/ On February 26, 2026, Jack Dorsey told Block shareholders he was reducing the company by nearly half, from more than 10,000 people to just under 6,000. More than 4,000 people were being asked to leave or enter consultation. The stock jumped as much as 24%. That's the part worth sitting with for a minute. A company announced one of the largest AI-framed workforce reductions we've seen, and the market applauded before the operating model had a chance to prove itself. Dorsey didn't blame a bad quarter. In Block's own shareholder letter, he said the business was strong, gross profit was still growing, and profitability was improving. The real change, he argued, was that intelligence tools paired with smaller, flatter teams had fundamentally changed what it means to build and run a company. He would rather make one decisive cut than bleed the organization through years of quiet rounds. Then he went further than most CEOs do. Within a year, he predicted, the majority of companies would reach the same conclusion and restructure the same way. I have spent three decades building software and the last several years leading the platform teams that keep it running. I want Dorsey to be wrong about the timeline and right about the tools. AI matters. What makes this moment worth writing about is whether the economics work once the subsidy disappears and the operating costs become visible. For roughly 18 months, the industry ran on two comfortable beliefs: that AI is cheap, and that AI can replace people. Usage-based billing is now exposing the true cost of the AI. The layoff boomerang is exposing the true cost of the people. Put real numbers on both sides of that ledger and the trade looks very different than it did in the press release. I'm not arguing that AI is too expensive to matter, or that headcount will never shrink. Some work will absolutely change, some roles will disappear, and some teams will get smaller. The argument is narrower and more important. The simple salary-for-subscription swap is usually fake math, because the full cost includes inference, reliability, supervision, rework, customer experience, and institutional knowledge. Once those costs move from hidden subsidy to visible operating expense, sloppy AI adoption and sloppy workforce cuts both get harder to hide. ## The flat fee was a promise the physics could not keep A month ago, the cool thing to do was token maxxing. Engineers compared usage dashboards like high scores, and teams joked about who could burn the most tokens in a week. It was fun, and it was a tell. We were treating inference like an all-you-can-eat buffet because someone else was paying for the kitchen. On June 1, 2026, [GitHub moved Copilot to usage-based billing](https://github.blog/news-insights/company-news/github-copilot-is-moving-to-usage-based-billing/). Every Copilot plan now consumes GitHub AI Credits based on token usage, including input, output, and cached tokens. GitHub described the move as necessary to align pricing with actual usage and make Copilot a sustainable business. That last word, sustainable, is the one that matters. GitHub made the change because agentic workflows changed the cost curve. A chat request and a long-running coding agent are different economic objects. One is a question. The other may hold a large context window open, search a repo, edit files, run tests, respond to failures, and try again. That's the whole point of agentic software development. It's also the bill. The legacy multiplier table tells the same story in a different language. For Copilot users who remain on annual plans under the old request-based model, GitHub now lists several frontier coding models with double-digit multipliers, including multiple Opus models at 27. The exact table will keep changing, which is the point. Model cost has moved from an invisible platform concern into the engineering operating model. This was never only a GitHub problem. OpenAI, Anthropic, Google, and the rest of the frontier labs have been wrestling with the same basic constraint. Heavy users were consuming more compute value than their subscriptions covered, while the vendors absorbed the difference in the name of growth. That was a reasonable customer acquisition strategy rather than a law of physics. There's an old idea hiding underneath all of this. In 1865, the economist William Jevons noticed that making coal use more efficient increased coal consumption instead of reducing it, because efficiency made coal worth using for more things. Cheap, subsidized inference did the same thing to us. It made us build agents that call other agents, summarize the output, generate tests, rewrite the tests, open the pull request, and then explain the pull request to another agent. For a while, someone else paid the metered rate. The bill has now been forwarded to the customer. ## Cheap for the buyer, profitable for the seller, pick one Why is the subsidy ending now, after the labs tolerated these losses for years? The answer is on the calendar. The IPO window is opening. Anthropic has reportedly filed confidentially to go public, and OpenAI is widely reported to be preparing its own path to the public markets. A private company can run for a long time on growth, scarcity, and belief. A public company has to show a path to durable margins. That's where the AI story gets interesting. The market wants two things at once. It wants AI cheap enough that enterprises can use it to justify massive productivity gains. It also wants the companies selling AI to prove they can become profitable public businesses. Those two demands are in tension. If inference stays heavily subsidized, customers get cheap automation but labs struggle to show the unit economics public investors expect. If inference gets priced closer to cost, labs can tell a better profitability story, but customers have to revisit the spreadsheet they used to justify replacing people, processes, or entire layers of work. That does not kill AI. It matures it. Maturity separates use cases that create real value from use cases that only looked good while the meter was hidden. It separates teams that know how to specify work from teams that send agents wandering through ambiguity with a corporate card. And it tells you which leaders are using AI to redesign work and which are using it to decorate a cost-cutting memo. Now hold that next to Block. Dorsey's efficiency bet only works if the productivity gain survives the full cost of the toolchain, the new operating model, the retained experts, the escaped defects, the rework, and the customer impact. The same investors who cheered the cut are also asking AI labs to stop subsidizing the compute that makes the cut plausible. Someone pays full price. Increasingly, that someone is the buyer. ## The boomerang Here is the part Dorsey's prediction has to survive. Some companies that already ran versions of this experiment are quietly reversing pieces of it. Klarna is the cautionary tale, though the lesson is broader than "AI failed." Business Insider reported that Klarna reassigned employees, including engineers and marketers, into customer-support roles after the company concluded that earlier cost-cutting had gone too far. The company had previously promoted aggressive AI-driven efficiency and said its AI assistant was doing the work of hundreds of customer support agents. Later, its CEO acknowledged that cost had become too dominant a factor and that lower quality was the result. Cost-led automation can degrade service quality when leaders remove human judgment before the operating model is ready. Klarna isn't alone. A February 2026 Careerminds survey of 600 HR professionals who had made layoffs in the prior 12 months found that companies were already rebuilding workforces they had cut. Careerminds reported that 35.6% of surveyed companies rehired for more than half of the roles they eliminated, while 32.7% rehired between 25% and 50% of the roles. Most did it within six months. That's the boomerang. A role looks automatable on a spreadsheet because the visible work is routine. Then the role disappears, and the invisible work shows up. It's the customer exceptions, the edge cases, the relationship context, the regulatory nuance, the institutional memory, and the judgment under pressure, all the things no one wrote down because the person doing the work simply knew them. AI is still reshaping real work, and the net job losses attributed to it are real. Challenger, Gray & Christmas reported that AI led all stated reasons for job cuts in April 2026, with employers attributing 21,490 cuts to it that month and 49,135 so far this year. But "AI-cited" and "AI-caused" are not the same thing. That distinction matters because AI is becoming the most convenient restructuring story in the market. It sounds strategic and inevitable. It also sounds better than saying the company overhired, duplicated work, tolerated unclear ownership, or let complexity compound until the org chart became the product. Which brings us back to the awkward question about Block. Dorsey framed the cut as an AI story, and he may be right. But the same story also includes a more familiar operating problem. During the pandemic-era growth cycle, Block grew dramatically and built Square and Cash App with more separate organizational structures. Reuters noted that analysts also viewed the reduction as a correction from pandemic overhiring, with Block's workforce growing from roughly 3,800 in 2019 to more than 10,000 by 2025. Strip away the framing and a large share of this looks like a long-overdue simplification move wearing AI as a more flattering jacket. That doesn't make the reduction meaningless, but it does make the attribution important. AI may be the accelerator, the excuse, or both. The gap between those explanations is where most of the next year is going to be argued. ## Reliability just became a line item The repricing changes more than budgets. It changes what good engineering is worth. Under a flat fee, a mediocre answer from a model was an annoyance. You shrugged, edited it, and moved on because the next attempt felt free. Under metered billing, a hallucination is a cost problem as well as a quality problem. It triggers a correction loop, and every loop costs money, so unreliable output now compounds directly onto your invoice. Consider the common agentic development failure mode. The ticket says "reduce our token spend," and it never says which workflow, what the budget is, or how anyone will know it worked. The agent goes looking, rewrites prompts that were never the expensive part, builds tests around its own reading of the problem, watches CI fail, pulls in more context, and tries again until it opens a credible-looking pull request that a senior engineer has to unwind. Nothing in that sequence is science fiction. It is Tuesday. The old cost was frustration. The new cost is frustration plus tokens plus review time plus opportunity cost plus whatever defect sneaks through because everyone wanted the automation story to be true. This is where I will repeat the thing I've been saying for years, because the economics have finally caught up to it. Unclear work was expensive before anyone metered it, and it is more expensive now. The real constraint is whether the work is specified well enough for a machine to do it without spinning in place. A vague request that sends an agent in circles used to cost a little patience. Now it shows up as a number on a dashboard. We made implementation cheaper, so the value moved upstream to specification. Usage-based pricing just attached a price tag to every fuzzy spec in your backlog. So the leaderboard era ends, and good riddance. Tokens consumed was always a vanity metric, the engineering equivalent of measuring a book by its page count. The number that replaces it is value per token, and that's a far better question to organize a team around. Value per token rewards clarity and reliability. It rewards teams that know how to decompose work, and engineers who can define acceptance criteria, constrain the search space, and recognize when the machine is confidently wrong. Conveniently, those are the same skills that made the layoff boomerang so predictable. One caution before anyone declares the party over: Jevons still cuts both ways. As models get more efficient and inference gets cheaper per unit, total usage will keep climbing. The end of the subsidy ends unmeasured AI adoption. That's maturity rather than contraction, the moment a fast-growing technology starts behaving like a real business, with a meter, a profit and loss statement, and consequences. ## Where this leaves the rest of us If you lead an engineering organization, the worst response is to pick a tribe. The "AI is fake" camp will miss a real shift in how software gets built. The "fire everyone" camp is about to learn what Klarna learned, on a delay, with a rehiring bill attached. The honest path is less dramatic and more durable. Track AI spend by workflow before you track it by user. A power user burning tokens on high-value migrations may be a bargain. A team burning the same tokens because its backlog is unclear is lighting money on fire, and the meter now tells you exactly how much. Measure accepted output rather than generated output. Code written is not value, and neither is a merged pull request on its own. Look at cycle time, escaped defects, rework, customer outcomes, and operational load. Require better specs before unleashing long-running agents. Agentic work still needs product thinking, architecture, and engineering judgment, and it punishes their absence faster. Treat AI displacement like a production change. Define the expected outcome, monitor the impact, preserve a rollback path, and know which humans still own the failure modes. If you wouldn't remove a database without a recovery plan, don't remove institutional knowledge without one either. And keep your best operators close. The people who understand the messy middle of the business are the ones who will make AI useful. They know where the process bends, where the system lies, where the customer gets stuck, and where the documentation stopped being true three reorganizations ago. That knowledge is expensive to rebuild because it was expensive to earn. As for Dorsey's prediction, we'll know soon enough. Maybe he read the future early and the rest of us are simply slow. Or maybe Block becomes the case study in someone's paper about boomerangs. Either way, the free lunch is over, the bill is itemized, and the companies that read it carefully are going to do very well. --- ### Sources and further reading - Block, Q4 2025 shareholder letter: https://s29.q4cdn.com/628966176/files/doc_financials/2025/q4/Q4-2025-Shareholder-Letter_Block.pdf - Reuters, "Block shares soar as Dorsey leans on AI to trim workforce": https://www.reuters.com/sustainability/sustainable-finance-reporting/block-shares-soar-dorsey-leans-ai-trim-workforce-2026-02-27/ - GitHub, "GitHub Copilot is moving to usage-based billing": https://github.blog/news-insights/company-news/github-copilot-is-moving-to-usage-based-billing/ - GitHub Docs, "Model multipliers for annual plans on request-based billing": https://docs.github.com/en/copilot/reference/copilot-billing/request-based-billing-legacy/model-multipliers-for-annual-plans - Reuters Breakingviews, "Anthropic IPO could train a large M&A model": https://www.reuters.com/commentary/breakingviews/anthropic-ipo-could-train-large-ma-model-2026-06-02/ - Axios, "Anthropic faces AI spending backlash before IPO": https://www.axios.com/2026/06/02/anthropic-ipo-ai-sticker-shock-spending-usage - Business Insider, "Klarna is reassigning engineers and marketers to customer support after its AI bet went too far": https://www.businessinsider.com/klarna-reassigns-workers-to-customer-support-after-ai-quality-concerns-2025-9 - Careerminds, "AI-led layoffs: What HR leaders wish they knew before making job cuts": https://careerminds.com/blog/cost-of-ai-layoffs - Challenger, Gray & Christmas, "April Job Cuts Rise 38% from March; YTD Cuts Down 50%": https://www.challengergray.com/blog/challenger-report-april-job-cuts-rise-38-from-march-ytd-cuts-down-50/ --- ## The Agent Team Tax: When AI Agents Need to Argue - **Published:** 2026-05-28 - **Tags:** claude-code, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-05-28-agent-team-tax/ Two of my Claude Code teammates spent part of last Tuesday arguing about a lockfile. The dependencies teammate said a missing `package-lock.json` was a high-severity finding. A reproducibility issue. Builds drift, environments diverge, and debugging gets harder. Annoying, but not automatically catastrophic. The security teammate disagreed. Without deterministic resolution, dependency installation can change underneath you. That is not just a reproducibility inconvenience. It is the same class of supply-chain risk that made the [event-stream incident](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident) so painful: a trusted dependency path changed, a malicious package entered the tree, and developers had to reason backward from a compromised build. Neither teammate was wrong. They were looking at the same finding through different domain lenses. The right answer was to let both ratings stand and add a cross-reference layer on top. I did not tell them to reach that resolution. They worked it out by messaging each other while I watched. That moment is the thing agent teams exist to enable. It is also the rarest thing that happened during the build. Most of what the team did could have been handled by plain subagents at a fraction of the cost. Knowing the difference is what this post is about. ## What agent teams are A quick refresher, since the terminology gets muddled fast. Subagents in Claude Code are workers that the main session spawns, delegates work to, and collects results from. They do not talk to each other. They report up. [Agent teams](https://code.claude.com/docs/en/agent-teams) are different. Each teammate is a separate Claude Code session with its own context window. They share a task list. They send each other messages. They can disagree, negotiate, and resolve things without the lead brokering every exchange. Both patterns parallelize work. Only one lets the workers coordinate as peers. ![Subagents vs. Agent Teams](/images/blog/2026/05/subagents-vs-agent-teams.png) *Subagents report up to the lead. Agent teams coordinate as peers through a shared task list.* Anthropic's docs are clear that agent teams use significantly more tokens than a single session. Each teammate has its own context window, and token usage scales with the number of active teammates. The docs also call out coordination overhead and diminishing returns as team size grows. One third-party estimate from Verdent puts a 3-agent team at roughly 7x the token usage of a standard single-agent session. I would not treat that as an Anthropic benchmark, but it is a useful field estimate. Your mileage will vary with model choice, team size, repo size, and workflow length. Agent teams are experimental and disabled by default. To enable them, set `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` to `1` in your `settings.json` or shell environment. You also need Claude Code v2.1.32 or later. That cost profile is the entire question. Agent teams are not faster subagents. They are a more expensive coordination pattern. The work has to need that coordination. ## The demo: a repo health auditor I wanted to test agent teams on something real, not a research exercise. So I asked the team to build a CLI tool called `repo-health`. It audits a Git repository across four domains: dependencies, security, test coverage, and CI configuration. The output is a Markdown report with structured findings. Four domains, four teammates, one shared codebase. The kind of work that looks parallelizable on the surface but has overlapping concerns underneath. A missing lockfile is a dependencies finding and a security finding. An untested error path is a test coverage finding and a CI finding when CI does not run tests. The interesting question was whether the team would notice those overlaps and do something useful with them.
Here is the full prompt I used. ```` Create an agent team to build a small but production-quality CLI tool called "repo-health" that audits a Git repository and produces a structured report. The tool should: - Accept a path to a local Git repo as an argument - Output a Markdown report with findings across four domains - Be written in TypeScript with Node.js, using a single dependency footprint (commander for CLI parsing, nothing else heavy) - Include a README, a working test suite, and a sample report run against this repo itself Spawn four specialist teammates. Each one owns a domain and a corresponding module in the codebase: 1. Dependencies teammate: parses package.json and lockfiles, reports local dependency hygiene signals, flags missing deterministic install inputs, and notes license risk where local metadata supports it. 2. Security teammate: scans for common smells (hardcoded secrets, unsafe regex, dangerous shell calls, missing input validation on CLI args). 3. Test coverage teammate: inspects the test setup, identifies untested modules and error paths, and reports coverage gaps. 4. CI configuration teammate: reads .github/workflows or equivalent, checks whether tests appear to run, notes whether local repo data can verify security scans, and calls out that merge-blocking behavior requires branch protection or repository ruleset data outside the local repo. Coordination requirements, not just parallel work: - Before any teammate writes code, all four must agree on the shared report schema (the TypeScript interface for a Finding) so their outputs compose cleanly. Have them negotiate this in the shared task list. - When the security teammate finds an issue tied to a dependency, it must message the dependencies teammate so the recommendation accounts for it. - When the test coverage teammate finds a gap, it must message the CI teammate to verify whether CI would have caught the gap. - Have them surface at least two genuine disagreements during the build (for example, severity ratings, or whether a finding belongs to one domain or another) and resolve them through direct messaging, not by escalating to the lead. Lead responsibilities: - Require plan approval before any teammate writes code. Only approve plans that include test coverage for the module. - Synthesize the final report structure and write the top-level CLI entry point that composes the four specialist modules. - After the tool is built, run it against this repo and include the output in the README as a worked example. Quality gates: - Every module must have at least one passing test. - No teammate may edit another teammate's module without sending a message explaining why. - The final report must include a "limitations" section written by the lead. When the build is complete, produce a postmortem document covering: which teammate-to-teammate messages actually changed an outcome, where coordination overhead exceeded its value, and what would have worked better as plain subagents. ````
The prompt does three deliberate things. It forces real peer coordination at the moment of the schema contract. It demands at least two genuine disagreements, which prevents the team from drifting into polite parallel work. And it ends with a postmortem requirement, which gives me primary-source material for honest analysis instead of opinion. One note on plan approval mode, which the prompt invokes. Each teammate submitted a plan before writing code. The lead approved all four on the first pass, since each plan included test coverage and stayed within scope. No rejections, no rework. That outcome is worth flagging. Plan approval is most valuable when the lead has clear criteria to enforce and a real chance of catching a plan that misses the mark. For a well-specified prompt like this one, plan approval added latency without catching anything. For a riskier task, it would be the most important guardrail in the workflow. ## What the team built The output landed in about two and a half minutes of wall-clock time. That measure covers the parallel implementation phase only, not the planning, schema definition, or postmortem write-up. The full session from prompt to final report ran closer to 15 minutes. The final shape: | Role | Module | Tests | Findings Produced | |---|---|---|---| | Lead | index.ts, report.ts, enrichment.ts | 4 | Composition | | Dependencies | analyzers/dependencies.ts | 6 | 7 finding types | | Security | analyzers/security.ts | 6 | 5 finding types | | Test Coverage | analyzers/test-coverage.ts | 4 | 5 finding types | | CI Configuration | analyzers/ci.ts | 2 | 5 finding types | Eight source files. Five test files. Twenty-two tests, all passing. One runtime dependency. Twenty-two finding types across four domains. That part of the story is unremarkable. Plain subagents would have produced something similar. The interesting part is what happened between the teammates. One important constraint: `repo-health` only reads the local repository. It does not call npm registry data, OSV, the GitHub Advisory Database, or private package registries. That means the dependency analyzer can report dependency hygiene signals from local files, but it cannot authoritatively identify outdated packages or known vulnerable versions. That distinction matters. A tool that reads files can flag risk. A tool that claims vulnerability intelligence needs a vulnerability data source. ## The message threads that mattered Four coordination threads stood out. Three changed the output. One was ceremony. ### Thread one: the lockfile argument This is the one I opened with. The security teammate pushed for critical severity on the missing lockfile finding. The dependencies teammate held the line at high. They resolved it without me by deciding that severity is domain-relative. Each module keeps its own rating, and the enrichment layer cross-references the security context when both domains flag related issues. The result is visible in the final report. A user looking at DEP-002 sees "high severity, reproducibility risk" with an annotation that the security analyzer also considers this a supply-chain exposure. Neither domain had to overstep its scope. The reader gets the full picture. This exchange would not have happened as a peer-to-peer debate with subagents. A single agent doing all four analyses would have picked one severity rating and moved on. Possibly the wrong one for whichever domain was last on its mind. ### Thread two: the CI gap escalation The test coverage teammate found three source files with no corresponding tests. Before reporting the finding, it messaged the CI teammate: > "I found 3 source files with no corresponding test. Does CI run tests at all?" The CI teammate's response was more useful than a simple yes or no: > "No local CI configuration detected. These gaps are invisible to automation from the repository data I can inspect. Merge-blocking behavior would require branch protection or repository ruleset data outside this repo." That exchange triggered the enrichment logic. Every test coverage finding now appends a warning: "Warning: no local CI workflow was found, so this gap would not be caught automatically by repository automation." The report also avoids claiming whether failed checks block merges, because [GitHub requires status checks through branch protection or rulesets](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches). A local file scan cannot prove that. A single agent could have produced this connection, but it would have required holding both domains in working memory at the same time. The team structure made the cross-reference cheap and explicit. ### Thread three: the eval-in-tests disagreement The security teammate's initial implementation flagged every use of `eval()` in the codebase. That included test helpers, where dynamic execution can be legitimate when the test is exercising dynamic code paths. The test coverage teammate pushed back: > "eval() in test helpers can be legitimate for testing dynamic code paths. Treating it the same as production eval usage creates noise that drowns out real findings." They resolved it by treating test-file matches differently. The analyzer now distinguishes production code from test code and downgrades test-only dynamic execution to a lower-risk annotation rather than treating it like a production finding. That nuance matters. Test code still executes in CI and can have access to secrets, so test-only dynamic execution should not disappear entirely. But it should not drown out production findings either. This is exactly the kind of judgment call where domain challenge improves the result. There is a second detail worth flagging. The security analyzer still risks false positives when regex patterns contain the literal string `eval(` as detection logic. The team noted this as a known limitation of regex-based detection rather than pretending the analyzer was smarter than it was. That kind of self-aware limitation is exactly what I want from analysis tooling. The lead carried that self-awareness into the final report. Its limitations section calls out three things. Regex-based security detection has known false positives. Dependency checks are limited to local repository data unless the tool connects to registry or advisory sources. The test coverage analyzer infers gaps from file naming rather than running coverage instrumentation. None of those are surprises. All of them are the kind of caveats I would want a junior engineer to surface in a code review. The fact that the lead synthesized them from teammate findings, rather than me prompting for each one, is a small win. ### Thread four: schema negotiation The prompt required all four teammates to agree on the shared report schema before writing code. In practice, the lead defined the `Finding` interface, the four teammates read it, and nobody proposed a change. The negotiation was zero rounds long. ```typescript interface Finding { id: string; // e.g. "DEP-002" domain: Domain; // "dependencies" | "security" | "test-coverage" | "ci" severity: Severity; // "low" | "medium" | "high" | "critical" title: string; description: string; remediation: string; file?: string; line?: number; } ``` Eight fields. Universal across all four domains. Nothing to negotiate. The schema was simple enough that top-down definition was strictly faster than ceremony. This is the most contrarian finding in the build, and the one I want engineering leaders to read carefully. A lot of multi-agent advice recommends upfront contract negotiation between agents. My data suggests that advice is conditional, not universal. Negotiation has a fixed cost. The schema's complexity has to clear that bar before the cost pays off. When would negotiation matter? If the security teammate had wanted a `cweId` field, or dependencies had wanted a `packageManager` field, the negotiation would have surfaced those tensions early. For a flat universal schema, the lead just writes the interface. ## The honest comparison: agent team versus subagents Here is where the build's data lines up against the alternatives. I went back through every coordination point and asked whether plain subagents would have produced the same outcome. | Aspect | Agent Team | Plain Subagents | Better As | |---|---|---|---| | Schema agreement | Four agents acknowledge a schema | Lead defines, subagents consume | Plain subagent | | Parallel module implementation | Four named teammates | Four anonymous subagents | Plain subagent | | Cross-module enrichment | Agents message each other | Lead or reviewer post-processes results | Either works | | Disagreement resolution | Agents debate via messages | Lead decides or reviewer adjudicates | Agent team | | Quality review | Teammates challenge each other | Dedicated reviewer subagent | Plain subagent | Three of five categories were better served by plain subagents. One was a wash. One genuinely benefited from the agent team structure. If you are wondering whether that ratio justifies the token multiplier reported for agent teams, you are asking the right question. For this particular task, it probably did not. The messages that changed outcomes were valuable. I could have approximated the same result with a dedicated reviewer subagent running after the four analyzers completed. Cheaper, simpler, and the reviewer would have had the full codebase context to work from. The agent team earned its premium on exactly one dimension: surfacing genuine domain conflict. That is rare in most tasks. It is real in some. ## When agent teams are worth it Four coordination threads are a small sample, but the pattern matches what Anthropic's docs describe. Agent teams pay off when the work has all three of these properties: 1. Multiple domains with legitimate authority. The security teammate and the dependencies teammate disagreed because both were right within their own scope. If one domain trumps the others by default, you do not need a team. You need that one domain plus subagents. 2. Decisions that benefit from challenge. Severity ratings, boundary calls, naming choices, architectural splits. Things where a single agent's first answer is plausible but not necessarily the best. A team forces the second opinion to be earned, not assumed. 3. Work that is independent enough to parallelize but interlocked enough to need coordination. If the modules are truly independent, you want subagents. If they are deeply coupled, you want one session. Agent teams sit in the narrow middle. The `repo-health` build hit two of those three. The four domains had legitimate authority. The severity decisions benefited from challenge. But the modules were genuinely independent, which made most of the team overhead unnecessary. A better fit for agent teams: cross-layer debugging where frontend, backend, and database changes interact in non-obvious ways. PR reviews where security, performance, and test coverage need to be argued against each other rather than reported side by side. Hypothesis-driven incident investigation where five competing theories need to challenge each other until one survives. A worse fit: anything where the work decomposes cleanly into independent slices. Most refactors. Most feature implementations. Most analysis tasks where the domains do not overlap. ## What I would do differently If I built `repo-health` again, I would not use an agent team. I would use four subagents with distinct prompts. A dedicated reviewer subagent would run after they complete and produce the enrichment annotations from a single context. That setup would have caught the lockfile argument as a reviewer note rather than a teammate debate, which is fine. It would have caught the eval-in-tests issue as a refinement pass rather than an inter-agent message, which is also fine. The outcomes that mattered would have been preserved at a fraction of the token cost. What I would keep from this experiment is the prompt structure for tasks that need teams. The "surface at least two genuine disagreements" instruction is the one I would carry forward. Without it, teams default to polite parallel work and you pay the team premium for subagent value. The other keeper is the postmortem requirement. Any time I run an agent team in the future, the team will produce a postmortem analyzing its own coordination patterns. That document is the difference between speculation and evidence about when this pattern is worth it. Agent teams in Claude Code are a real capability. They do something subagents cannot do, and they cost significantly more to do it. The question is whether your work produces enough of that something to justify the price. For `repo-health`, the answer was probably no. For cross-layer debugging or adversarial code review, the answer is probably yes. For most of the daily engineering work that fills a sprint, the answer is almost certainly no, and the right tool is still subagents. The bottleneck was never the stack. In this case, it was not the model either. It was whether the work required the model to argue with itself. Most work does not. --- ## Workflow.ts: When the Code Runs the Agent, Not the Other Way Around - **Published:** 2026-05-26 - **Tags:** ai-strategy, genai, engineering-leadership, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-05-26-context-spine-workflow-js/ The default mental model for AI-assisted work is the agent loop. Give the model a goal, a set of tools, and a system prompt. It decides what to do next based on what just happened. The control flow belongs to the model. The inversion is simple. You define the steps in code. Each step invokes the model with a tightly scoped prompt and a tightly scoped tool boundary. The output of one step becomes the input of the next, validated by code, not by another model call. The control flow belongs to the engineer. That trade is not subtle. | Dimension | Agent loop | Workflow | | :--- | :--- | :--- | | **Control flow** | Model decides | Code decides | | **Token cost** | High and variable | Bounded and predictable | | **Debuggability** | Trace the model's reasoning | Read the code | | **Security surface** | Whatever the model picks up | Whatever you allowlist | | **Failure modes** | Discovered at runtime | Tested at build time | | **Best for** | Open-ended exploration | Knowable, repeatable work | Most real engineering work sits closer to the second column than the first. We keep reaching for the agent loop because it is what the tools default to, not because it is what the work needs. The honest answer to "should I build this today or wait?" Build it today if you have one workflow that already runs by hand and you want to make it inspectable, governable, and cheap. Wait if you are looking for a polished framework. Anthropic appears to have a `Workflow` tool in flight (a [changelog line for 2.1.147](https://github.com/anthropics/claude-code/commit/c6b849f27118d97ed57d6067eeb269750b2e647e) referenced it before being pulled), and when it ships, the official version will almost certainly be better than what I show below. The pattern, though, will be the same. Building the rough version now is how you learn what to ask of the official one when it lands. I have written before about the [spec, standards, specialists loop](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/) and the [Context Spine](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) as the durable artifact that travels through it. Both posts were about pattern. This one is about the code, and the day I caught the workflow doing something an agent loop would have missed. ## The moment the inversion clicked Here is the representative failure mode that made the pattern click. The spec was small: a slugify function with four acceptance criteria and a coverage threshold of 0.85. The plan step produced a clean file list. The implement step compiled and linted. The test step passed. Coverage cleared the threshold. Three for three. That is exactly where this kind of work gets dangerous. The review step blocked. It mapped each acceptance criterion to evidence in the diff and found one criterion with no asserting test: "collapse consecutive hyphens." The implementation handled it correctly, the path executed in another test as a side effect, and line coverage looked healthy. The acceptance criterion was satisfied in production and unverified in CI. A coverage-only completion check would have shipped that. Tests were green. Coverage was high enough. The workflow asked a different question: does every acceptance criterion have evidence? It did not. The validator failed closed. That is the inversion in one paragraph. The model still did the judgment work. The code decided what counted as done. ## The Context Spine, in code [The Spec Is the Product](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/) made the case for a versioned specification as the source of truth. The companion idea is the Context Spine, which I introduced in [*The Agentic SDLC*](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/): the structured artifact that carries the spec, the plan, the implementation notes, and the review findings through every stage of the pipeline. In an agent loop, the spine lives in the model's context window. It gets compressed, paraphrased, and occasionally forgotten as the conversation grows. In a workflow, the spine lives on disk and in code. Each step reads it, enriches it, and writes it back. No paraphrase. No forgetting. That is the design goal of the file below. ## What the workflow does Four steps. One spec in. One result out. 1. Plan: Read the spec. Explore the codebase. Produce a JSON plan of files to touch, the approach, and known risks. Read-only tools. 2. Implement: Take the plan. Write the code. Validate by running the build and the linter. Fail if implementation touches files outside the plan. 3. Test: Write tests that map to each acceptance criterion. Run the suite. Validate coverage against the spec's minimum. 4. Review: Read the diff. Map every acceptance criterion to evidence in the code. Block on uncovered criteria or blocking findings. Every step has a deterministic gate. Build passes. Lint passes. Coverage clears the threshold. The review step asks the model to map each acceptance criterion to concrete evidence, then the validator checks that every cited file and line range exists. The model proposes the evidence. Code decides whether the step passed. ## A note on the SDK before the code Two details in the [Claude Agent SDK](https://docs.claude.com/en/docs/agent-sdk/typescript) are easy to get wrong, and getting them wrong silently breaks the whole pattern. I will name both here so the code below makes sense. `allowedTools` is the auto-approval list, not the restriction list. The SDK docs are explicit: passing `["Read", "Grep"]` does not mean "the model can only use Read and Grep." It means "Read and Grep are pre-approved without prompting." To get actual restriction, you pair `allowedTools` with `permissionMode: "dontAsk"`, which denies anything not on the list without prompting. The combination is the real security boundary. The popular `acceptEdits` mode auto-approves edits but does not restrict which tools the model can reach for. I caught this before publishing, but a less careful version of me would have shipped a workflow that claimed to enforce a boundary it did not enforce. Tool errors arrive in user messages, not assistant messages. The SDK runs an internal loop. When the model emits a `tool_use` block in an assistant message, the SDK executes the tool and injects the result back into the stream as a `tool_result` block on the next user message. The `is_error` flag lives on `tool_result`. Watching `tool_use` blocks for errors is a silent no-op. Both details below are wired correctly. If the official Workflow tool ships and handles this for you, you can stop thinking about either one. ## The file This is `workflow.ts`. About 390 lines, with dependencies kept to `@anthropic-ai/claude-agent-sdk@0.3.150` and Zod. I type-checked this version locally on Node 22 with TypeScript strict mode and `skipLibCheck` enabled. The `skipLibCheck` caveat matters: the SDK package's own declaration files currently surface unresolved internal type references when library checking is enabled. The point is not to ship a framework. The point is to show what the inversion looks like when you can read the whole thing in one screen. ```typescript // workflow.ts // Context Spine handoff: spec -> plan -> implement -> test -> review. // Code owns the control flow. The model owns the judgment per step. // // Tested against @anthropic-ai/claude-agent-sdk@0.3.150 on Node 22. // Pin your version. The SDK API has shifted in 2026. import { query, type SDKMessage } from "@anthropic-ai/claude-agent-sdk"; import { execSync } from "node:child_process"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { z } from "zod"; // Spec contract: the Context Spine artifact const SpecSchema = z.object({ id: z.string(), title: z.string(), intent: z.string(), acceptanceCriteria: z.array(z.string()).min(1), affectedPaths: z.array(z.string()), constraints: z.object({ language: z.enum(["typescript", "python", "go"]), testFramework: z.string(), minCoverage: z.number().min(0).max(1).default(0.8), buildCmd: z.string().default("npm run build"), lintCmd: z.string().default("npm run lint"), testCmd: z.string().default("npm test -- --coverage"), }), }); type Spec = z.infer; // Step result envelope type StepResult = { step: string; output: T; tokensUsed: number; durationMs: number; }; type ValidationResult = { ok: true } | { ok: false; reason: string }; // Core step runner async function runStep(opts: { name: string; prompt: string; systemPrompt: string; allowedTools: string[]; cwd: string; parse: (raw: string) => T; validate: (parsed: T) => ValidationResult; maxRetries?: number; }): Promise> { const start = Date.now(); let lastError = ""; let tokens = 0; for (let attempt = 1; attempt <= (opts.maxRetries ?? 2); attempt++) { const stream = query({ prompt: attempt === 1 ? opts.prompt : `${opts.prompt}\n\nPrevious attempt failed validation: ${lastError}. Fix and retry.`, options: { systemPrompt: opts.systemPrompt, allowedTools: opts.allowedTools, cwd: opts.cwd, model: "opus", // 'dontAsk' is the real restriction mode: anything not in allowedTools // is denied without prompting. 'acceptEdits' only auto-approves; it does // NOT restrict which tools the model can reach for. permissionMode: "dontAsk", maxTurns: 20, }, }); let finalText = ""; let toolError: string | null = null; for await (const msg of stream as AsyncIterable) { // Tool errors come back as tool_result blocks inside user messages. if (msg.type === "user") { const content = msg.message.content; if (Array.isArray(content)) { for (const block of content as unknown as Array>) { if (block.type === "tool_result" && block.is_error === true) { toolError = `tool ${String(block.tool_use_id ?? "unknown")} errored`; } } } } if (msg.type === "result") { if (msg.subtype === "success") { finalText = msg.result; } else { lastError = `SDK returned non-success: ${msg.subtype}`; } tokens += (msg.usage?.input_tokens ?? 0) + (msg.usage?.output_tokens ?? 0); } } if (toolError && !finalText) { lastError = toolError; continue; } try { const parsed = opts.parse(finalText); const check = opts.validate(parsed); if (check.ok) { return { step: opts.name, output: parsed, tokensUsed: tokens, durationMs: Date.now() - start }; } lastError = check.reason; } catch (e) { lastError = `parse failed: ${(e as Error).message}`; } } throw new Error(`Step '${opts.name}' failed after retries: ${lastError}`); } // Shell helpers function runShell(cmd: string, cwd: string, timeoutMs = 120_000): ValidationResult { try { execSync(cmd, { cwd, stdio: "pipe", timeout: timeoutMs }); return { ok: true }; } catch (e) { const msg = (e as Error).message.slice(0, 1_000); return { ok: false, reason: `'${cmd}' failed: ${msg}` }; } } function runShellText(cmd: string, cwd: string, timeoutMs = 120_000): { ok: true; stdout: string } | { ok: false; reason: string } { try { const stdout = execSync(cmd, { cwd, encoding: "utf8", stdio: "pipe", timeout: timeoutMs }); return { ok: true, stdout }; } catch (e) { const msg = (e as Error).message.slice(0, 1_000); return { ok: false, reason: `'${cmd}' failed: ${msg}` }; } } function lines(stdout: string): string[] { return stdout.split("\n").map(line => line.trim()).filter(Boolean); } function changedFiles(cwd: string): { ok: true; files: string[] } | { ok: false; reason: string } { const tracked = runShellText("git diff --name-only --diff-filter=ACMRTUXB", cwd); if (!tracked.ok) return tracked; const untracked = runShellText("git ls-files --others --exclude-standard", cwd); if (!untracked.ok) return untracked; return { ok: true, files: [...new Set([...lines(tracked.stdout), ...lines(untracked.stdout)])] }; } // Step 1: Plan const PlanSchema = z.object({ files: z.array(z.object({ path: z.string(), action: z.enum(["create", "modify", "delete"]), purpose: z.string(), })), approach: z.string(), risks: z.array(z.string()), }); type Plan = z.infer; async function planStep(spec: Spec, cwd: string) { return runStep({ name: "plan", cwd, allowedTools: ["Read", "Grep", "Glob"], systemPrompt: "You are a senior engineer producing implementation plans. Output ONLY valid JSON. No prose.", prompt: ` Spec: ${JSON.stringify(spec, null, 2)} Explore the codebase at ${cwd}. Produce a JSON plan: { "files": [{"path": "...", "action": "create|modify|delete", "purpose": "..."}], "approach": "2-3 sentences", "risks": ["..."] } `.trim(), parse: (raw) => PlanSchema.parse(JSON.parse(extractJson(raw))), validate: (plan) => { if (plan.files.length === 0) return { ok: false, reason: "empty file list" }; const planned = new Set(plan.files.map(f => f.path)); const covered = spec.affectedPaths.every(p => planned.has(p)); return covered ? { ok: true } : { ok: false, reason: "plan missing files from spec.affectedPaths" }; }, }); } // Step 2: Implement const ImplementSchema = z.object({ filesChanged: z.array(z.string()), }); async function implementStep(spec: Spec, plan: Plan, cwd: string) { return runStep({ name: "implement", cwd, allowedTools: ["Read", "Edit", "Write", "Bash"], systemPrompt: "Implement the planned change. Touch only files in the plan. Match existing code style.", prompt: ` Spec: ${spec.title} Intent: ${spec.intent} Plan: ${JSON.stringify(plan, null, 2)} When done, output: {"filesChanged": ["path1", "path2"]} `.trim(), parse: (raw) => ImplementSchema.parse(JSON.parse(extractJson(raw))), validate: (result) => { const build = runShell(spec.constraints.buildCmd, cwd); if (!build.ok) return build; const lint = runShell(spec.constraints.lintCmd, cwd); if (!lint.ok) return lint; const actual = changedFiles(cwd); if (!actual.ok) return actual; const planned = new Set(plan.files.map(f => f.path)); const stray = actual.files.filter(f => !planned.has(f)); if (stray.length) { return { ok: false, reason: `actual diff touched files outside plan: ${stray.join(", ")}` }; } const reported = new Set(result.filesChanged); const missingFromManifest = actual.files.filter(f => !reported.has(f)); if (missingFromManifest.length) { return { ok: false, reason: `manifest omitted changed files: ${missingFromManifest.join(", ")}` }; } return { ok: true }; }, }); } // Step 3: Test const TestSchema = z.object({ coverage: z.number().min(0).max(1) }); async function testStep(spec: Spec, cwd: string) { return runStep({ name: "test", cwd, allowedTools: ["Read", "Edit", "Write", "Bash"], systemPrompt: "Write tests covering every acceptance criterion. Use the project's existing test framework.", prompt: ` Spec: ${JSON.stringify(spec, null, 2)} Each acceptance criterion needs at least one test. Run the suite. Output: {"coverage": 0.NN} `.trim(), parse: (raw) => TestSchema.parse(JSON.parse(extractJson(raw))), validate: (result) => { const tests = runShell(spec.constraints.testCmd, cwd); if (!tests.ok) return tests; if (result.coverage < spec.constraints.minCoverage) { return { ok: false, reason: `coverage ${result.coverage} below minimum ${spec.constraints.minCoverage}` }; } return { ok: true }; }, }); } // Step 4: Review const EvidenceSchema = z.object({ file: z.string(), lineStart: z.number().int().positive(), lineEnd: z.number().int().positive(), note: z.string(), }); const ReviewSchema = z.object({ verdict: z.enum(["approve", "request_changes", "block"]), findings: z.array(z.object({ severity: z.enum(["info", "warn", "blocker"]), file: z.string(), note: z.string(), })), acceptanceCoverage: z.array(z.object({ criterion: z.string(), covered: z.boolean(), evidence: z.array(EvidenceSchema).min(1), })), }); function validateEvidenceLocations(review: z.infer, cwd: string): ValidationResult { for (const item of review.acceptanceCoverage) { for (const evidence of item.evidence) { const path = resolve(cwd, evidence.file); if (!existsSync(path)) { return { ok: false, reason: `evidence file does not exist: ${evidence.file}` }; } if (evidence.lineEnd < evidence.lineStart) { return { ok: false, reason: `invalid evidence range: ${evidence.file}:${evidence.lineStart}-${evidence.lineEnd}` }; } const lineCount = readFileSync(path, "utf8").split("\n").length; if (evidence.lineEnd > lineCount) { return { ok: false, reason: `evidence range exceeds file length: ${evidence.file}:${evidence.lineStart}-${evidence.lineEnd}` }; } } } return { ok: true }; } async function reviewStep(spec: Spec, cwd: string) { return runStep({ name: "review", cwd, allowedTools: ["Read", "Grep", "Glob", "Bash"], systemPrompt: "Map every acceptance criterion to concrete evidence in the diff. Block on security or correctness issues.", prompt: ` Spec: ${JSON.stringify(spec, null, 2)} Run \`git diff\`. For each acceptance criterion, cite the file and line range that proves it. Output JSON matching the review schema. `.trim(), parse: (raw) => ReviewSchema.parse(JSON.parse(extractJson(raw))), validate: (review) => { const uncovered = review.acceptanceCoverage.filter(c => !c.covered); if (uncovered.length) return { ok: false, reason: `uncovered: ${uncovered.map(c => c.criterion).join("; ")}` }; const evidence = validateEvidenceLocations(review, cwd); if (!evidence.ok) return evidence; const blockers = review.findings.filter(f => f.severity === "blocker"); if (blockers.length) return { ok: false, reason: `${blockers.length} blocking findings` }; return { ok: true }; }, }); } // Workflow orchestrator export async function contextSpineWorkflow(specPath: string, cwd: string) { const spec = SpecSchema.parse(JSON.parse(readFileSync(specPath, "utf8"))); const plan = await planStep(spec, cwd); const impl = await implementStep(spec, plan.output, cwd); const tests = await testStep(spec, cwd); const review = await reviewStep(spec, cwd); const summary = { spec: spec.id, plan: plan.output, implementation: impl.output, tests: tests.output, review: review.output, totalTokens: plan.tokensUsed + impl.tokensUsed + tests.tokensUsed + review.tokensUsed, totalMs: plan.durationMs + impl.durationMs + tests.durationMs + review.durationMs, }; mkdirSync(`${cwd}/.spine`, { recursive: true }); writeFileSync(`${cwd}/.spine/${spec.id}-result.json`, JSON.stringify(summary, null, 2)); return summary; } function extractJson(raw: string): string { const match = raw.match(/```(?:json)?\s*([\s\S]*?)```/); return (match ? match[1] : raw).trim(); } async function main() { const [, , specPath, repoPath] = process.argv; if (!specPath || !repoPath) { console.error("Usage: tsx workflow.ts "); process.exitCode = 1; return; } const result = await contextSpineWorkflow(specPath, repoPath); console.log(JSON.stringify(result, null, 2)); } const isDirectRun = process.argv[1] === fileURLToPath(import.meta.url); if (isDirectRun) { main().catch((error: unknown) => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; }); } ``` ## The spec, on disk Every step reads from this file. It is the Context Spine. The MFA content below is an example contract, not a claim about a live endpoint. ```json { "id": "AUTH-142", "title": "Add MFA enrollment endpoint", "intent": "Users can enroll in TOTP-based MFA from account settings", "acceptanceCriteria": [ "POST /auth/mfa/enroll returns a TOTP secret and QR code URI", "Secret is encrypted at rest in the user record", "Endpoint requires authenticated session", "Replay attempts are rejected" ], "affectedPaths": ["src/auth/mfa.ts", "src/auth/mfa.test.ts"], "constraints": { "language": "typescript", "testFramework": "vitest", "minCoverage": 0.85, "buildCmd": "npm run build", "lintCmd": "npm run lint", "testCmd": "npm test -- --coverage" } } ``` That file is the artifact you version. It is the artifact you review. It is the artifact a future engineer or a future agent reads to understand what the system was supposed to do. The code that comes out of the workflow is the regenerable output. The spec is the durable input. This is the practical answer to the question I get from leaders thinking about this pattern: "What do we actually own when the AI writes the code?" You own the spec. You own the standards. You own the workflow. The code is what falls out. ## Running it ```bash npm install @anthropic-ai/claude-agent-sdk@0.3.150 zod npm install -D tsx typescript @types/node npm pkg set type=module export ANTHROPIC_API_KEY=... npx tsx workflow.ts ./specs/AUTH-142.json ./repo ``` To type-check the file the same way I did: ```bash npx tsc --noEmit --strict --skipLibCheck --module NodeNext --moduleResolution NodeNext --target ES2022 --types node workflow.ts ``` The result lands in `.spine/AUTH-142-result.json`. Plan, implementation manifest, test coverage, review verdict, total tokens, total wall clock. The whole workflow becomes inspectable. ## Where I would push back on my own design Two things I would flag if I were reviewing this in a code review. The retry loop is still naive: Two attempts by default. The truncated stderr helps, but a production version bounds retry with progressively narrower scope and falls back to opening a ticket for human review instead of throwing. The first version of any workflow should fail hard. The second version should fail gracefully. I am on version one. There is no checkpoint: If the implement step fails after the plan succeeded, the plan is lost. A production version writes the plan to disk before the implement step starts, so a re-run can resume from the last successful checkpoint. For a single-engineer use case, restarting is cheap. For a CI pipeline, it is not. Both are solvable. Both are the kind of engineering additions that turn a prototype into something you would run inside a regulated engineering organization. ## Where the workflow does not belong This pattern earns its keep on knowable, repeatable work. It does not belong on open-ended exploration. If I am debugging a production incident, I want the agent loop. The path is not known. I need the model to decide what to look at next based on what just happened. A workflow with predefined steps would slow me down. If I am implementing a spec with clear acceptance criteria, I want the workflow. The path is known. I want code to enforce the boundaries and validators to fail closed when something drifts. Both patterns belong in the same toolkit. The mistake is treating either one as the default for all engineering work. ## What changes when the official Workflow tool ships If Anthropic ships the Workflow tool hinted at in the removed changelog line, it should be better than what I built. When an official version lands, three things change. The orchestrator code in this post becomes easier to replace. An official tool should handle more of the agent loop, structured outputs, and retry semantics natively. What stays relevant is the Zod-validated spec, the deterministic validators, and the tool-scoping discipline. Those are the parts you would have to design either way. The integration surface gets cleaner. I would expect an official tool to hook into the Claude Code permission model, the existing subagent infrastructure, and the session resume machinery. A homegrown `workflow.ts` does none of that. The work you do today to define your spec schema and your validators carries forward. The orchestration layer underneath does not. The pattern gets easier to defend with platform and security partners. Saying "I use the official tool with a custom spec schema" is a much cleaner conversation than "I rolled my own orchestrator." If you are inside a regulated organization, waiting for the official abstraction may be worth it. If you are not, build the rough version now. It is the fastest way to learn what you want from the polished one. ## What changes Monday Five steps in order. 1. Pick one workflow that already runs by hand: A spec to PR loop. A weekly FinOps review. A compliance evidence gather. Something repeatable. 2. Write the spec contract in Zod: What is the input shape? What is the output shape? What are the deterministic validators between steps? If you cannot answer those questions, the work is not ready for a workflow yet. 3. Write the smallest possible orchestrator: Two steps, not four. One validator each. Run it once by hand. 4. Add a third step only when the absence of one hurts: This follows the exact same rule as with specialist agents. Build the role the moment you catch yourself wishing for one. 5. Log the spine: Every run writes a result file with the spec, the steps, and the validator outcomes. That file is the audit trail and the postmortem. The agent loop is a great default for personal productivity. It is a terrible default for production engineering. The workflow inversion is how the same model becomes governable, predictable, and cheap enough to run inside the systems we already trust. The model still did the judgment work. The code decided what counted as done. That distinction is what I will be defending in every conversation about this pattern for the next year. --- *The full working code, the example spec, and the type-check configuration live in the companion repo: [github.com/vscarpenter/context-spine-workflow-js](https://github.com/vscarpenter/context-spine-workflow-js). Clone it, run it, and break it. That is the fastest way to feel the inversion for yourself.* --- ## The Frame Is the Bottleneck - **Published:** 2026-05-24 - **Tags:** ai-strategy, ai-coding, learning, engineering-leadership, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-05-24-the-frame-is-the-bottleneck/ My thesis is that as agents get better at execution, the bottleneck moves upstream to framing. Last week, Claude Code handed me a credible-looking refactor for a service I had been refactoring for months. The plan was tight. The diff was clean. The tests passed. I read it twice and killed it. The model had solved the problem I wrote down, not the problem we actually had. That gap, the one between the prompt and the situation, is the whole game. Multiply it across lots of engineers, a multi-cloud footprint, and a growing portfolio of agentic workflows, and you have my Monday morning. Dan Shipper recently published a long essay called [After Automation](https://every.to/p/after-automation). His thesis: AI progress creates more work for humans, not less. Every, the media and software company behind a daily newsletter on what comes next in technology, is a 30-person team running Codex, Claude Code, and Cowork across every function, and their headcount keeps climbing. The judgment load is heavier than it was before they automated anything. I want to extend a few of his arguments from the vantage point of a Fortune 100 platform org. The picture changes when you scale from 30 people to a few hundred engineers operating across AWS, Azure, and a vendor ecosystem that won't slow down for anyone. ## Two modes, and the one most leaders miss Shipper splits agent work into two modes. The first is the obvious one: agent employees. These are bots in Slack with names and jobs, or embedded agents like Fin handling basic support conversations. The second is human-agent collaboration inside tools like Codex and Claude Code, where you and the agent share the same workspace, the same browser, the same files, and the same problem in real time. The first mode is what most executives picture when they hear "AI strategy." The second mode is where much of the actual leverage lives, and most leaders are still underinvesting in it. I run my whole day this way now: spec, plan, review, refine. The agent does the typing and I do the framing. By frame, I mean the explicit shape of the work rather than a better prompt: constraints, invariants, acceptance criteria, risks, non-goals, and the situational judgment a senior engineer usually carries in their head. Kieran Klaassen at Every calls this the human sandwich: a human sets the frame, the AI collapses the task, and a human judges and extends the result. The sandwich is a workflow shape. The top slice is a written spec and a defined acceptance test. The middle is one or more agent runs against that spec. The bottom slice is a human review that either ships the work or feeds the gap back into the spec for the next run. It's the same shape I describe in [Spec, Standards, Specialists](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/), and the shape my engineers are increasingly running every day. If your org is mostly optimizing for "give every employee a chatbot," you're probably underinvesting in the mode that matters most. ## Jevons, again Shipper doesn't name Jevons Paradox, but much of his argument behaves like one. > **Jevons Paradox:** When a technology makes a resource cheaper or more efficient to use, total consumption of that resource often rises instead of falls. AI makes yesterday's expert competence cheaper, so we use more of it. That expansion creates new demand for the next layer of judgment above it. The pattern is familiar. Compilers did not eliminate programmers, cloud did not eliminate operations, and Kubernetes did not eliminate platform engineers. Each layer commoditized the layer below and created appetite for expertise at the layer above. When writing code becomes effectively free, the organization's appetite for software explodes and output rises faster than headcount. We suddenly tackle the deep architectural debt, the niche automation pipelines, and the complex integration layers we used to defer. What's different this time is the speed. The cycle that used to take a decade now runs in quarters. The benchmark you ran in January is saturated by July, and the frame you designed in spring is the new floor by fall. The job is no longer to master a stack and wait for the next abstraction wave, but to keep framing faster than the frame collapses. Models climb frames. Leaders build them. ## The personal agent trap This is one of the most important parts of Shipper's essay, and I suspect many leaders will skim past it. Every gave every employee a personal agent. Then they pulled it back. Personal agents go stale fast because the humans they work with stop maintaining them. Every now runs agents at the team and org level, with a dedicated AI engineering function keeping them healthy. That is the difference between an AI initiative that compounds and one that quietly dies in 18 months. Agents are software. Software needs owners, telemetry, evals, on-call, and a backlog. Treat them like Lambda functions you forgot you deployed, and they will rot like Lambda functions you forgot you deployed. The unit of ownership has to be a team or a platform. If an agent matters to the business, it needs a product owner, a health model, evaluation data, and a path for change. It also needs someone who gets paged, literally or figuratively, when it starts making expensive nonsense with confidence. I've been saying this for a year, and Every just gave us the receipts. ## Smuggled intelligence and the Context Spine Shipper introduces a concept he calls smuggled intelligence: the hidden layer of human judgment baked into every prompt that makes a benchmark result possible. He dissects an OpenAI GDPval prompt that asks a model to perform audit sampling on financial crime metrics. The prompt is a wall of constraints: confidence levels, tolerable error rates, specific entities, risk weightings, and formatting requirements. By the time the model touches the problem, an expert has already done much of the hard work. The benchmark measures the model, but the score reflects the framer. This is also why benchmark watching is a trap. Shipper calls it chart psychosis, the habit of extrapolating curves into sweeping predictions while ignoring that every benchmark lives inside a chosen frame. Saturate the frame, move the frame, watch the score collapse, and restart the cycle. Benchmarks can be useful signals. The mistake is treating external benchmarks as your evaluation strategy. You need your own evals against your own work, versioned like code. Let them decay on a known schedule, because your work changes, your tools change, and your risks change. I have been calling the artifact that carries this judgment a Context Spine, an idea I first laid out in [*The Agentic SDLC*](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/). A Context Spine is a versioned markdown specification that lives directly in the root of a repository, traveling with the work through every agent run, and getting reviewed via pull requests like any other production artifact. It acts as the explicit vehicle for making smuggled intelligence reusable and legible. To see the difference, look at how the same objective changes when the frame is made explicit. A weak frame says: ```text Refactor this service to simplify the retry logic. ``` A strong frame, the kind that populates a Context Spine, says: ```markdown # Context Spine: Core Ingestion Service Retry Refactor ## Constraints & Invariants - Maintain strict idempotency guarantees across all standard consumer endpoints. - Do not increase downstream connection pressure during partial database outages. ## Acceptance Criteria - Implement exponential backoff with jitter for transient 503 errors. - Include explicit integration tests for duplicate message handling under high concurrency. ## Non-Goals - Do not modify the underlying message schema or alter the dead-letter queue routing logic. ``` The first prompt asks for cleaner code. The second protects the system. That's the difference between asking an agent to finish a task and giving it enough context to help safely change a production system. The Context Spine lets a senior engineer's framing scale to a hundred agent runs without losing the thread. It also lets you audit, evaluate, and improve the frame itself, because the frame is now a first-class development artifact instead of a Slack thread, a vague hallway conversation, or a comment buried in a pull request. Spec-driven multi-agent development is the discipline of making your framing legible enough to compound. ## Governance without ceremony There's a danger here, especially in large enterprises. Leaders will hear "treat agents like software" and respond with a 47-page governance process, three approval boards, and a SharePoint site that somehow makes everyone sad. The point is lightweight ownership, visible risk, measurable quality, and fast feedback. You get there by automating the guardrails. Instead of manual review boards, we use automated evaluation harnesses embedded directly into our CI/CD pipelines. If a team modifies an agent or updates a Context Spine, the changes run against a deterministic suite of regression tests and simulation loops. The pipeline acts as the gatekeeper, verifying that the agent operates safely within its boundaries before it ever interacts with production logic. Not every agent interaction needs a full Context Spine. Asking for a regex, a shell command, or a quick explanation doesn't require ceremony. Nobody needs an architecture review board for "what does this awk command do?" We have all suffered enough. But the moment an agent touches production logic, customer experience, security posture, data movement, regulatory exposure, or architectural direction, the frame needs to become durable and verifiable. Can we explain the frame the AI operated inside, and can the pipeline verify it automatically? If the answer is no, your AI strategy is vibes with a diff. ## What this means if you lead engineers * Retire the personal-agent fantasy. Stop promising every employee a custom AI sidekick as the centerpiece of your strategy. Encourage experimentation, but focus your energy on building durable agents that serve teams and systemic workflows. Fewer agents, better maintained, with clear organizational owners. This is the contrarian move most enterprises will get wrong, and it's the one that protects your investment. * Invest in framers, not finishers. The scarce skill is shaping the problem so the agent can finish it well. Promote, hire, and develop people who can sit at the front of the human sandwich. They're your primary leverage point. * Treat agents as platform infrastructure. Evals, simulation harnesses, prompt libraries, skill packages, and CI hooks belong in your platform operating model rather than scattered across hobbyist teams. Stand up an AI engineering capability with clear ownership, support expectations, and a structured roadmap. Apply the same discipline you use for your internal developer platform to the agents now changing your systems. * Measure systemic leverage instead of headcount. Engineers per team was the old metric. Throughput per framer is the one I want now, with quality, production stability, and rework factored in. If your reporting still rewards large headcounts over high-leverage teams shipping safely at velocity, you'll starve the operating model that actually works. * Build the Context Spine. Make your specs durable, versioned, and machine-readable, and treat the frame as a first-class development artifact. ## Coda Shipper closes with a story about a man who writes down where he put his clothes so he can find them in the morning. The next day he finds his cap, his pants, and his shoes. Then he asks: where am I myself? That is the question every leader has to keep asking as the models get better. The models will find every part of your work that has become legible enough to write down. The part of you that decides what matters today, in this codebase, for this customer, in this market, is the part the frame depends on. [The bottleneck is not the stack](https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/). It is the frame. --- ## Code Review Your Prompts - **Published:** 2026-05-17 - **Tags:** ai-strategy, ai-coding, learning, engineering-leadership, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-05-17-code-review-your-prompts/ The thread promised "a hidden Claude feature called Burnout Recovery Protocol Mode" that would reset cortisol baseline and recover six months of exhaustion in 14 days. Seven prompts, each with role definitions and methodology sections, each citing real researchers, hundreds of thousands of likes, and engineering leaders sharing it. None of it would survive a code review. We apply rigorous evaluation to architectural decisions, library choices, and security reviews. We catch memory leaks in 30 seconds and demand load tests before we trust a dependency. Then we copy-paste a "scientifically backed protocol" from a stranger on the internet and run it on our lives. Or worse, we ship that same uncritical pattern into the prompts powering our agentic SDLC pipelines. Prompts deserve the same scrutiny as code. Here is a framework for applying it. A note before diving in: this is model-agnostic. The framework works for Claude, GPT, Gemini, Llama, or any system prompt you find in a GitHub repo. The failure modes are universal because they come from how prompts are written, not which model runs them. ## The pattern Before the framework, the pattern. Viral prompts circulating on Twitter, LinkedIn, Medium, and Facebook share a remarkably consistent set of failure modes. Once you see them, you can't unsee them. Pseudoscience dressed in neuroscience vocabulary. "Dopamine baseline compression," "cortisol reset," "HPA axis dysregulation." These terms map to real concepts in their original clinical context, then get stretched into folk science. The dopamine detox concept, for instance, has been [thoroughly debunked by working neuroscientists](https://www.the-scientist.com/debunking-the-dopamine-detox-trend-72036). Dopamine is a neurotransmitter involved in motivation and prediction error, not a pleasure currency that depletes and refills. You can't "reset" it in 14 days because that framing doesn't describe how the system works. Name-dropping researchers with no real link to the science. Anna Lembke, Andrew Huberman, Matthew Walker, Stephen Porges. Real people doing real work, cited as if their endorsement is implicit. Spot-check the actual research and the gap shows up fast. Walker's *Why We Sleep* drew a [detailed critique from Alexey Guzey](https://guzey.com/books/why-we-sleep/) flagging factual errors, with Columbia statistician Andrew Gelman calling one issue a potential "smoking gun" for research misconduct. Porges's polyvagal theory was [declared "untenable" in February 2026](https://www.clinicalneuropsychiatry.org/download/why-the-polyvagal-theory-is-untenable-an-international-expert-evaluation-of-the-polyvagal-theory-and-commentary-upon-porges-s-w-2025-polyvagal-theory-current-status-clinical-applications-and/) by Paul Grossman and 38 co-signatories in *Clinical Neuropsychiatry*, arguing core premises are not defensible based on existing neurophysiological evidence. Huberman has drawn [pointed criticism from working scientists](https://slate.com/technology/2024/03/andrew-huberman-huberman-lab-health-advice-podcast-debunk.html) for cherry-picking weak studies and extrapolating animal research to human prescriptions. Citing a researcher does not transfer their rigor. It borrows their credibility. Invented timelines. "14 days to reset." "21 days to rewire." "Six weeks to mastery." These numbers feel concrete. They're almost always fabricated. The "21 days to form a habit" myth traces to a 1960 plastic surgeon's observation about amputation recovery, then got laundered through self-help books. Actual habit formation research (Lally et al., 2010) found a median of 66 days with wide variance. Burnout recovery, when severe, takes months to a year, not 14 days. Fake credentialing. "Behavioral scientist who has worked with 1,000-plus high-performers." "Sustainable performance designer who has worked with athletes, founders, and surgeons." These are roleplay instructions to a language model, and the credentials exist only in the prompt itself. Neither the author nor the model is a behavioral scientist. The credential is theater. Pop-psychology resets that sidestep the honest reality. Changing habits, behaviors, and identity patterns takes work, commitment, and time. The viral prompt economy sells the opposite, promising two weeks, one protocol, and a hidden mode unlocked. The framing is appealing because the real answer is hard, and the hard answer doesn't generate engagement. If a prompt promises a fast reset to a hard problem, it's selling you something, and the result isn't what you're buying. ## The framework Four questions. Apply them to any prompt before you run it. **1. What is the underlying claim?** Strip the role definition, the methodology bullets, and the output format. What is this prompt actually asserting will happen? Often the answer is something the prompt would never state plainly, because stated plainly it would sound absurd. "Run these seven prompts and recover six months of burnout in 14 days" is the actual claim of the viral thread. Written that way, it fails the smell test immediately. The framing exists to keep you from seeing the claim. Make yourself see it. **2. Does evidence support it?** Spot-check one citation. If the prompt invokes a researcher, does that researcher actually say what is being implied? Open a tab. Read an abstract. Search for critiques of the work, not just summaries that agree with it. This takes 90 seconds. Almost nobody does it. That's the entire business model of the viral prompt economy. **3. What is framing versus technique?** This is the most important question, and the one that generalizes furthest. Separate the costume from the substance. Role definitions ("You are an executive coach with 15 years of experience"), dramatic context ("My baseline pleasure response is compressed"), and methodology theatrics ("Front-load week one with nervous system regulation") are framing. The actual instructions to the model are the technique. The pattern shows up in engineering prompts too. Consider a coding prompt that starts with: "You are a 10x principal engineer with 20 years of experience at FAANG companies. You write production-grade, enterprise-scale code that scales to billions of users." Strip the costume. The actual instruction is: "Write good code." The credentialing gives the model nothing to act on and sells the prompt to the reader instead. Most viral prompts are 80 percent framing and 20 percent technique. The framing is what sells the prompt on social media, while the technique is what produces the output. Optimizing the framing without improving the technique is selling. **4. How would you rebuild it?** This is the real test. If you can't rewrite a prompt to be better, you don't understand why it works. If you can, you have turned a piece of content into a tool you own. Rebuilding forces you to identify which parts of the original were doing real work and which parts were performance. It's the equivalent of refactoring someone else's code. You find out fast what they understood and what they were faking. ## A worked example Here is one of the viral prompts. Names and identifying details removed. ``` You are a behavioral psychologist trained in dopamine homeostasis research and neuroscience protocols. My baseline pleasure response is compressed. Normal activities don't feel rewarding because I've over- stimulated my dopamine system. I need a strategic phased reduction, not a binary detox. 1. Ask me to list my top 7 dopamine spikes in a typical day 2. Rate each on frequency per day and dependence level 1-10 3. Design a 14-day phased reduction: - Days 1-3: Awareness only (track, do not change) - Days 4-7: Reduce frequency 50% - Days 8-14: Replace with low-dopamine alternatives 4. Build the replacement behavior library - Dopamine Spike Profile (top 7, with ratings) - Daily Reduction Calendar across 14 days - Replacement Behavior Library - Withdrawal Symptoms to Expect - Day 14 Reset Signals (how to know your baseline is recovering) ``` Apply the four questions. The claim. Stripped of framing: "Following this 14-day plan will measurably reset your dopamine system to a healthier baseline." That's a neuroscientific claim about a specific physiological change occurring in a specific timeframe. The evidence. Dopamine doesn't have a "baseline" that gets "compressed" by phone use in any clinically meaningful sense. [Medical News Today and the Cleveland Clinic](https://www.medicalnewstoday.com/articles/dopamine-detox) both note no substantial evidence supports the concept. Neuroscientists interviewed by [The Scientist](https://www.the-scientist.com/debunking-the-dopamine-detox-trend-72036) called the framing a fundamental misunderstanding of how the system works. The 14-day window is invented. "Withdrawal symptoms" for non-substance behavior is borrowed clinical vocabulary that doesn't map cleanly to checking Instagram. Framing versus technique. Strip the costume. The actual technique is: track high-stimulation habits, reduce them gradually, substitute alternatives. That's behavioral activation and habit substitution, both of which have real evidence behind them (Gollwitzer's implementation intentions, Fogg's behavior model, Lally's habit formation research). The neuroscience framing adds credibility theater and nothing else. The rebuild. ``` You are a behavior change coach drawing on evidence-based frameworks: behavioral activation, Gollwitzer's implementation intentions, and stimulus control from cognitive behavioral therapy. You do not invoke dopamine mechanisms unless citing specific peer-reviewed evidence. I want to reduce compulsive engagement with high-stimulation activities that crowd out things I value more. I'm looking for behavioral strategies with evidence behind them, not neuroscience claims. 1. Help me identify 5 to 7 compulsive habits. For each, identify: - The cue or trigger - The reward I'm actually seeking (stress relief, boredom escape, social connection) - A competing behavior that could deliver a similar reward 2. Design a plan using: - Week 1: Self-monitoring and trigger identification - Week 2: Stimulus control (environment changes) plus implementation intentions ("when X, I will Y") - Week 3: Habit substitution with the competing behaviors 3. Build in honest expectations about relapse, which is normal and not failure, plus specific recovery protocols. 4. Distinguish compulsive use from legitimate use of the same tool. Scrolling LinkedIn is different from posting on it. - Habit audit with triggers and underlying rewards - Environmental design changes for each habit - If-then implementation intentions for high-risk moments - Replacement behaviors matched to the actual reward sought - Relapse recovery plan - Weekly check-in questions - Do not invoke dopamine mechanisms without specific citations - Acknowledge uncertainty - Recommend a licensed therapist if patterns suggest clinical depression, anxiety, or addiction ``` The output difference is concrete. The original prompt produces a confident 14-day calendar with phrases like "Day 7: Your dopamine receptors are beginning to upregulate" and "Day 14: You should notice your baseline recovering." The rebuild produces a habit audit that names the actual reward each behavior delivers, environmental changes to remove cues, and a relapse plan that treats setbacks as data rather than failure. The first reads like a wellness app. The second reads like a clinician's intake notes. The rebuild is longer than the original because it does less marketing and more work. Instead of imaginary neurochemistry, it targets the actual mechanism (habit loops). It builds in honest expectations about relapse and acknowledges the limits of what an AI conversation can do. This is what a code-reviewed prompt looks like. ## From personal prompts to production systems The same uncritical patterns are migrating into engineering workflows. The bridge between a viral wellness prompt and your CI/CD pipeline is shorter than it looks. Both depend on the same skill: distinguishing what a prompt claims from what it actually instructs the model to do. Spec-driven development, agentic SDLC pipelines, multi-agent orchestration, and Claude Code configurations all depend on prompts that survive scrutiny. If the industry can't evaluate a self-help prompt critically, what happens when prompts are running production pipelines? Consider what a fake-credentialed prompt costs in production. A system prompt that opens with "You are a senior security engineer with 20 years of experience reviewing code for vulnerabilities" does nothing functional. The model isn't a senior security engineer, and it can't become one through assertion. But that prompt running in a CI pipeline creates a false confidence that security review happened, when what actually happened was pattern matching against a costume. The cost is the gap between "this code was reviewed" and "this code was reviewed by something competent to catch the vulnerability that ships to production." The viral prompt economy is training a generation of practitioners to mistake framing for technique, defer to fake credentialing, and skip evidence checks because the formatting looks rigorous. That habit doesn't stay confined to wellness content. It shows up in the prompts your engineers write, the agents your platform deploys, and the decisions those agents make on your behalf. The four-question framework is for upstream prompt design. It's the skill that makes downstream evals (golden datasets, A/B comparisons, output quality scoring) useful in the first place. Evals catch defects in prompts that already exist. The framework prevents defective prompts from being written. ## Putting the four questions to work Three practices to adopt this week. Audit one prompt you trust. Pick a prompt currently running in a workflow you own, whether it's a Claude Code configuration, a Cursor system prompt, a GitHub Copilot custom instruction, or an agent definition in a pipeline. Apply the four questions, and you'll likely find it's more framing than technique. Rewrite it. Establish a prompt review checkpoint. Prompts that ship to production should pass through the same review surface as code that ships to production. That can be a section in your existing code review template, a dedicated prompt repository with pull request review, or a checkpoint in your spec-driven workflow. Pick one and make it real. Slow down on first read. This framework adds friction, and that's the point. A 90-second citation check is the cheapest insurance available against a class of error that will otherwise scale across every prompt you write. The friction pays back the first time it catches a bad prompt before it ships. The four questions are the artifact. Print them, pin them, and put them in your team's prompt template. 1. What is the underlying claim? 2. Does evidence support it? 3. What is framing versus technique? 4. How would I rebuild it? Engineering rigor is a disposition, and it applies to your prompts the same way it applies to your code. If a prompt promises a fast reset to a hard problem, treat it the way you'd treat a pull request from someone who has never seen the codebase. Politely, carefully, and with the assumption that you're going to find something broken. You usually will. ## Further reading In an era of AI-generated content, telling fact from fiction is becoming a critical skill. The sources below are good starting points if you want to go deeper on either the evidence-based frameworks worth trusting or the patterns of misinformation worth recognizing. **On evaluating science claims** - ["Matthew Walker's Why We Sleep Is Riddled with Scientific and Factual Errors"](https://guzey.com/books/why-we-sleep/) by Alexey Guzey. A masterclass in how to fact-check a popular science book. Worth reading for the method as much as for the conclusions. - ["Scientists Like Me Knew There Was Something Amiss With Andrew Huberman's Wildly Popular Podcast"](https://slate.com/technology/2024/03/andrew-huberman-huberman-lab-health-advice-podcast-debunk.html) in Slate. A working scientist walks through specific examples of cherry-picking and overextrapolation. - ["Debunking the Dopamine Detox Trend"](https://www.the-scientist.com/debunking-the-dopamine-detox-trend-72036) in *The Scientist*. Neuroscientists explain what dopamine actually does and why the detox framing misses the point. **On evidence-based behavior change** - *Atomic Habits* by James Clear. Popular but grounded, and Clear is careful to cite his sources. Good entry point to habit research. - Peter Gollwitzer's research on implementation intentions. The "when X happens, I will do Y" framework, with decades of randomized trials behind it. - BJ Fogg's *Tiny Habits*. Behavioral design from a Stanford researcher, with a model that holds up under scrutiny. - Steven Hayes's work on Acceptance and Commitment Therapy (ACT). One of the most studied evidence-based therapeutic frameworks. - Christina Maslach's research on burnout, particularly the six-factor model (workload, control, reward, community, fairness, values). The foundation for taking burnout seriously as a workplace phenomenon, not just a personal one. **On information literacy in the AI era** - Carl Bergstrom and Jevin West's *Calling Bullshit*. A field guide to spotting bad arguments in a data-saturated world. Their [free course materials](https://www.callingbullshit.org/) are excellent. - Julia Galef's *The Scout Mindset*. On how to think about evidence without defending a position. The skill is developing the disposition to check before sharing, the patience to read past the headline, and the humility to update when the evidence doesn't match the story. --- ## Stunning UIs Aren't Just Designed. They're Enforced. - **Published:** 2026-05-14 - **Tags:** engineering-leadership, spec-driven-development, ai-strategy, agentic-sdlc, design - **URL:** https://vinny.dev/blog/2026-05-14-inkwell-design-system-enforced-ui/ Most product UIs don't fail at taste. They fail at consistency. Hand a designer the same brief on Monday and on Friday. You'll get two pages that are both fine, and that don't quite agree with each other. Buttons drift. A heading picks up a new line height. One card wears a 2px border, the next wears 1px. Each page is acceptable on its own. Together they read as two different products built by two different people. That does not mean designers are optional. It means the best design work has to survive the next page, the next component, the next developer, the next coding agent, and the next late-night change. That realization became Inkwell, a pure-CSS design system I reach for whenever I start a new project. This post is a field report on how I built it, the discipline it costs, and the decisions you can lift directly into your own work. ## Consistency is a system, not a vibe Stunning UIs aren't created by one beautiful page. They're enforced across all the pages that come after it. The work of design is not only making one screen look good. Plenty of people can do that. The harder work is making 15 pages look like the same hand drew them on the same day. There are two ways to get there. The first is talent so absolute that you redraw every decision the same way every time without thinking. That scales to one person. The second is to write the decisions down once, name them, and stop remaking them. That scales to a team, an LLM, and future you at 11 p.m. Inkwell is the second path, made concrete. At the core: four CSS files. Add one optional Tailwind v4 theme file if your project already lives there. No build step. No dependencies. The basic install is one line in your ``: ```html ``` What you get back is a tokenized color system, three type families with assigned jobs, a 1.5px hairline running through everything, and dark mode that lifts the accents instead of inverting them. The hard work isn't writing the system. The hard work is making yourself follow it. ## Name your taste before you write any components The most common failure mode in a young design system is reaching for components first. "I need a card. I need a button. I need an alert." So you write a `.card` with `border: 1px solid #ddd; border-radius: 8px;` and ship it. A sprint later, you add a `.panel` with `border: 2px solid #ccc; border-radius: 12px;` because, you know, it's a *panel*, not a card. Six components in, you have six versions of "thin rectangle with a border," and nobody can tell you which one is canonical. The fix is boring, which is usually a sign it might work. Decide the atoms before you build the molecules. Inkwell defines one border token: ```css :root { --border: 1.5px solid var(--gray-300); } ``` Every panel-shaped component points at that token. The day I decide hairlines should be 1.25px, I change one line and the whole system breathes in at once. Colors follow the same rule. Inkwell ships 12 hues mapped through about 25 semantic tokens. `--ivory` is for page background. `--paper` is for surfaces. `--slate` is for primary text. `--accent` is for the one, yes, one, saturated brand color. Components never see hex codes. They see semantic tokens. The hex values only live in `:root`. This sounds obvious until you check your own discipline. In Inkwell v1.3.1, I shipped a patch release whose entire job was sweeping six raw `rgba()` literals out of `inkwell-components.css`. Past me had typed colors inline instead of defining them as tokens. Very rude of him, frankly. Promoting one of those values to a paired light/dark token looked like this: ```css :root { --olive-strong-border: rgba(120, 140, 93, 0.45); } @media (prefers-color-scheme: dark) { :root { --olive-strong-border: rgba(156, 176, 122, 0.6); } } ``` Five of the six literals I swept were also dark-mode bugs the system had been silently carrying. The values were locked to the light-mode hue, so on a dark surface the border kept its old color while the background flipped. Tokens would have prevented every one of them. The lesson costs you exactly one refactor, and you'll probably do it on yourself before you do it on anyone else. ## Assign jobs, not preferences The thing that gives Inkwell its editorial feeling is not the colors. It's three font families doing very specific work. ```css :root { --serif: ui-serif, Georgia, "Times New Roman", Times, serif; --sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; --mono: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace; } ``` Serif handles headings, stat numbers, and italic emphasis. It carries the editorial gravitas. Mono handles eyebrows, file names, hex codes, and table headers. It signals technical metadata. Sans handles everything else. It's the default. You don't choose a font in Inkwell. You choose a *job*. A button is sans because a button is interactive, not editorial. An eyebrow tag above a section is mono because it signals metadata. A page hero is serif because it's making a statement. People resist this principle the most when I describe the system, and it pays back the most once they try it. Stop thinking, "What font feels right here?" Start thinking, "What role does this text play?" Every page in your project starts to harmonize whether you're paying attention or not. One bonus: I use platform fonts only. `ui-serif`, `system-ui`, and `ui-monospace`. No webfont download, no flash of unstyled text, and no licensing. Some readers will hate this. It's fine. The system is meant to look like a thoughtful default, not a logo. ## Pick a signature and ride it everywhere Inkwell has a signature, and it's silly: borders are 1.5px, never 1px, never 2px. A 1px border can read as wireframe. A 2px border can read as playful. A 1.5px border reads as a hairline. Once you see a page of 1.5px borders against cool-putty neutrals, you can't unsee it. It's the single most identifiable thing about the system, and it cost nothing to decide. The 1.5px is retina-first by design. On lower-density displays, browsers may snap border widths to align with device pixels, so the computed value can differ from the authored value. That is not a bug in Inkwell. It is the browser doing what browsers do: trying to keep borders crisp. If you want to verify the signature visually, do it on a 2x display. The point isn't the 1.5px specifically. The point is that every design system needs one technical choice nobody else makes, applied with embarrassing consistency. Maybe it's your radius scale. Maybe it's your shadow profile. Maybe it's the way you handle accent tints. Find your 1.5px and ride it everywhere. That's the thing people will remember. ## Define dark mode at the same time as light mode Most systems retrofit dark mode. Inkwell defines both modes for every saturated token in the same file, on the same screen. The rule: every saturated color gets a *lifted* dark counterpart. Same hue, more luminance. ```css :root { --accent: #3B4A8C; /* deep indigo on cool stone */ } @media (prefers-color-scheme: dark) { :root { --accent: #7A8AD1; /* periwinkle on near-black */ } } ``` `#3B4A8C` against a near-black background reads as a hole punched in the page, not a highlight. `#7A8AD1` restores the sense of "this thing matters" by keeping the hue but gaining luminance. Apply that rule to every colored token and dark mode stops looking like an afterthought. A token defined only in `:root` will look wrong on a dark surface. That's the trap most systems fall into. They flip the background and call dark mode done. The accent has to move with the room, or the system fails it. ## Name your anti-patterns out loud Every design system document I've read describes what the system *is*. Almost none describe what the system *isn't*. That asymmetry is where drift comes from. Inkwell's spec has a §4 titled "Anti-patterns." It reads like a list of grievances I have with my past self: - No pure white backgrounds. Use `--ivory`. White on white kills depth. - No pure black text. Use `--slate` (`#13141B`). Pure black is too cold. - No warm grays. The neutrals here are cool putty. Warm beige makes the indigo accent feel orphaned. - No multiple accent colors. One indigo, period. If you need a second hue for data visualization, reach for `--olive` or `--sky`. - No sans-serif headings. Serifs do the editorial work. Sans headings collapse the personality. - No emoji icons. Inline SVG strokes only. - No hex literals in component CSS. Always reference tokens. Always. The anti-pattern list also has to include accessibility failures. No invisible focus states. No status conveyed by color alone. No tiny tap targets because the page looks better in a screenshot. A design system that only enforces aesthetics is incomplete. The system should protect the user from my taste when my taste gets too clever. Writing these rules down makes you realize what consistency really is: the absence of specific small mistakes. The interesting design decisions aren't infinite. There are maybe a dozen places where you can take a wrong turn. Name them, and you're 80 percent of the way to a coherent system. ## Write the system for people and agents The other audience for Inkwell is not just me. It is the coding assistant I am going to hand the next screen to. That changes how the system has to be written. A vague design system tells a human designer what direction to aim. A useful design system tells an agent what not to invent. Use this token. Do not create a second accent. Use serif headings. Do not reach for emoji icons. Keep borders at 1.5px. The more explicit the system is, the less creative the agent gets in the places where creativity becomes drift. This is where design systems and AI-assisted development start to rhyme. Agents are excellent at producing plausible work. That is both the superpower and the risk. Without constraints, they will invent a good-looking local answer that quietly weakens the global system. The answer is not to make the agent less capable. The answer is to give it better rails. Inkwell's documentation has to serve two readers at once: the person making judgment calls and the agent applying the rules. The person needs the why. The agent needs the boundaries. Both need the same source of truth. That is why the anti-patterns matter. That is why semantic tokens matter. That is why "use `--accent`" is better than "make this feel branded." The first instruction can be followed. The second one invites a tiny act of unauthorized creativity. Enough of those and your product starts wearing mismatched socks. ## Be willing to refactor your own naming The first cut of Inkwell was four palette variants: clay, sage, burgundy, and indigo. All shared one base file. The accent token was named `--clay` regardless of the actual hue because *clay was first*. The indigo variant still referenced `var(--clay)` for its accent. It worked, technically. It also made obvious that `--clay` was a brand-layer name pretending to be a semantic token. The fix was to rebuild the canonical layer with `--accent` as the semantic name. I demoted the original four variants to a `variants/` folder, kept them as references, and marked them as explicitly *not* the place new work happens. The repo now contains two universes. `--accent` is for new work. `--clay` is for the legacy palette set. The README warns you, in bold, not to mix them. That kind of refactor is the most painful move to make and the most clarifying. You can't build a repeatable system by being precious about your earlier decisions. The version of you that named the token six months ago is the version you most often need to disagree with. Writing the disagreement down, where it can be pointed at, beats silent reinvention every time. ## Where this approach does not fit Inkwell is not for every project. If you're building a brand-led marketing site where the hero color *is* the brand and changes by campaign, a tokenized system biased toward editorial restraint will fight you. If you're shipping a white-label SaaS where each tenant gets a different accent and font, you need a theming layer Inkwell doesn't ship. If you treat every page as a unique composition rather than an instance of a system, the constraints will feel like a cage. The system works best for what I built it for: product UI, dashboards, technical documentation, and editorial layouts where the brand is "thoughtful default" rather than "vivid signature." Use the right tool for the job. Even the best hammer gets weird when you start aiming it at soup. ## What repeatable buys you The honest payoff is easy to undersell. Sit down in front of a blank page in an Inkwell project. The questions you have to answer are: *What is this page for? What's the hierarchy? What's the data shape?* You don't think about button colors. You don't think about border widths. You don't think about heading font choice. Those decisions are gone. Made once, named, tokenized, and they don't come back as long as the system holds. That's the payoff. A design system isn't a UI library. It's a memory aid. It's the place where you put down the decisions you don't want to keep paying for. The repeatable process isn't about being faster at making the same decisions. It's about not making them at all. The work that's left, once the system carries its weight, is the work that deserves your attention: figuring out what to put on the page, in what order, with what emphasis. *That* is the part where taste matters. Everything below that line should be on rails. If you take one thing from this, take this. Before you write your next component, write the token it points at. Then grep your existing component CSS for `#` and `rgba(`. Every literal you find outside `:root` is a future drift bug hiding in plain sight. Sweep them now. The discipline pays back faster than you expect. --- Inkwell is open source under MIT. See it in use at **[inkwell.vinny.dev](https://inkwell.vinny.dev)**. Open any page and view source: everything is in the CSS files. *Made with hairlines and serifs. The 1.5px is on purpose.* --- ## The Bottleneck Is Never the Stack - **Published:** 2026-05-13 - **Tags:** engineering-leadership, spec-driven-development, ai-strategy, platform-engineering, agentic-sdlc, future-of-work - **URL:** https://vinny.dev/blog/2026-05-13-the-bottleneck-is-never-the-stack/ A year ago I came back to blogging after a 20-year silence. The early posts were small, curious, and mostly me finding my voice again. One was a quiet admission that I had missed having a public voice. I closed it with three words: [*Welcome back, old friend.*](https://vinny.dev/blog/2025-05-17-back-to-blogging/) I had no plan. I had a backlog of thoughts. By that first weekend, I was writing about [running a 20-billion-parameter language model entirely offline on a Mac](https://vinny.dev/blog/2025-05-17-Twenty-Billion-Parameter-LLM-at-home/). By fall, I was writing about agents, platforms, specifications, leadership, and the uneasy bargain underneath all of it. Nearly 50 posts later, I have an argument, and this essay is my attempt to name it. ## The argument, in one sentence The bottleneck is never the stack. It is the clarity of intent, encoded in durable artifacts, enforced by systems rather than willpower. The leaders and builders who win this cycle are the ones who industrialize craft and bargain honestly with the humans whose careers it reshapes. I didn't invent that sentence in May 2026. I arrived at it by writing the same thing in different rooms for 12 months. "Specs beat vibes." "The code is exhaust, the spec is the product." "Discipline does not scale; automation does." "Trust compounds faster than velocity." "The bottleneck is never the stack." Those lines were all reaching for the same idea. For the rest of this essay, I want to lay it out fully, then tell you where I am still uncertain. ## Why this matters now Two things are true at the same time. AI may be the next great technology wave after the internet and mobile, but this one is arriving on a compressed timeline. At the same time, many enterprise conversations about it are theater built on inherited frames nobody stopped to question. The doomer narrative says AI is coming for your jobs. The hype narrative says AI is the productivity flywheel that will 10x your engineers. Both narratives are incomplete, and both are useful to someone's balance sheet. When I wrote [*Strip the Assumptions*](https://vinny.dev/blog/2026-03-22-strip-the-assumptions-enterprise-ai/) in March, I tried to name what was happening underneath. Generative AI reduces the marginal cost of specific cognitive outputs. That is a meaningfully different claim from the one either narrative is making. It changes what an engineering leader should be asking. Which artifacts become cheap, which become valuable, and what kind of work moves to the top of the priority list? After a year of writing, I keep arriving at the same answer. The artifact that becomes valuable is the spec. The work that moves to the top is the work of defining intent clearly, enforcing standards with automation, and bargaining honestly with the people whose careers are reshaped along the way. That is the argument. Three pillars hold it up. ## Pillar one. The spec is the product. I've written about this in pieces all year. In August, I called it [spec mode over vibe mode](https://vinny.dev/blog/2025-08-10-From-Vibe-Mode-to-Spec-Mode/). In September, I called it [coaching the LLM with software craftsmanship principles](https://vinny.dev/blog/2025-09-27-coaching-your-llm-with-software-craftmanship-principles/). In November, I called it [the journey from vibe coding to spec-driven development](https://vinny.dev/blog/2025-11-15-journey-with-trusting-genai-and-coding-workflow/). By April, I was writing about [specs, standards, and specialists](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/) as the working loop underneath everything I build. Then in May, I landed on [the formulation that captures it best](https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/): the code is exhaust, the spec is the product. For most of the last 30 years, software organizations have measured the wrong thing. Commit counts passed for velocity, coverage numbers passed for quality, and the engineers we called senior were the ones with the most code behind them. Team size was a forecast of how many lines we expected. That structure rested on a quiet assumption. Turning intent into working software was the hard part, so the typing was the bottleneck and the senior engineer was whoever typed the right things faster. That assumption is breaking. Every senior engineer I know has felt it quietly, usually around 11 p.m., the week an agent finished a job they had budgeted three hours for. With agentic coding tools, turning a clear, bounded specification into working code is becoming dramatically cheaper. What stayed hard, and what becomes more visible every day, is everything upstream: knowing what to build, what good looks like, and which edge cases will break in production. Someone still has to read the generated artifact and judge whether it meets the intent. When generated code comes back wrong, the defect usually started earlier than the code itself, in a vague spec, a verification step nobody wrote, a standard nobody enforced, or a review that skimmed. That reframe rearranges almost every engineering practice we built in the last 20 years. Spec review is becoming the new code review, and seniority now shows up in clarity of thinking rather than speed at the keyboard. The apprenticeship pipeline, the thing that produced our seniors out of our juniors, has to move from pairing on code to pairing on specs and reviews. It also changes what we should measure. Story points, pull requests, and lines of code measure activity. The numbers I want are accepted specifications, review latency, spec-to-verified-delivery time, and rework rate when reality contradicts the spec. That last one matters most. Rework is where the illusion breaks. It tells you whether the original intent was clear enough, whether the standards were strong enough, and whether the review process caught the right failures before production did. The durable artifact your organization produces, the thing that survives leadership transitions, tool migrations, and model upgrades, is the specification layer. The repository becomes a fossil record. The spec becomes the strategy. ## Pillar two. From toil to judgment. If pillar one is about what becomes valuable, pillar two is about what humans still own. AI agents are a lever against the gravity of operational drudgery. In the same way that cloud freed us from racking servers and patching disks, AI agents can free us from babysitting dashboards, chasing cost anomalies, and reading the same triage runbook for the hundredth time. That is a redistribution of human attention. When I wrote about [my FinOps agent in September](https://vinny.dev/blog/2025-09-14-From-AI-to-AI-Agents/), I framed it this way: the future of work will be defined by how effectively we use agents to reduce toil and reclaim human judgment. I haven't found a better way to say it since. The scarce skills become problem framing, system design, judgment, and taste. The scarce organizational capability becomes evaluation capacity, which is the ability to read a generated output and confidently say whether it is trustworthy. Most leadership discussions about AI argue about model capability. The bottleneck is the organization's ability to evaluate whether outputs are correct. You need fewer generators and more evaluators, close enough to the work to correct it in real time. Augmented humans catch errors as they happen, and automated errors compound. There is a humanist version of the same idea that I keep returning to. AI is reminding us what we're here for. The keyboard work was never the meaningful part of being an engineer or a leader. The judgment was, and the taste, and the willingness to engage with messy details long enough to make better decisions. The tooling is finally catching up to the part of the job that always mattered. ## Pillar three. Principles outlast personalities. The third pillar is the leadership claim, and it's the one I feel most strongly about because I have watched the alternative break good organizations. In [*Yesterday's Feature Is Today's Bug*](https://vinny.dev/blog/2026-03-15-yesterdays-feature-is-todays-bug/), I wrote that if your IT strategy cannot survive a leadership transition, it was someone's aesthetic preference rather than a strategy. A personality expressed as architecture. The revolving door of leadership is a test of good strategy. This pillar shows up in different language across the year. In [*Building Cloud From Zero*](https://vinny.dev/blog/2026-05-08-building-cloud-from-zero/), I called it the discipline of making the right thing the default before anyone builds workarounds. Platforms only work when the defaults are inherited. In [*Pipeline-First Is Not a DevOps Initiative*](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/), I called it trust-scaling, the move from individualized heroics to systemic delivery. In [*When Winning Teams Lose*](https://vinny.dev/blog/2025-11-13-f1-ferrari-leadership-lesson/), I called it accountability flowing upward, because if you publicly criticize your team while protecting yourself, you create the culture problem you're complaining about. One phrase ties the pillar together: principles, not personalities. The leaders who matter 10 years from now are the ones whose work [keeps getting better](https://vinny.dev/blog/2025-12-31-getting-better-at-getting-better-in-2026/) after they've moved on. That is the entire point. This is also where the AI story and the platform story meet. A platform is an opinionated system of defaults that helps people make better decisions without asking every person to rediscover the same lesson alone. The same is true for AI-assisted engineering. A good operating model shouldn't depend on one brilliant engineer knowing the perfect prompt, one staff engineer catching every bad diff, or one leader personally reinforcing the same principle in every meeting. That doesn't scale. Worse, it creates fragility disguised as excellence. The work has to move into artifacts, defaults, standards, and feedback loops. Human judgment goes into designing them, so the system can help more people make better decisions more often. That is how principles outlast personalities. ## The bargain underneath The fourth thread arrived later, and it's the one I am still learning how to say well. It came from watching the politics around AI harden, from executive optimism on one side to public anger on the other. Alignment that stops at the technology just means a worse outcome arrives well engineered. Builders set the language for our own technology. If the words I use in an investor meeting are the same words I use with someone whose work has just been displaced, I've earned the reaction I get. Truth and audience are two different problems, and we keep solving only the first one. *Workforce optimization* is a bloodless phrase for a human cost. *We are using AI so a smaller team can do harder work and get paid better for it* is at least a plan someone can interrogate. It makes the bargain visible. The trust deficit is on the builders. Pick the version of the bargain you can live with, then own it plainly enough that the people affected by it can argue with the real thing. I don't think technical leaders can opt out of this conversation. Talk only about productivity and we miss the human consequences; talk only about fear and we miss the chance to build better systems. The work is to hold both truths without hiding behind either one. That is uncomfortable. Good. ## Where I am less sure I have shipped this synthesis with three confident pillars and one developing one. Here is where I am still working things out. I am most confident in the spec pillar. I have written it five different ways with five different examples, and every example has held up. I am moderately confident in the toil-to-judgment pillar. It is well-developed, but it sometimes blurs into the spec pillar. They may be two faces of the same belief. The clarity question is whether evaluation capacity is a separate scarce resource from specification clarity, or whether they are the same skill at different elevations. I am increasingly confident in the leadership pillar, but I am still working on the cleanest language. "Build for after you are gone" gets at the humility of it. "Principles outlast personalities" gets at the system design. "Design for succession" gets at the operating model. I suspect the real idea needs all three. I am least certain about the builder's bargain, not because I doubt its importance, but because I am still learning how to reach beyond the audience that already agrees with me. The people building AI understand the promise. The people being asked to absorb the consequences often hear something else. The work there is not done. That uncertainty matters. It keeps the argument honest. ## What I want this to do I wrote this because the people who read me at vinny.dev deserve more than a chronological list of posts. They deserve the argument underneath them. The people I lead deserve the same thing. When technology moves this quickly, silence becomes its own kind of message. After 30 years in this craft, the advantage I would bet on is clearer intent, stronger systems, better judgment, and more honest conversations about the work we are changing. The bottleneck, after all, is never the stack. If you think I have one of these wrong, write to me at vin@vinny.dev. Good points of view get sharper when they meet other points of view. --- --- ## The Spec Is the Product - **Published:** 2026-05-12 - **Tags:** spec-driven-development, platform-engineering, engineering-leadership, aws, context-spine, ai-strategy - **URL:** https://vinny.dev/blog/2026-05-12-the-spec-is-the-product/ *Code used to be the durable asset. In an agentic SDLC, that changes. Code becomes the regeneratable output of a system that runs on something more important: a clear, versioned, reviewable specification. That shift changes what engineering organizations invest in, how they govern delivery, who they hire, and what they ship.* ```bash $ vinny spec --diff v2.1 v2.2 + accept partial cancellations + enforce 90-day audit retention - legacy reconciliation path ✓ regenerate · 6 services · 3 languages // the durable artifact is upstream ``` Read your team's last sprint backlog. Now read your team's last sprint of merged code. One of those is becoming the more durable asset of your engineering organization, and it may not be the one you think. For 30 years I have written code, reviewed code, refactored code, audited code, and built organizations around the assumption that code was the thing. The repo was the inventory, the diff was the proof of work, and the pull request was the unit of accomplishment. We measured velocity in commits, quality in coverage, and seniority in lines shipped. We sized teams by how much code we expected them to produce. That whole structure rested on a quiet assumption: turning intent into working software was the hard part. That assumption is starting to break. When a competent agent can take a clear, well-scoped specification and produce working, tested, conformant code in minutes, the scarce resource moves upstream. The expensive thing is knowing exactly what to build, why, for whom, under what constraints, and how to verify it. The expensive thing is the specification. So here is the reframe I've been working through, and the one I think every engineering leader needs to sit with: the code is exhaust. The spec is the product. ## What "exhaust" means and does not mean Exhaust isn't worthless. A jet engine produces exhaust, and that exhaust is visible evidence that the engine works. It's the byproduct of useful work, and without it you have no flight. But you don't store or version exhaust, and you don't pay people for how much of it they produced this quarter. You measure the engine. Code in an agentic SDLC is exhaust in that sense. It is the visible, valuable, working output of a system that turned intent into running behavior. It still has to be correct, pass tests, meet performance budgets, and clear security review. None of that goes away. But code is becoming less durable than the artifact that produced it. In the right workflow, code can be regenerated from a better spec, produced in a different language, refactored against a new framework, or reshaped around a stronger platform standard. That makes code downstream rather than disposable. I have done this. So have a lot of you. The first time you regenerate working, production-quality code from a tight spec and realize the underlying language was almost incidental, something inverts in your head. The repo stops feeling like inventory and starts feeling like a fossil record. ## What the spec is When I say "spec," I don't mean a Word document that lives in SharePoint and goes stale by sprint two. We've all seen that movie. It has too many sequels. I mean a structured, versioned, machine-readable artifact that captures: - The intended behavior, in terms specific enough to test - The constraints, including performance, security, compliance, accessibility, data residency, and cost - The interfaces and contracts - The decisions and the reasons behind them - The known risks and open questions - The verification criteria and acceptance signals This artifact lives next to the code. It is reviewed before any code is generated. It is the input to every agent in the pipeline, from the one that writes the implementation, to the one that writes the tests, to the one that updates the runbook. It's what gets diffed across versions, and what the security reviewer and the auditor read. It's also what the next engineer reads when they need to evolve the feature next year. A payment cancellation feature, for example, starts life as "allow the user to cancel." A real spec needs to say whether partial cancellations are allowed, what happens after settlement, what audit events are retained, what downstream systems receive the reversal, what appears in the UI, what customer communications are triggered, and how support teams can explain the outcome. Once those decisions are explicit, generating the code is still real work, but it's no longer the most ambiguous work. The ambiguity moved upstream. I've been calling this artifact the Context Spine. The name matters less than the function. The Context Spine is the artifact that keeps intent from evaporating as work moves from product discussion to agent planning, code generation, testing, documentation, operations, and audit. Without it, every downstream step has to infer what the last step meant. That's where agentic workflows become expensive, inconsistent, and occasionally very confident about the wrong thing. A Context Spine makes the pipeline a system instead of a collection of clever prompts. ## The implications are not subtle Once you accept that the spec is becoming the product, several things follow. Most of them are leadership problems, not tooling problems. Your investment shifts. You invest in the quality of the spec, the discipline around its review, the standards it enforces, and the format it uses. You invest less energy celebrating the boilerplate of the code itself, because more of that boilerplate is regeneratable. You stop celebrating "we wrote 40,000 lines this quarter" and start asking, "Are our specs sharper this quarter than last?" Your governance shifts. Compliance, audit, and risk review move upstream. You stop auditing only what shipped and start auditing the spec that produced it. A finding against a spec is fixable earlier, more consistently, and with a cleaner trail of intent. A finding against code often turns into the slow, manual archaeology we all know too well. Your talent equation shifts. The engineers who thrive in this environment are the clearest thinkers. They can hold a problem in their head long enough to specify it precisely, anticipate edge cases, and articulate acceptance criteria. That's a senior engineering skill, and it always was. AI just made it more visible. Engineers who only know how to translate requirements into code are going to feel the pressure first. The bottleneck is moving from implementation speed to clarity of intent. This is also why the apprenticeship problem is real and underdiscussed. If junior engineers never learn to write a sharp spec, they'll never become the senior engineers we need. The old path ran through writing a lot of code badly, then less code well. The new path may run through writing a lot of imperfect specs, getting them reviewed carefully, and learning how to make them precise, testable, and useful. That review culture has to exist, and most organizations don't have it yet. Your org design shifts. Spec ownership becomes a real question. Is it the product manager, the architect, the engineer, or the platform team? The answer won't be one role in most mature organizations. Product leaders will own customer and business intent. Engineers and architects will own technical feasibility, constraints, and verification. Platform teams will own reusable standards and paved paths. Security, risk, and compliance partners will help define the controls that need to exist before the system generates anything meaningful. The important shift is that the spec becomes a first-class artifact with explicit owners. It can't remain a meeting note everyone hopes the team remembers. Hope is not a great persistence layer. Your vendor strategy shifts. When code is regeneratable, your lock-in story changes. The argument for choosing GitLab, AWS, Azure, or any other foundational vendor becomes less about "we wrote a million lines against your APIs" and more about "our specs assume your primitives, our pipelines route through your platform, and our standards are encoded in your tooling." That's a different kind of stickiness. It's also a different kind of negotiation. ## What humans still own The spec becoming the product raises the bar for what engineering judgment means. Humans still own the intent, the trade-offs, the risk decisions, the constraints, and the final accountability. Agents can generate options, produce code, write tests, and compare output to the spec. They cannot decide what trade-off the business should make when correctness, cost, speed, regulatory expectations, and customer experience collide. That's where senior engineers, architects, product leaders, security partners, and platform teams still matter. Maybe more than before. "Can the agent build this?" is the easy question. The best engineers in an agentic SDLC spend their time on the ones that take judgment: - Is this the right problem to solve? - What edge cases are we avoiding because they're uncomfortable? - What constraints are assumed but not written down? - How will we know the generated work is correct? That's not less engineering. That's engineering with the typing separated from the thinking. The typing was never the hard part for very long. ## The objection I hear most "But the code still has to be right." Yes. The code has to be right. It has to compile, perform, secure, and behave, and none of that is in question. The point is that code correctness increasingly becomes a property of the spec plus the verification harness. It depends less on the keystroke quality of the engineer who typed it. I've watched that distinction get blurred in a lot of executive conversations, so let me sharpen it. If your team's generated code is wrong, the problem may be in the spec, the verification, the standards, or the review, not in the code. Fixing the code in place may solve the immediate defect, but it's often the least durable response. Fixing the upstream artifact and regenerating is faster, cleaner, and more consistent across every other piece of work derived from the same source. This is the inversion many leadership teams haven't internalized. They still debug the code that broke and leave the spec that produced it untouched. ## Where I would start If you lead an engineering organization and you take this seriously, start with three things. First, decide what your spec artifact looks like. Pick a format, version it, and put it under source control next to the code it informs or generates. Markdown with structured frontmatter, a YAML schema, a domain-specific format, the choice matters less than the commitment. Standardize early, and resist the temptation to let every team invent its own. Second, build a review culture around the spec. Spec review is becoming the new code review. It's where seniority shows up, where standards get enforced, and where the most expensive defects get caught. If your senior engineers aren't spending material time in spec review, they may be spending too much time downstream. Third, change what you measure. Stop treating commits and pull requests as the primary unit of work. Start looking at accepted specifications, review latency, and the time between spec approval and verified delivery. The metrics move upstream because the work did. The spec is the product and the code is exhaust. Your organization will ship better work when you finally invest in the artifact that has always mattered most. A better stack won't do it for you. I would love to be wrong about this, so tell me where the argument breaks. --- ## AI Populism is a Builder's Problem - **Published:** 2026-05-10 - **Tags:** platform-engineering, engineering-leadership, learning, future-of-work, genai - **URL:** https://vinny.dev/blog/2026-05-10-ai-populism-builders-problem/ Sam Altman's home took a Molotov cocktail on a Friday and gunfire on a Sunday. An Indiana councilman who approved a data center project found 13 bullets and a "NO DATA CENTERS" note at his door. Jasmine Sun calls these warning shots in [her sharp piece on AI populism](https://jasmi.news/p/warning-shots), and I think she is right. I read her article wearing two hats. As an engineering leader who has spent the last few months writing about [agentic SDLC](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/), the [Context Spine](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/), and the [Dark Factory](https://vinny.dev/blog/2026-04-05-dark-factory-model-for-ai-software-development/), the piece sat with me. Her central claim is that AI populism treats AI not as a normal technology, but as an elite political project to resist. The actual utility of the tool is beside the point. What matters is the societal change it represents. Inside our industry, we tell each other a tidy story. AI amplifies builders. It raises the floor. It compresses the boring parts of the job and frees humans for higher-leverage work. After 30 years of writing software, I believe that story. I also see how thin it sounds outside the bubble. That gap is the real problem, and it is ours to close. ## The narrative failure is not a PR issue Sun makes a sharp observation. Years of executive messaging about human obsolescence and rogue AI risk landed badly with the public. Most people do not parse the difference between OpenAI and Anthropic. They hear "Big Tech" and they reach for whatever leverage they can find. The AI safety community fixated on existential risk and waved off short-term harms like jobs and mental health. Sun calls this a sociopolitical alignment failure. That phrase deserves to stick. Technical alignment without sociopolitical alignment is not safety. It is just better engineering for a worse outcome. ## The Dark Factory and the villain's edit When I wrote about the Dark Factory and autonomous software pipelines, I was describing a real direction of travel. I still believe the architecture is right. Pipelines, specs, and standardization keep winning, and the bottleneck is never the stack. But read the phrase "Dark Factory" through a populist lens. It evokes a windowless plant with no humans inside. If I describe my engineering vision to investors in the same words I would use with a laid-off illustrator, I sound like the villain in a movie. Honesty is not the same as audience awareness. Builders need to start picking better ways to say true things. > **Related**: [The Dark Factory Model for AI-Driven Software Development](https://vinny.dev/blog/2026-04-05-dark-factory-model-for-ai-software-development/). The original argument for what the architecture is, and why experience is the raw material that makes it run. ## What engineering leaders can do This is where it gets practical. I'm running cloud, platform, and DevOps for hundreds of engineers at a 169-year-old company. Here is where leaders like me have real leverage: Be honest with your own team. Not the corporate version. The real version. Where is AI raising their leverage? Where is it shrinking headcount needs? Vague reassurance is not safety. Specificity is safety. Invest in people's leverage, not just shipping velocity. [Agentic SDLC](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) and the [Context Spine](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/) only pay off if the humans running them get more capable and more secure. If the gains all flow to the income statement and none to the people, you are building the populist movement Sun describes. Talk like a human. "Workforce optimization" is a cancer phrase. "We are using AI so a smaller team can do harder work and get paid better for it" is a real plan. Pick the version you can live with. > **Related**: [Pipeline-First Is Not a DevOps Initiative. It's a Culture Shift.](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/) The part the slide decks leave out is what determines whether your investment in your people pays off. ## The CEO of your own career The other half of the optimism lives outside the org chart. If you work in tech right now, you are the CEO of your own career. I don't say that to mean you are on your own. I say it to remind you that you have more agency today than at any point in the last three decades. No one is a passenger in this cycle unless they choose to be. That isn't a threat; it's an invitation. The same tools causing the noise are the most powerful learning accelerators we have ever seen. I use [Claude Code](https://vinny.dev/blog/2026-04-25-claude-code-build-system/) every day across JavaScript, Java, and Python. [PourCraft](https://vinny.dev/blog/2026-03-01-vibe-coding-with-coffee/), the coffee calculator I shipped to the App Store, went from idea to submission in an afternoon because I leaned into that agency. Bias for action is the most underrated career skill of the next decade. The engineers who thrive treat every new tool as something to wrestle with. They build small things and force themselves back into a "beginner's mind." [They write down what they learn so the next session is faster](https://vinny.dev/blog/2026-03-28-coding-standards-skill/). Whatever made you valuable five years ago is not what makes you valuable today. ## The bargain we owe Sun ends her piece by arguing that the only peaceful resolution is a grand bargain. A plan that addresses public fears and redistributes the gains. I know what the builder's version of that bargain looks like at the team level. It looks like clear talk, fair pay, real training, and servant leaders who treat AI as a tool to make their people more valuable, not as a tool to make them optional. The bottleneck is never the stack. It is also not AI. The bottleneck is whether the people building this stuff earn enough trust to keep building it. That is on us. --- ### Related reading on this blog - [The Agentic SDLC: Uniting the AI Tool Sprawl](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) - [Spec, Standards, Specialists: How I Actually Build with AI](https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/) - [The Dark Factory Model for AI-Driven Software Development](https://vinny.dev/blog/2026-04-05-dark-factory-model-for-ai-software-development/) - [Claude Code Is a Build System, Not a Chatbot](https://vinny.dev/blog/2026-04-25-claude-code-build-system/) - [Pipeline-First Is Not a DevOps Initiative. It's a Culture Shift.](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/) - [From Copy-Paste to Skill: What Thousands of AI Coding Sessions Taught Me About Guardrails](https://vinny.dev/blog/2026-03-28-coding-standards-skill/) - [Vibe Coding With Coffee: Shipping PourCraft to the App Store in an Afternoon](https://vinny.dev/blog/2026-03-01-vibe-coding-with-coffee/) --- ## Building Cloud From Zero: Five Decisions That Compounded and Three I’d Redo - **Published:** 2026-05-08 - **Tags:** cloud, platform-engineering, engineering-leadership, aws, finops - **URL:** https://vinny.dev/blog/2026-05-08-building-cloud-from-zero/ A few times a month, my phone lights up with the same kind of message. A friend, a former colleague, or a peer from another company is somewhere in the middle of a cloud journey and wants to compare notes. They want to know what worked. They want to know what did not. Mostly, they want to know what they should be worried about before it becomes expensive. Sometimes they are six months in and looking for validation. Sometimes they are three years in and looking for a sanity check. Sometimes they are 10 years in and quietly wondering whether the whole thing needs to be rebuilt. I love these conversations because I learn something every time. The shape of the journey is similar across firms, but the details are always different. The details are where the interesting failure modes live. I also love them for a more selfish reason. Every conversation forces me to explain why we made the choices we made, and that explanation is its own form of pressure testing. Some decisions look sharper after I say them out loud. Others reveal a wobble I had not noticed, a piece of reasoning that no longer holds, or a trade-off I have been quietly paying for and stopped seeing. The longer I do this, the more convinced I am that the small decisions in year one decide whether you have a platform or a pile in year five. I have been in the cloud business since the days when EC2 was a curiosity and "the cloud" was a phrase you had to define for half the room. Two firms, 15 years, both in financial services. Both started before "cloud strategy" was a slide in everyone's deck. Financial services adds a useful constraint: security, auditability, resiliency, and cost discipline do not get to wait for a later maturity phase. They have to be part of the foundation. The first build taught me what works. The second build taught me what compounds. Most of what made these organizations successful, and most of what eventually made them painful, traces back to maybe eight choices made in the first 18 months. Five of those choices I would make again tomorrow. Three I would do very differently. What follows is an honest accounting, written the way I would explain it to another technology leader over coffee. No victory lap, no Gartner quadrant, and no slide that says "transformation." ## The five decisions that compounded ### 1. Centralized landing zones, before the first workload The seductive thing about cloud in the early years was that any team with a corporate credit card could spin up infrastructure. We refused to let that be the on-ramp. Both times, we built a centralized landing zone first. Shared services, identity, networking, logging, tagging, guardrails, and the rest of the foundation were in place before the first business workload landed. The pain was real. Application teams complained about waiting. Leadership wondered out loud whether we were building a bottleneck. I had more than one meeting where I had to defend the timeline against a team that just wanted an account, a VPC, and the freedom to figure out the rest. Five years later, the value of that decision was obvious. Every workload inherited identity, observability, network controls, and tagging by default. When auditors asked for a list of every workload in a given organizational unit and what it was costing us, we had the answer in minutes. The organizations that skipped this step are still building inventory tools and still finding shadow accounts. The deeper lesson is that platforms only work when defaults are inherited, not chosen. If a team has to opt into security, observability, or cost controls, most teams will not. The ones that do will implement them slightly differently from each other. Centralized landing zones make the right thing the normal thing. That sounds less dramatic than "cloud transformation," but it is also much harder to ruin in production. ### 2. Terraform over CloudFormation Both tools worked. CloudFormation was the native AWS answer and had tighter service integration on day one. We chose Terraform anyway, twice, for two reasons that mattered more than either tool's feature list. The first was the provider ecosystem. The same workflow that managed our AWS accounts also managed our DNS, identity provider, secrets backend, observability platform, and source control. Engineers learned one mental model and applied it across the entire toolchain. CloudFormation could only ever talk to AWS, and a real platform talks to a lot more than AWS. The second reason was cognitive portability. Engineers who learned Terraform on our team could take that skill anywhere. Engineers joining us from another firm were productive in a week. Tool choices that double as recruiting and retention strategies are underrated, and the cost of a tool nobody else uses shows up on every offer letter and every onboarding plan. That does not mean Terraform is the right answer forever, or that CDK and native provisioning tools have not improved. It means the best tool was the one that gave us the broadest platform model, the strongest talent market, and the least context-switching across the systems we had to manage. I will note for the record that this decision aged well through the OpenTofu fork and the licensing turbulence. The skill investment held its value, which is the only test of a tool choice that ultimately matters. I also wonder how generative AI will impact this specific decision for folks making it today. When code generation can produce CDK, Terraform, Pulumi, or Bicep with equal fluency, the cost of choosing the "wrong" IaC tool drops. The cost of fragmenting your team across three of them does not. ### 3. Infrastructure and policy as code, treated as a product Most organizations say "infrastructure as code" and mean "we have a repository with some Terraform in it." We treated the platform itself as a product. It had engineers, a roadmap, SLOs, a backlog, and real customers in the application teams. Policy as code came in early as well, through service control policies, OPA, and the equivalent guardrails for every system that could be guarded. The reason this compounds is subtle. If your platform team operates with lower engineering standards than the teams you serve, your platform becomes both the bottleneck and the blame magnet. Application teams will route around you, build their own glue, and quietly create a shadow platform inside your platform. I have watched this happen. It is corrosive in a way that is hard to undo. Treating the platform as a product means writing tests for your modules, running CI on your guardrails, versioning your golden paths, and shipping changes through the same pipeline you ask everyone else to use. It also means having a product manager who talks to internal customers, understands demand, and shapes a roadmap around what teams need rather than what the platform team finds interesting. The leadership discipline here matters as much as the engineering discipline. A platform team has to be humble enough to listen, confident enough to set standards, and disciplined enough not to confuse "customer obsession" with "say yes to everything." ### 4. T-shaped engineers, not specialists In the 2014 to 2018 window, cloud organizations loved specialists. The AWS networking person. The IAM expert. The Kubernetes specialist. We hired the opposite both times. We looked for generalists with one or two areas of depth and a willingness to learn the next thing. The result was an organization that absorbed new services, new clouds, and new tools without restructuring. When containers became real, we did not need to hire a containers team. When serverless mattered, we did not need a serverless practice. When the AI infrastructure conversation arrived, the same engineers who built the landing zone could reason about GPU capacity, model serving, and inference cost. Deep specialists are necessary. Hire them when the depth is genuinely irreducible. The failure mode is when the operating model depends on them, complexity hardens around them, and the organization starts protecting the dependency instead of reducing it. T-shaped engineers create a different culture: a team where knowledge spreads, problems get owned by whoever is closest, and the next pivot does not require a reorg. This is also where the dark factory idea starts to take shape. You cannot run a lights-out platform with a team built around heroes and gatekeepers. You need engineers who codify what they know and trust the system to run it. ### 5. The right level of abstraction This is the most subtle of the five, and it is the one I think about most often. Too thin an abstraction and your platform is just raw AWS with extra steps and a logo. Too thick and you have built a homegrown PaaS that nobody can debug, no vendor will support, and the next platform leader will spend three years untangling. The answer we converged on, both times, was golden paths. Opinionated, well-paved routes for the 80% of workloads that look the same as every other workload, with explicit escape hatches for the 20% that genuinely need to do something different. A team building a standard web service should never need to think about the underlying primitives. A team building a low-latency trading bridge or a real-time risk engine should be able to reach past the abstraction without filing a ticket and waiting two quarters. The leadership mistake is believing that giving every team a choice is the same thing as helping them. Sometimes the more helpful move is to remove low-value decisions so teams can spend their energy on the business problem. The failure mode to avoid is the gilded cage: a platform so opinionated it can only build one shape of application, then dies the moment the business asks for a second shape. Greenfield gives you the rare opportunity to design the abstraction layer with both the common case and the escape hatch in mind from day one. Brownfield platforms almost always pick one and bolt on the other later, and the bolt-on never quite fits. ## The three I would redo If the five above are the decisions I would make again, these next three are the ones I think about late at night. Not every night, to be clear. I do sleep. Occasionally. ### 1. I would kill the multi-cloud aspiration faster For a few years at both firms, "multi-cloud" lived on the strategy slide. It sounded responsible. It sounded like a hedge against vendor lock-in. It sounded like the kind of thing a serious enterprise should be planning for. The honest truth is that most companies do not need multi-cloud. They need a real disaster recovery story, genuine regional resilience, a defensible vendor exit plan, and clean abstractions over the handful of services that genuinely matter. None of those require running production on two clouds. Multi-cloud done seriously is a tax on your engineers, tooling, contracts, security model, and finance team. Multi-cloud done as a hedge is a fantasy that costs you depth in the cloud you use while delivering none of the resilience you imagined you were buying. There are companies that genuinely need multi-cloud. Sovereignty requirements, regulatory geography, and real customer demand for a specific provider can all be valid reasons. If you are one of those companies, you already know it. Everyone else is paying a complexity tax for a problem they do not have. I would have removed that line from the strategy slide much earlier. ### 2. I would put FinOps in the foundation, not the renovation At both firms, we treated cost optimization as a phase. Build the platform. Get workloads on. Then do a FinOps push. It worked, in the sense that we eventually saved a great deal of money. The most recent push at my current firm reached a 46% effective optimization rate across our cloud estate, which I am proud of. But every dollar you save through retroactive FinOps is a dollar you spent badly first. The engineering hours you put into cleanup are hours you cannot put into the next thing. If I started over tomorrow, FinOps would live in the landing zone. Tagging would be enforced at account creation, not retrofitted across years of workloads. Showback dashboards would be live before the first invoice. Reserved capacity, savings plans, and commitment strategy would be early architecture decisions, not later cleanup projects. Cost anomaly detection would be wired into the same alerting backbone as security and reliability, because cost is a reliability concern. If a workload can accidentally burn through budget in a weekend, that is not just a finance problem. That is an engineering problem wearing a finance costume. The cultural piece matters as much as the tooling. If teams see their cost from day one, they design for cost. If they see it three years later, they argue about it. ### 3. I would standardize harder, sooner This is the regret that hurts the most. We let teams pick. CI tools. Secret managers. Observability stacks. Deployment patterns. Base images. Each individual choice felt small at the time and was defensible in isolation. Each team had a reasonable story for why its pick was the right one for its context. We told ourselves variability was a feature, that meeting teams where they were would build trust, and that we could rationalize later. Five years on, those small choices became a tax we paid every time we wanted to upgrade something, roll out a new control, or move a workload between teams. Standardization feels heavy-handed in year one and saves you in year five. Variability is a debt that compounds faster than you think, and unlike financial debt, you cannot refinance it. You can only pay it down, slowly, while the interest keeps accruing. If I were starting over, the platform would offer fewer choices and better defaults. Teams would still have escape hatches for genuine edge cases, but the default toolkit would be smaller, sharper, and non-negotiable. The teams that pushed back hardest on standardization in year one would, I am certain, thank me in year five. They might not say it out loud, but I would know. Platform people are allowed a small amount of delusion. As a treat. ## If I started tomorrow If I had to compress the entire essay into a starting checklist, here is what I would protect: 1. Build the landing zone before the first workload. 2. Pick one infrastructure-as-code path and make it the paved road. 3. Put FinOps, tagging, showback, and anomaly detection into the foundation. 4. Define the golden paths before teams invent their own. 5. Treat the pipeline as the product, not the plumbing. That does not mean every edge case disappears. It means exceptions become explicit. The platform can support different shapes of work without letting every team quietly become its own platform team. I would also make one leadership choice early: decide which decisions the platform owns and which decisions product teams own. Ambiguity here is expensive. If the platform owns too little, every team builds its own version of the same thing. If the platform owns too much, the platform becomes a ticket queue with a mission statement. The goal is not control for its own sake. The goal is to remove low-value variability so teams can move faster, safer, and with less cognitive load. ## What greenfield gets right that brownfield never can This is where the cloud conversation becomes less about infrastructure and more about the delivery system itself. In advanced manufacturing, the aspiration is a dark factory: a production line that runs lights-out, with no humans on the floor, because every step has been encoded into the machinery. Software has the same opportunity, and the cloud era is what makes it possible. The path from a developer's commit to production should run without human intervention, because every guardrail that matters lives in the pipeline rather than in someone's head. Security, compliance, cost, reliability, and quality should not depend on a heroic person remembering the checklist. The checklist should be encoded into the system. Pipeline-first delivery is the practical expression of that idea. It says the delivery path is the product. The application is the payload. Most engineering organizations have this backward. They invest in the application and treat the pipeline as plumbing. The result is a beautifully crafted application moving through a pipeline that requires three approvals, two manual steps, and a meeting to release on a Friday. No one should need a meeting to release on a Friday. Ideally, no one should release on a Friday, but that is a separate blog post and possibly a support group. The reason brownfield organizations struggle to get there is not technical. It is human. Every existing exception is a person. Every team that does something differently has a reason that made sense at the time. Every legacy workaround was once a fix for a real problem. You cannot encode what you cannot standardize, and you cannot standardize what people have already built workarounds for. Brownfield platforms spend most of their energy retrofitting around habits that calcified before the platform existed. Greenfield gets the rare gift of writing the rules before anyone has a workaround. The pipeline exists before the workloads. The guardrails exist before the violations. The standards exist before the variability. Production-grade habits become normal because they are the only habits anyone has. That is the real greenfield advantage. It is not the newer technology, the absence of legacy databases, or the chance to skip a generation of tooling. Those things matter, but they age out. The advantage that compounds, the one I would protect above all others if I were starting again tomorrow, is the absence of bad habits. The chance to make the right thing the easy thing, the easy thing the default, and the default the only thing. If you are about to start a greenfield cloud build, that is the gift you have been handed. Do not give it back by year three. --- ## AI Did Not Configure My Network. It Helped Me Understand It. - **Published:** 2026-05-06 - **Tags:** ai-strategy, claude-code, side-projects, context-spine, engineering-leadership - **URL:** https://vinny.dev/blog/2026-05-06-ai_did_not_configure_my_network/ One Saturday morning, I caught myself staring at my UniFi dashboard. My home network was running, but not running well. I had been telling my team for months that AI tools amplify builders. The bottleneck is never the stack itself, but the thinking, the context, and the willingness to engage with the messy details long enough to make better decisions. So I decided to put my own thesis to the test. I opened Claude Code for my house instead of a coding project. I was comfortable doing that because Claude Code ran locally, reasoning over files I controlled and helping me think through the system. Nothing touched my firewall, routing rules, VLANs, or access points unless I typed the change into UniFi myself, and that boundary mattered. The point is simple: AI did not configure my network. It helped me understand it. ## The setup I had I run a Ubiquiti Dream Machine SE as the brain of my home network. It's the router, firewall, WiFi controller, and Protect NVR all in one. Three U6 Mesh access points cover the house, and two ISPs land on the box: Spectrum cable as the workhorse and Verizon 5G Home as the helper. The setup included four VLANs, two SSIDs, a handful of routing rules, and a growing collection of devices. On paper, that's a respectable homelab. In practice, I had built it the way many engineers build personal infrastructure: I stood it up, made it work, and moved on. ![Simplified home network topology showing dual WAN, UniFi Dream Machine SE, VLANs, SSIDs, and access points.](/images/blog/2026/05/unifi-network-topology.png) Load balancing ran with default weights and untuned health checks. VLANs existed, but the firewall rules between them were not enforcing the trust boundaries I thought they were. My IoT devices and my work laptop shared paths in ways I hadn't really thought through. My Zscaler VPN occasionally fell off a cliff, and I kept blaming Verizon without proving it. Worst of all, I couldn't have explained to anyone, including myself, why every part of it was configured the way it was. ## The honest moment I am a VP of Engineering. I lead a large engineering organization, and I spend a lot of time talking about architecture, platforms, guardrails, documentation, and operational discipline. I also still ship code, tinker with systems, and occasionally break things in my own house. Then I explain to my family why the internet is having a character-building moment. That's what made the moment uncomfortable in the right way. I had a network setup that worked well enough most days, but I couldn't fully defend the design. That gap between what I knew was possible and what I had actually built felt familiar. I see versions of it at work all the time when teams have strong tools and decent architecture, but no clear throughline connecting the decisions. The fix is rarely a new tool, and more often it's slowing down long enough to ask better questions. So I asked Claude Code to help me ask better questions. ## Claude Code outside the code editor Most people use Claude Code for what it says on the tin: generating code, refactoring a module, running a build, or fixing a failing test. That is the obvious surface area, and it's genuinely useful. Claude Code is also a tool for structured reasoning over text, files, commands, and context. That distinction matters because networking gear produces text. Configurations, logs, vendor documentation, and RFCs are all text, so if the problem can be expressed clearly, the tool can help reason about it. I exported the relevant pieces of my UniFi configuration into a markdown file: gateway settings, access points, VLANs, SSIDs, DHCP scopes, firewall rules, routing rules, QoS rules, security posture, and known issues. I wrote it the way I would write a runbook for a new engineer joining my team. Instead of a raw configuration dump, it was a narrative that tried to explain intent, trade-offs, and the places where I knew the system had drifted. Then I handed Claude Code that file and asked it to be skeptical. ## The conversation that mattered The first round was diagnostic. I asked Claude Code to read the setup and tell me what looked wrong, what looked inconsistent, and what looked like it had been built by someone who got distracted halfway through. The answers were uncomfortable in the best possible way because they exposed the gap between the network I thought I had and the network I had actually configured. ### My IDS/IPS scope did not match my mental model I had IDS/IPS turned up aggressively, with the full signature set, notify-and-block mode, and maximum sensitivity. The problem was that the control was narrower than my mental model of it. I had scoped inspection too tightly around the Default VLAN, which was mostly management gear. Trusted, IoT, and Guest traffic weren't getting the level of inspection I assumed they were. I had built a strong checkpoint on a road very few people used. That is exactly the kind of issue AI is useful for surfacing, because it can hold the intended model and the actual configuration side by side and ask whether they really match. ### My load balancing was naive I had a 50/50 split between Spectrum and Verizon, with both WANs relying on similar health-check targets. That looked balanced, but it wasn't thoughtful. Spectrum is my reliable workhorse. Verizon 5G Home is useful as a second pipe, but it's not the connection I want carrying half my household by default. It also didn't help that both WANs could mark themselves unhealthy at the same time if the shared health-check path had a hiccup. Claude Code helped me reason through a better model. We diversified the SLA targets, tuned the health checks, and shifted the weight to match reality. Spectrum carries most of the load, while Verizon helps when it should. The configuration now reflects the actual operating model instead of pretending both links are equivalent. ### My Zscaler problem had a real cause I had been blaming Verizon for my work VPN problems in the vague way we blame things we haven't fully diagnosed. The better explanation was more specific: Zscaler didn't love asymmetric paths, CGNAT, and multi-path flow splitting over a 5G link. When traffic moved unpredictably between WANs, the VPN experience got ugly. The fix was precise. I created a policy-based route that pinned my work MacBook to Spectrum by MAC address, regardless of the load balancer's mood. I tested the VPN throughput before and after, and the cliff vanished. One change produced one verifiable result, which reminded me that I had been living with a problem I could have solved earlier if I'd stopped to define it clearly. ### Netflix was making the same complaint Streaming had its own version of the problem. Netflix would re-authenticate or drop quality when a flow landed on Verizon, which made more sense once I thought about how streaming providers use public egress IPs, CDN behavior, and session consistency. The fix was another policy-based route, this time matching a curated list of Netflix domains and sending that traffic out Spectrum. The domain list needs occasional refresh because Netflix shuffles its CDN egress patterns, but the routing rule itself is stable. Streaming has been boring ever since, which is exactly what you want from streaming. ### My VLAN segmentation was performative I had four VLANs, but the firewall rules weren't enforcing the trust boundaries I thought they were. In a stateful firewall, rule order matters because the first matching rule wins. A broad block rule above a narrow allow rule can silently kill the use case the allow rule was meant to support. That mattered for the IoT-to-Trusted path. Google Cast and one Minecraft device needed narrow exceptions, so those allow rules needed to sit above the broader IoT-to-Trusted block rule. They now do, which means the block rule is finally acting like a boundary instead of a suggestion. ### mDNS was the puzzle I did not know I had Once you segment a network properly, your phone on the Trusted VLAN can no longer magically see the Chromecast on the IoT VLAN. That is the point of segmentation, not a bug. The lazy fix is to punch broad firewall holes and call it a day. The gateway mDNS proxy does the job properly, scoped only to the VLANs that need to discover each other. I had no idea that feature existed before this exercise, and now I understand both the problem and the right way to solve it. ## The before and after The value of the session was a series of small corrections that made the system more understandable. | Area | Before | After | | --- | --- | --- | | WAN routing | 50/50 split across Spectrum and Verizon | Weighted routing that reflects Spectrum as the workhorse and Verizon as the helper | | VPN stability | Work traffic could land on the 5G path | Work MacBook pinned to Spectrum | | Streaming | Netflix could re-authenticate or drop quality | Netflix traffic routed consistently through Spectrum | | IDS/IPS | Control scope was narrower than my mental model | Scope captured as a known gap with a clear next step | | IoT segmentation | VLANs existed, but boundaries were loose | Narrow allow rules placed above broader deny rules | | Device discovery | Broad access was tempting | Scoped mDNS between only the VLANs that needed discovery | | Documentation | Most intent lived in my head | `NETWORK.md` became the source of truth | That table captures the difference between a system that works and a system I can explain. ## What this looked like in practice Claude Code never typed into my UniFi dashboard, and it didn't need that level of access to be useful. This was a working session where I described what I had, Claude Code asked clarifying questions, suggested changes with reasoning, and I made the changes by hand in the UniFi UI. ![UniFi dashboard showing internet activity and device health.](/images/blog/2026/05/unifi-console.png) That separation of concerns is important. Claude Code could reason, challenge, summarize, and suggest, but I still made every change manually. Anything that touches routing, firewall rules, segmentation, or security boundaries deserves that level of friction. Agents advise; humans decide. What the agent did, and what would have taken me much longer alone, was hold the whole picture in its head while I poked at one corner at a time. When I changed the WAN weighting, it reminded me to verify that NAT and failover behavior still made sense. When I added the Netflix routing rule, it asked whether I should sanity-check the QoS rule for FaceTime so I wasn't stacking conflicting policies on the same path. That is the kind of assistance I value. It's better pressure against my own assumptions. ## The document became the deliverable I left the session with a `NETWORK.md` file I would trust because it captured the reasoning behind the configuration. I wrote the bones. Claude Code pressed on the gaps, challenged the weak spots, and pushed me to capture the rough edges I'd normally leave implicit. Every VLAN now has a documented purpose. Every firewall rule has a documented intent. Every known issue is called out by name, including the Living Room access point negotiating at 100 Mbps because of what's almost certainly a flaky cable run, the Guest VLAN that exists but does not have a live SSID yet, and the IoT migration from `carpenter` to `carpenter-iot` that is roughly a third complete based on live client counts. ![UniFi traffic view showing client-level usage patterns.](/images/blog/2026/05/unifi-traffic.png) That document is now the source of truth I will hand to future me when I forget why I made these decisions 18 months from now. This is the same idea I have been pushing at work for the last year: the Context Spine. It's a lightweight, versioned artifact that travels with the system and explains intent, and it turns out the pattern works for a home network too. ## What I learned A few lessons stuck with me after the configuration changes were done and the house internet was still, thankfully, working. ### The tool is not the point Claude Code is excellent, and so are Claude chat, the API, and a growing list of other AI surfaces. Picking the right one matters, but it matters less than being clear about what you're trying to accomplish. I used Claude Code here because I wanted shell access, file editing, and the ability to iterate on a markdown document over a longer working session. Different tasks deserve different tools, so the lesson was to bring the right context to the right tool, then stay engaged. ### Domain expertise compounds I am not a network engineer. I am a software person who has run enough infrastructure to be useful and occasionally dangerous, which is a very specific and familiar kind of confidence. Claude Code is not a network engineer either, but when we combined vendor documentation, RFCs, live configuration, and a willingness to verify everything, we made better decisions than I would have made alone on a Saturday morning. That distinction matters because the agent amplified my curiosity instead of replacing expertise. ### Documentation is the durable artifact The improved configuration, the better firewall posture, and the cleaner routing model all matter. The most durable artifact is still the markdown file that explains why the system works the way it does. If the only thing AI tools did was lower the activation energy for writing things down, they'd already be valuable. Most systems fail because nobody remembers the reason, not because nobody can find the setting. ### Be skeptical, including of the agent Claude Code suggested a few things I rejected. One recommendation around region blocking would have cut off a country my brother travels to for work, while another proposed rule change would have broken Google Cast for the Apple TV in the living room, which my daughter would have noticed within an hour. The agent was confidently wrong in both cases, and catching that is the job. Good collaboration looks the same whether your collaborator is human or AI. They bring breadth, you bring judgment, and both sides verify. ## The pattern I would reuse The pattern is simple enough to reuse well beyond home networks. 1. Export or write down the current state. 2. Describe the intent, not just the configuration. 3. Ask the agent to challenge assumptions. 4. Verify recommendations against documentation and real behavior. 5. Make changes manually when security or reliability is involved. 6. Capture the final state as durable documentation. That pattern works for a UniFi network. It also works for a CI/CD platform, a Kubernetes operating model, a cloud account structure, a service onboarding flow, or any system where configuration and intent have drifted apart. The point is to make the system legible enough that a human can steer it better. ## What is next The known rough edges in `NETWORK.md` are now a small backlog. I need to widen IDS/IPS scope to cover the networks that matter, stand up the Guest SSID with a proper egress-only firewall rule, finish migrating IoT devices off `carpenter` and onto `carpenter-iot`, and replace the cable that's making the Living Room access point negotiate at 100 Mbps when the rest of the network is gigabit. None of this work is glamorous, but all of it is the kind of work that gets deferred when you don't have a clear picture of the system. I have a clear picture now, and the backlog is finite. That, more than any single configuration change, is the win. ## Why I think this matters I write a lot about AI in the enterprise, including pipeline-first delivery, the agentic SDLC, the Context Spine, the apprenticeship argument, and the need for teams to treat AI as part of the delivery system rather than as a novelty sitting off to the side. The risk in writing about all of that from a corporate perch is that it can start to sound abstract. Strategy decks, steering committees, and slides can read well without ever touching a real system. Spending a Saturday using the same tools I'm asking my organization to understand, on a problem that mattered to my actual life, is the cheapest way I know to keep that thinking honest. If Claude Code can help a VP of Engineering build a better home network on a weekend, it can help an engineer at any level go faster on Monday, given the right context, the right guardrails, and the right level of human judgment. My network is faster, safer, and finally documented. More importantly, I understand it again. --- ## Spec, Standards, Specialists: How I Actually Build with AI - **Published:** 2026-04-30 - **Tags:** ai-coding, engineering-leadership, claude-code, spec-driven-development, platform-engineering, agentic-sdlc - **URL:** https://vinny.dev/blog/2026-04-30-spec-standards-specialists-final/ *The strategy posts say AI software development is a system. This is the practitioner layer underneath that idea.* I've written a lot lately about the strategy of AI-assisted development: the [dark factory model](https://vinny.dev/blog/2026-04-05-dark-factory-model-for-ai-software-development/) for the mental picture, the [Agentic SDLC](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) for how the tool sprawl resolves into a pipeline, and [Claude Code as a build system](https://vinny.dev/blog/2026-04-25-claude-code-build-system/) for how the daily tooling has to be configured. This post is the working loop underneath those ideas. It's the workflow I run on real features: write a spec, load the project standards, hand the brief to Claude Code, and let a coordinated set of specialist agents work inside the guardrails. The AI writing code is the least interesting part. What matters is that the system has enough context, standards, and review pressure to produce code I can trust. That is the shift. AI-assisted development is turning into an engineering workflow rather than a better chat window. That is the whole shape: | Layer | Artifact | Purpose | Failure mode if missing | | --- | --- | --- | --- | | Intent | `tasks/spec.md` | Defines what we are building, for whom, and how we will know it works | The system confidently builds the wrong thing | | Context | `CLAUDE.md` | Tells the system where the work lives and how the project operates | The output looks like a stranger wandered in with a keyboard and confidence | | Standards | `coding-standards.md` | Defines the non-negotiables for quality, security, accessibility, testing, and maintainability | The code compiles, passes light review, and quietly drifts | | Execution | Specialist agents | Breaks work into focused planning, building, review, docs, and closing loops | One giant session tries to be good at everything and misses important details | A quick definition before we go further. I use "AI-assisted" to mean a developer typing prompts into a chat window and reviewing each suggestion. I use "agentic" to mean a system where the model plans work, dispatches parts of that work to other models, and operates inside guardrails I designed ahead of time. The difference is who holds the steering wheel between turns. In an AI-assisted setup, you do. In an agentic one, the system does more of the driving, and you set the rails. I am writing for two readers at once. If you're an engineering leader trying to understand what an AI-native delivery model could look like at team scale, this workflow is one of the units of work you may need to industrialize. If you're a senior engineer who wants a working blueprint, this is the loop, the inputs, and the costs, without pretending the rough edges are gone. The leadership read sits on top of the practitioner one because the operating model already exists in pockets. The leader's job is to recognize the one some engineers are already running and scale it intentionally. ![The workflow](/images/blog/2026/04/spec-standards-specialists-workflow.svg) ## A representative example Before the mechanics, here is what this looks like in practice. On a recent side project, I was working through what looked like a small settings feature. The first instinct was to treat it like a simple UI change: add a control, wire it to persistence, update the state, move on. The spec review slowed me down in the best way. Claude came back with questions I should have asked myself first: - What happens if the stored value is missing or malformed? - Should the setting sync across devices or remain local? - What is the default for a returning user? - Does the UI need to announce the change for assistive technologies? - What should the user see if the save fails? The original version in my head had one acceptance criterion: the setting can be changed and saved. After the spec review, the feature looked different. | Before spec review | After spec review | | --- | --- | | Setting can be changed and saved | Default behavior is defined | | Basic persistence | Malformed stored values are handled | | Happy-path UI control | Accessibility announcements are included | | Save action works | Save failure behavior is specified | | State updates locally | State restoration is tested | None of those questions required genius, only patience, and patience is exactly what a good workflow can force. The planner split the work into smaller tasks than I would have written on my own, and the builder wrote the failing tests first. The reviewer caught an accessibility gap in the control behavior. Then `/qcheck` flagged a mismatch between the implementation and the acceptance criteria. None of the findings was dramatic, which was the point. The workflow caught small problems while they were still cheap. It didn't make the work effortless, but it did make the work harder to lie about. ## The three inputs Every feature I build with AI starts with the same three artifacts. None of them is the code. A specification. What we are building, why, for whom, with what constraints, and how we will know it works. The spec is the contract. If it's vague, everything downstream is vague. Technical preferences. The platforms, languages, frameworks, and runtime targets this project lives inside. SwiftUI on a recent macOS, Bun and TypeScript with React, Java 21 with Spring Boot, AWS-native or on-device foundation models. The AI shouldn't have to guess at any of it. Coding and design standards. The non-negotiables. File size limits, type safety rules, accessibility baselines, security defaults, test discipline, naming, error handling. The body of work I packaged into a [reusable Claude Skill](https://vinny.dev/blog/2026-03-28-coding-standards-skill/) so my standards travel with me from project to project. These three inputs are the brief. Everything else is execution. The order matters. Specs without standards produce plausible code that fails review, and standards without a spec produce well-structured code that solves the wrong problem. Preferences without either produce something that compiles, ships, and breaks in production three weeks later. All three, together, are the minimum viable brief for an agentic workflow. Skip any one of them and the loop downstream gets noisier in proportion. ## Step 1: write the spec with Claude, not for Claude Here is the first place many people get this wrong. They open Claude, type a paragraph that starts with "build me a feature that," and call that a spec. That is a prompt, and a prompt commits nobody to anything. I use Claude as my drafting partner for the specification itself. I give it a rough description of the problem, the user, and the outcome I want. It comes back with a structured draft: goals, inputs and outputs, constraints, edge cases, out of scope, acceptance criteria, and open questions. The open questions are the most valuable part. They are the holes in my own thinking, surfaced before I write a line of code. Most of my first-draft specs come back with a healthy list of open questions. A handful are genuinely unresolved product decisions, a few are technical assumptions I hadn't validated, and the rest are edge cases I had not considered. I answer them, the spec firms up, and what looked like a one-week feature often turns into a clearer two-week feature with sharper acceptance criteria. That's a win, even though the timeline grows. A vague feature shipped fast is a bug factory in slow motion. The shape of a working spec is boring on purpose: - Goal. One paragraph. What changes for the user. - Inputs and outputs. What the feature consumes and produces. - Constraints. Performance, privacy, platform, dependencies, and time. - Edge cases. What we expect to fail and how it should fail. - Out of scope. What we are deliberately not doing. - Acceptance criteria. Testable statements, one per behavior. - Open questions. Things we still owe ourselves an answer on. Claude is good at producing this structure, and I'm good at deciding what belongs in each box. The collaboration is asymmetric on purpose, with the model bringing completeness and me bringing judgment. I keep the final spec in `tasks/spec.md` in the repo, and every later step in the workflow reads from it. The spec keeps evolving as I learn during the build. When I discover a new edge case, it goes into the spec, not just the code. The spec is the source of truth. The code is what falls out of it. This is the discipline that vibe coding skips. Vibe coding is fun, and it produces something that looks like progress in the first hour. It can also produce something that looks like a tire fire in the third week. ## Step 2: pair the spec with preferences and standards Once the spec is real, the next step is to make sure the AI has the rest of the brief. This is where the workflow stops being "talk to Claude" and starts being "load the project's working memory." That memory lives in three files in the repo. `tasks/spec.md` holds the specification. The thing we just wrote. `CLAUDE.md` holds the technical preferences and project conventions. Roughly 200 lines, project-specific, loaded into every session automatically. What stack, what versions, what file layout, what to never touch, and what local commands matter. This is the file that tells the AI you use Bun, not npm. That migrations live under `db/migrations` and require a separate review path. That the design system lives in `packages/ui` and nothing else can hand-roll a button. That `safeParse` is preferred to `parse` on user input. The boring details matter. They determine whether the output looks like it belongs in your codebase or like a stranger wandered in with a keyboard and confidence. `coding-standards.md` holds the long-form standards. The same standards document I distilled into a [reusable skill](https://vinny.dev/blog/2026-03-28-coding-standards-skill/) so my standards travel with me from project to project. File size limits, type safety, security defaults, accessibility baselines, testing discipline, and the red flags list. The skill version makes this portable, and the repo copy makes it concrete. Both earn their place. The skill is the canonical source, and the repo copy is the version this project agreed to follow when the work started. Together, those files answer three different questions: - The spec answers what we are building. - The preferences answer where it has to live. - The standards answer how it must be built. This is the layer many teams underinvest in. They have specs of varying quality and they have stacks. They may even have standards, scattered across wiki pages, pull request comments, and the collective memory of three senior engineers who everyone keeps interrupting on Slack. That is not enough for an AI workflow. The AI needs the standards in a form it can use. Otherwise, it defaults to a generic best-guess style that looks fine and fails review. Better prompting doesn't fix that. The fix is doing the writing once so every session inherits it. If I had to pick the single highest-leverage day of work for a team adopting this kind of workflow, it would be the day they sit down and write the standards file. That day counts for more than the day they pick a model or the day they buy seats. Everything else compounds on it. ## Step 3: hand the brief to Claude Code, then let the specialists work This is the part that surprises people the first time they see it. I don't ask Claude Code to build the feature; I ask the main session to read the brief, plan the work, and dispatch specialists to do it. In this workflow, a specialist means a narrowly scoped agent configuration rather than a person: a role, a prompt, a tool boundary, and a definition of done. The fan-out usually looks something like this, depending on the feature: - A planner session reads the spec, the preferences, and the standards. It produces a task breakdown, a dependency order, and a definition of done. The output goes to `tasks/todo.md`. - A builder subagent takes one task at a time. It writes the failing test first, then the minimum implementation, against the standards. Strict red, green, refactor. - A reviewer subagent runs after each meaningful change. For component work, it is the [accessibility reviewer](https://vinny.dev/blog/2026-04-25-claude-code-build-system/). For data work, it is the migration reviewer. For security-sensitive paths, it is a focused audit subagent. Read-only, narrow tools, explicit findings. - A docs subagent updates README files, ADRs, and inline docs as the implementation lands. Documentation as the work happens, not as a guilt trip at the end. - A closer session runs `/qcheck`, my skeptical staff-engineer review command, against everything that changed in the session. It compares the diff to the spec and the standards and flags anything that drifted. Each specialist has one job, a tight tool allowlist, and its own context window. The main session doesn't have to hold every domain in its head, because the specialists do that work. This is [principle three of the build system view](https://vinny.dev/blog/2026-04-25-claude-code-build-system/): specialists beat generalists. It's also the practical answer to the [tool sprawl problem](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/). The pipeline is a coordinated multi-agent workflow with clear interfaces. I sit in the loop, not above it. I review the planner's task list before the builder runs, and I read the reviewer's findings before merging. I'm steering the system that types the code. That is the [dark factory](https://vinny.dev/blog/2026-04-05-dark-factory-model-for-ai-software-development/) in practice. Lights-on at the inputs and outputs. Lights-off in the middle. My job is to design the line and check the parts coming off it, not to weld every joint by hand. The failure mode this pattern helps solve is hidden quality drift. The naive version of an agentic workflow is one large session that holds everything in its head: the spec, the standards, the migration rules, the accessibility rules, the security checklist, and the current task. That session can do pretty good work across 10 domains. The output compiles, the tests pass, and the code looks fine. You don't notice the cost until the third regression, the missed accessibility issue, or the migration that locked the database. A specialist does better work in one domain because its context window isn't polluted by the other nine. Multi-agent workflows aren't always faster than a single big session in any one moment, but they are sharper across many moments. That is the trade. ## The guardrails matter more than the agents The agent setup only works because the permissions are intentionally boring. Reviewers are read-only, builders get narrow tool access, and destructive operations require human approval. Secrets stay out of prompts, and hooks log the commands that matter, so the workflow creates a trail of what changed, what ran, and what the system decided. That boredom is what lets the workflow move quickly without pretending the model deserves unlimited trust. That matters even more at team scale. A personal workflow can survive some rough edges because the person running it knows where the sharp corners are. A team workflow needs those edges made visible. The better question is what permissions, context, and review pressure let the agents be useful without becoming reckless. That is a much healthier place to start than asking how to make them more powerful. ## Where I still require human judgment The workflow delegates work. It does not delegate accountability. There are specific points where I still want a human in the loop: - Before accepting the spec. - Before approving the planner's task list. - Before letting implementation proceed after the failing test. - Before accepting or overriding reviewer findings. - Before merging the pull request. - Before changing standards that other sessions or teams inherit. Those checkpoints are where judgment matters most. The model proposes, the system executes, and the specialists review. I still own the decision. That distinction matters. The more capable the tooling becomes, the easier it is to confuse fluency with trustworthiness. Polish is not correctness. ## What this looks like end to end A single working session usually starts with the same rhythm. I open the project, and `CLAUDE.md` and the standards skill load automatically. I open `tasks/spec.md`, refine the next slice of work with Claude in conversation, and commit the updated spec. I run a planner prompt that reads the spec and the standards and produces a task list. I review it, push back on anything that feels off, and commit `tasks/todo.md`. The planning step is short, but it protects the build from drifting. A plan I disagreed with on Tuesday will produce code I disagree with on Thursday. Then I run `/tdd` against the first task. The builder writes a failing test, I read it and approve it, and the builder writes the minimum implementation. The accessibility reviewer fires automatically on changed components, and I read its findings. The post-tool-use hook runs a fast type check, the audit hook logs the bash commands, and the decision hook captures the diff to the daily log. I move to the next task on the same loop. The docs subagent updates the README as features land, and the reviewer subagents catch the things I'd miss at midnight. When something bites me twice, the lesson goes into `tasks/lessons.md` so the next session inherits the scar tissue. When the slice is done, I run `/qcheck`. It reviews every changed file against the standards, flags drift, and tells me what is not yet ready to ship. I fix the flagged items and push. CI runs the heavy suite, and the pull request opens with a generated description that pulls from the spec and the diff. I published a small companion repo with the artifacts from this post at [github.com/vscarpenter/multi-agent-workflow](https://github.com/vscarpenter/multi-agent-workflow). It includes the spec, project memory, standards, subagents, commands, hooks, planner output, and one completed vertical slice so you can see how the scaffolding turns into code. The repo is there to make the workflow inspectable rather than to be copied blindly. I did not type a `for` loop. I made a stack of decisions, all of them about intent, structure, and trade-offs. The mix has shifted over the last year toward more design and less syntax, more review and less translation. The total work is not smaller. The hours feel different at the end of the day, in ways I am still adjusting to. ## I do not use the full loop for everything This is important. I do not use the full multi-agent loop for every change. A copy edit, a small refactor, or a low-risk internal tweak doesn't need a five-agent procession with tiny ceremonial hats. The workflow earns its keep when the work has ambiguity, risk, cross-cutting impact, or enough surface area for quality drift to hide. The way I think about maturity looks roughly like this: | Level | Workflow | Best for | | --- | --- | --- | | Level 1 | Spec plus Claude Code session plus human review | Small, low-risk features | | Level 2 | Spec plus standards plus one reviewer agent | Medium-risk changes | | Level 3 | Planner plus builder plus reviewers plus closer | Complex or high-risk features | | Level 4 | Team-owned standards, versioned agents, measured outcomes | Scaled engineering organizations | That framing matters because the goal is to match the workflow to the risk. A mature engineering organization already does this with architecture review, security review, testing depth, and release controls. Agentic engineering needs the same judgment. Use the full loop when it earns its keep. Do not build a cathedral for a closet shelf. ## What the loop costs I will not pretend this is free. Five honest costs are worth naming. Up-front investment. The first time you do this on a new project, you're writing the standards, the `CLAUDE.md`, the slash commands, and the subagents. That is real work. It pays back inside two or three features, but the first feature feels slower because you're building the factory and the product at the same time. Leaders can get impatient with this trade. Senior engineers usually recognize it. The way through it is to call it out explicitly so nobody confuses ramp cost with permanent cost. Discipline. The loop only works if you keep `spec.md`, `todo.md`, and `lessons.md` honest. If `todo.md` drifts out of sync with reality, the next session resumes from a lie. I have done this. It's recoverable, but the cost is real. The fix is boring and effective: end every session with the state files matching the world. Judgment load. You make fewer keystrokes and more decisions. That's a different kind of tired. By the end of a long session, my hands are fine and my brain is cooked. If you go in expecting AI-assisted development to feel like a vacation, you'll be disappointed. You may also become worse at it, because the hard part moved instead of disappearing. False confidence. The output looks polished, the tests pass, and the reviewer subagents say the diff is clean. It's easy to assume the code is correct and ship it without enough thought. The discipline of `/qcheck` and human review exists because polish is not correctness. The loop is fast, and that speed deserves a counterweight. Thin specs. This one deserves its own warning, because the whole loop is built on the spec. If you skip Step 1 and go straight to Step 3, you'll get something. It may look fine, and it will often be wrong in ways you only discover when a user does something the spec would have caught. Every time I have been burned by this workflow, the root cause has been a thin spec. Always. The wins are bigger than the costs, but only if you're honest about both. ## What I am still working out A short section, in the spirit of saying the quiet part out loud. I have not figured out how to share a multi-agent workflow across a team without flattening the parts that make it work. The standards layer scales, the subagents scale, and the slash commands scale. The judgment that decides when to override the planner, when to ignore a reviewer flag, and when to throw out the day's work and rewrite the spec scales through mentorship, practice, and shared review, none of which transfers by copying files. I am still working out what that mentorship looks like in a world where the keyboard time is increasingly delegated. The half-formed thought I am testing: the apprenticeship model has to move from pairing on code to pairing on specs and reviews. Senior engineers narrate why they reject a planner's task list, not why they wrote a particular function. I also have not solved the cost problem at scale. A multi-agent workflow uses more tokens than a single session. For a senior engineer running this loop on high-leverage work, the math can be easy. Across a large engineering organization, the math becomes a real conversation, and one worth having with finance partners before the usage curve surprises anyone. I'm leaning toward tiering the workflow, with full multi-agent loops for complex or high-risk features and lighter single-session work for the routine path. Treat the org-wide bill as a portfolio rather than a flat rate. There's also a measurement problem. The most interesting gains are not always visible in raw throughput. Some show up as better specs, some as fewer review cycles, and some as defects that never escape because the workflow caught them early. Those are real outcomes, but they require better instrumentation than "how many lines of code did the AI write?" The metric I am watching most closely right now is rework rate, the share of pull requests that require substantive changes after initial implementation. It's the cleanest proxy I've found for whether the spec was real and the specialists did their job. If you've figured out how to scale the judgment layer, the cost model, or the measurement model, I would like to hear about it. I am still learning this part. ## What this means for engineering leaders This is bigger than a personal productivity setup. One credible shape of an AI-native software organization looks a lot like this workflow scaled to a team. The spec layer is product engineering, formalized. It forces the conversation about what we are building before we start arguing about how. It's the same discipline we've always wanted from product specs, now reinforced by the fact that an AI cannot proceed reliably without one. Teams that have struggled to maintain spec discipline in the past will discover, sometimes painfully, that AI exposes the gap immediately. That is a feature, not a bug. The bottleneck moves from typing to thinking, which is exactly where it should be. The preferences and standards layer is platform engineering: shared `CLAUDE.md` baselines, a team-owned standards skill, a common set of subagents for review work, and permission baselines that ship with the platform, not assembled by every developer at their kitchen table. This is the same [pipeline-first culture shift](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/) work, applied to AI tooling instead of CI/CD. The same uncomfortable conversations apply. Centralized defaults feel slower in the moment and faster across the year. Done well, standardization frees senior engineers to do the work only senior engineers can do. The orchestration layer is delivery engineering. Multi-agent workflows, each role with a job and an interface, look a lot like any well-designed delivery system. The [Agentic SDLC post](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/) was about why the boundaries matter. This post is about what it feels like when you draw them. At team scale, those boundaries need owners. Subagents need versioning, review, and a path to retirement. Standards need a steward, and specs need a template the team agrees on. None of that is glamorous work, and all of it determines whether the system gets better every week or rots into shadow tooling. The leader's job in this world is to make sure the spec layer is real, the standards layer is owned, and the orchestration layer has paved paths. The teams that learn how to do that early will have an advantage over teams still treating AI coding as a personal productivity hack. ### A note on what "senior" means now The bar for senior engineering is changing. Writing correct code quickly still matters, and it will always matter. But speed at the keyboard is becoming less differentiating by itself, because the model can now do more of that translation work. The differentiating skills are moving upstream and downstream: writing a clear spec, holding the line on standards, designing the boundaries between agents, reading a diff with skepticism, knowing what to test, knowing what to mock, and knowing when the model is confidently solving the wrong problem. Those skills were always valuable. AI just makes them more visible. If you're a leader thinking about hiring, promotion criteria, or career ladders, this is the conversation worth having now. Hiring for prompt craft misses the point. Every senior engineer will need to become better at defining intent, constraining systems, and reviewing work produced by something other than a human teammate. That is a real shift, and a healthy one. ## Where to start If you want to start running this loop, you don't need to rebuild your tooling. Start with five things, in order. 1. Pick one feature on one project. Small enough to ship in a week. Real enough to matter. 2. Write the spec with Claude, not for Claude. Use the seven sections above. Answer the open questions before you write code. 3. Make sure your `CLAUDE.md` and your standards file are real. If they aren't, today is the day. Two hours of writing can pay back for months. 4. Run the build with one specialist in the loop. A reviewer is the easiest place to start, with read-only access, narrow tools, and explicit findings. 5. Close the loop. Run a skeptical review pass against the spec and the standards before you push. Even one prompt works. `/qcheck` is just a saved version of that discipline. That is the minimum viable version. From there, add planners, docs subagents, and the rest as the absence of each one starts to hurt. The way you know you need a new specialist is simple: it is the moment you catch yourself wishing for one. Build it then. If you're a leader and you want this to scale beyond a few enthusiasts, the equivalent five things look different. 1. Identify the one team most likely to make this work. Senior, motivated, willing to share what they learn. Resource them to pilot. 2. Make the standards layer a platform deliverable, owned, versioned, and governed. A wiki page with good intentions and an expiration date does not count. 3. Define what a spec looks like for your organization. Template it. Make it the price of admission for any AI-assisted feature. 4. Build a small library of reusable specialists. Reviewers first. They have the highest signal-to-noise. 5. Measure something honest. Pick one: lead time on AI-assisted features versus comparable ones, defect rate on AI-assisted code, reviewer flag rate per pull request, or rework after initial implementation. Watch the trend for two quarters, then decide with those numbers in front of you. Ship when the system earns your trust. That standard is good news for engineers who like to think, and a fair warning for the ones who built a career on speed alone. --- --- ## Claude Code Is a Build System, Not a Chatbot - **Published:** 2026-04-25 - **Tags:** ai-coding, engineering-leadership, claude-code, spec-driven-development, platform-engineering - **URL:** https://vinny.dev/blog/2026-04-25-claude-code-build-system/ *A year of refinement, six principles, and the configuration to back them up.* > **Repo:** [github.com/vscarpenter/claude-code-build-system](https://github.com/vscarpenter/claude-code-build-system). Fork it, take what is useful, skip the rest. Most Claude Code setups start the same way mine did. You treat it like a very smart chatbot you have to babysit. You write detailed prompts. You paste in style guides. You ask nicely for tests. It works when you are paying close attention. It fails silently when you are not. The setup I use now treats Claude Code more like a build system: configurable, layered, observable, and designed to keep working when my attention drifts. That shift took 13 months, a lot of failed experiments, and enough humbling moments to keep the learning honest. I do not mean Claude Code replaces CI, Make, Gradle, Xcode, or your deployment pipeline. I mean it deserves the same operating model we give build systems: explicit rules, repeatable workflows, guardrails, logs, fast feedback, and a bias toward automation over memory. This post covers the configuration I have converged on across daily use on multiple projects spanning JavaScript, TypeScript, Java, Swift, Python, and a stack of utility projects. Six principles, the actual code that implements them, what I got wrong, and a starter kit if you want to skip some of the fumbling. ## The shift: discipline does not scale For the first few months, I did what most people do. I wrote detailed prompts. I pasted in style guides. I asked Claude to run tests, follow conventions, and avoid known traps. It worked when I was fully engaged. It failed the moment I got distracted. The shift came when I stopped writing instructions and started writing enforcement. Instead of "please run the tests after editing," I added a hook that runs a fast type check automatically. Instead of "remember to follow the accessibility checklist," I built a subagent that reviews changed `.tsx` files against WCAG AA. Instead of "use `safeParse` rather than `parse` on user input," I documented the lesson in `tasks/lessons.md` and reinforced it across sessions. The principle is simple: anything you have to remember to do, you will eventually forget. Anything you can put in a hook, a skill, a subagent, a slash command, or a denylist will keep working when you stop paying attention. Everything else in this post is a corollary. ## Principle 1: write the standards once, reference them everywhere I have a 753-line `coding-standards.md` checked into the repo. It has 10 parts covering agentic behavior, code quality, testing, security, git workflow, ADRs, task management, prompt engineering, reusable skills, and a quick-reference list of red flags. That sounds excessive. It is not. The cost of writing it once amortizes across every session, every pull request, and every new contributor, human or AI. The benefit is that when I tell Claude to "follow the standards," it has standards to follow. Not "be careful," but explicit, prescriptive rules. The difference is structural. It is the gap between asking a junior engineer to "write good code" and handing them a clear style guide. Two files do the work: - `CLAUDE.md` loads automatically every session. It includes project conventions, gotchas, file locations, and what not to do. I keep it tight, roughly 200 lines, because it is always in context. - `coding-standards.md` holds the long-form rules. Skills, subagents, and slash commands reference it when they need deeper guidance. Each rule includes the reason behind the rule, not just the rule itself. That matters because future-me still needs to judge edge cases the document did not anticipate. "Use parameterized queries" without "to prevent SQL injection because of this attack pattern" produces a parrot. Include the why and you produce a thinker. I treat updates to these files as engineering work, not as edits to a notepad. ## Principle 2: make the right thing automatic, even when it costs you I run three custom hooks, all in shell scripts under `~/.claude/hooks/`. None of them is doing rocket science. The value is that they fire deterministically on relevant lifecycle events, with no prompting from me. `audit-command.sh` fires before every Bash tool call. It logs the command with timestamp and session ID. It pattern-matches against high-risk shapes such as `curl | sh`, `eval`, `exec`, and `git push --force`, then routes risky commands to a separate `flagged-` log. It is an audit trail, not a blocker. I review the flagged file weekly. `capture-decision.sh` fires after file mutations. It captures the file path, session ID, and a `git diff --stat` snapshot to a daily decision log. When I find a regression two weeks later, I can scroll back through `~/.claude/decisions/decisions-2026-04-25.log` and find the likely cause. `persist-memory.sh` is the one I would write first if I were starting over. When a session ends, it reads the session transcript, pipes it into a fresh `claude --print` invocation, asks the model to extract one to three reusable lessons, and appends them to `~/.claude/lessons.md`. Claude summarizes Claude. Over weeks, that file becomes an institutional memory of patterns and gotchas I would otherwise forget. Here is the illustrative shape of the script: ```bash #!/bin/bash # ~/.claude/hooks/persist-memory.sh set -euo pipefail MEMORY_FILE="${CLAUDE_MEMORY_FILE:-$HOME/.claude/lessons.md}" TIMESTAMP=$(date '+%Y-%m-%d %H:%M') INPUT=$(cat) TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // empty') [ -z "$TRANSCRIPT_PATH" ] && exit 0 [ ! -r "$TRANSCRIPT_PATH" ] && exit 0 # Cap transcript size. JSONL lines can be tens of KB each, and a long # session will blow past the prompt limit. Recent context is what matters. TRANSCRIPT_TAIL=$(tail -c 65536 "$TRANSCRIPT_PATH") [ -z "$TRANSCRIPT_TAIL" ] && exit 0 # Bound the call so a stuck CLI invocation cannot hang the hook. set +e LEARNINGS=$(printf '%s' "$TRANSCRIPT_TAIL" | timeout 120 claude --print \ "Review this Claude Code session transcript (JSONL). Extract 1-3 specific, reusable learnings. Format each as a single bullet on its own line: '- [YYYY-MM-DD] '. Output ONLY the bullets, nothing else. If there are no genuine insights, output nothing at all.") RC=$? set -e # On non-zero exit, claude writes the error to stdout. Do not append it # to the memory file or you will persist things like "Prompt is too long". [ "$RC" -ne 0 ] && exit 0 # Keep only well-formed bullet lines. LEARNINGS=$(printf '%s\n' "$LEARNINGS" | grep -E '^- \[' || true) if [ -n "$LEARNINGS" ]; then { echo "" echo "" echo "$LEARNINGS" } >> "$MEMORY_FILE" fi ``` The version in the [repo](https://github.com/vscarpenter/claude-code-build-system) adds debug logging and a TTY guard for safer manual testing. Either way, the pattern is general: when you want the system to learn from itself, pipe durable state into a fresh `claude --print` call and append the output somewhere the next session can see it. The cost is real. Hooks add latency. Nested Claude calls add usage cost. Hooks can also fail silently if you break them. I wrote the audit hook in March, broke it accidentally in April when I refactored the JSON parsing, and did not notice for nine days. That is the tax. You also need to choose the right lifecycle event. A fast type check works well as a `Stop` hook because it runs when Claude finishes responding. Memory persistence belongs closer to a `SessionEnd` hook because it needs the full transcript. If you run a nested Claude call from a session-end hook, set an appropriate timeout. Otherwise, the clever automation you lovingly crafted may quietly tap out like a marathon runner in dress shoes. For project-level enforcement, I use lighter hooks per repo. One project has a `PreToolUse` hook that blocks edits to `.env*`, lockfiles, and migration files. A `PostToolUse` hook runs `bunx eslint --fix` on edited TypeScript and JavaScript files. A `Stop` hook runs `bun typecheck` as a fast last-line check. The pattern is simple: project hooks for project-specific safety, global hooks for cross-project intelligence. ## Principle 3: specialists beat generalists The main Claude session is a generalist. It is good at a lot of things. It is not deeply expert at any one thing. When a domain has hard, non-obvious constraints, I push the work to a specialist subagent. Two examples carry most of the weight. `a11y-reviewer` is a read-only subagent that reviews changed `.tsx` files against the WCAG AA baseline from my standards doc. It checks semantic HTML, keyboard accessibility, drag-and-drop behavior, Radix dialogs, form labels, image alt text, color-only state, and modal focus. It returns findings as `file:line, issue, fix`. It does not modify code. The main session decides whether to act. `pg-migration-reviewer` reviews changes under `db/migrations/**` against documented PostgreSQL gotchas. `CREATE INDEX` without `CONCURRENTLY` blocks writes for the duration of the build. Adding a `NOT NULL` column without a default fails immediately on any non-empty table. Foreign keys often need `NOT VALID` followed by a separate `VALIDATE` step to reduce lock risk. `ALTER COLUMN TYPE` for incompatible types can rewrite the entire table. That is exactly the kind of constraint set you should not expect a human reviewer to remember at 11 p.m. on a Friday. The subagent format is approachable. Here is the frontmatter for `a11y-reviewer.md`: ```yaml --- name: a11y-reviewer description: Reviews changed React components against the WCAG AA baseline defined in coding-standards.md Part 2. Read-only. model: sonnet tools: Read, Grep, Glob, Bash --- You are a strict accessibility reviewer for this codebase. The baseline is non-negotiable... ``` Below the frontmatter is the system prompt, about 40 lines of explicit rules. The body of the agent is just a focused Claude session with one job and a tight tool allowlist. The win is not that the subagent is magically smarter. The win is focus. Its context window does not get polluted by broader feature work. Its prompt is precise. Its findings are concise and actionable. I run these subagents on Sonnet because Sonnet is fast and good enough for pattern-matching review work. I save Opus for the main session when I need deeper architectural judgment. The payoff has been concrete. The `pg-migration-reviewer` caught a regression in February where I added an index without `CONCURRENTLY` in a migration meant to run against a populated table. It would have blocked writes during the build. The subagent flagged it before I committed. I have not shipped a migration that locked the database since. ## Principle 4: rituals deserve commands Some moments in development have a fixed shape every time. Starting a feature. Writing the failing test. Reviewing your own work before a pull request. Each is a ritual with predictable inputs, predictable structure, and predictable failure modes if you skip a step. I encode those rituals as project-level commands and skills. Claude Code now treats older `.claude/commands/` files and newer skills as part of the same slash-command surface. My examples still use commands because they are simple and portable. For richer workflows with supporting files, versioned instructions, and more reusable behavior, I would move them into skills. Three commands carry most of the weight. `/qspec ` generates a Spec-Driven Development spec to `tasks/spec.md`. It includes Goal, Inputs and Outputs, Constraints, Edge Cases, Out of Scope, Acceptance Criteria, and empty test stubs that map to each acceptance criterion. The empty stubs are the magic. They make the spec executable, not just descriptive. No implementation code is written yet. `/tdd ` starts a strict red, green, refactor cycle. It writes a failing test first, pauses for my approval, then writes the minimum implementation. If the change touches `db/migrations/**`, it invokes `pg-migration-reviewer`. If it touches components, it invokes `a11y-reviewer`. The TDD discipline is enforced by the command itself. I cannot accidentally skip the red step unless I decide to bypass the ritual. `/qcheck` runs a skeptical staff-engineer review of every changed file. It runs `git status` and `git diff` first to understand the work. It checks file size limits, type safety, test quality, project-specific gotchas such as `safeParse` on user input, `bun run test` instead of `bun test`, `toast.error()` instead of `alert()`, and the full Definition of Done. The command file structure is intentionally simple: ```markdown --- description: Skeptical staff-engineer code review of changed files against coding-standards.md. --- Review all changed files in this session as a skeptical staff engineer. Apply the full coding-standards.md and CLAUDE.md rules. Run `git status` and `git diff` first to see what has changed. Then evaluate each changed file against: 1. Standards compliance (files <=350 lines, functions <=30 lines...) 2. Type safety (all signatures typed, no `any`...) [...] ``` The filename becomes the command. The frontmatter sets the description. The body is the prompt template. The flow is `/qspec` to think, `/tdd` to build, and `/qcheck` to ship. Three commands, one feature, less improvisation. ## Principle 5: memory is a feature, not a side effect Three layers of memory work together. `tasks/lessons.md` holds project-specific gotchas. I review it at the start of every session. When something bites me twice, it goes here. Examples from a recent project include: "auto-generated columns cannot be referenced in custom indexes," "the import parser strips trailing whitespace before validation," and "use `bun run test`, not `bun test`." Each entry is one or two lines. Each entry has saved me at least an hour of debugging. `tasks/todo.md` holds in-flight work. It has a "Resuming From Here" section so a fresh session can pick up without me re-explaining context. The discipline is simple: never end a session with this file out of sync with reality. Auto-memory under `~/.claude/projects//memory/` is Claude Code's own memory system. I store user-level facts such as "uses bun, not npm," feedback such as "TDD is the default workflow," and project-level decisions such as "merge freeze begins 2026-03-05" as discrete `.md` files indexed by `MEMORY.md`. The `persist-memory.sh` hook feeds new lessons into that broader memory pattern automatically. Each layer answers a different question. `lessons.md` answers: what gotchas exist in this project? `todo.md` answers: what was I in the middle of? Auto-memory answers: what facts about me, this project, and our agreements should persist across sessions? The cost of writing things down is lower than the cost of remembering them. That is true for humans. It is true for AI agents. It is especially true at the seam between the two. ## Principle 6: permissions are safety equipment, not friction I treat the permission allowlist the way I treat a seatbelt. I want it on. I want it tight. I want it to catch me when I make a mistake. My global `~/.claude/settings.json` denies `rm`, `sudo`, `chmod`, and reads of `.env*` and `**/secrets/**`. Those are categories I never want Claude to touch without explicit confirmation. Below the denylist, I allow common development tools such as `git:*`, `gh:*`, package managers, language toolchains, and container CLIs. The goal is balance. Broad enough that I am not approving every command. Narrow enough that nothing destructive is one keystroke away. Per project, I keep a `settings.local.json`, which is gitignored, for personal allowances and a `settings.json`, which is checked in, for the team baseline. The split matters. Anything in the team file ships to every contributor. Anything local is just mine. I prune the local file every quarter. Left unattended, it accumulates parser-artifact junk, one-shot literal commands, and stale entries from cross-project sessions until it becomes 250 lines of noise wearing a tiny permissions hat. The audit log from `audit-command.sh` is the third leg. Even when a command passes the allowlist, the log captures it. I scan the `flagged-` files weekly. Twice in the last six months, that scan caught a pattern I would have missed otherwise. The first was a `curl | sh` Claude proposed for a one-off install. The pattern matched. The flag fired. I read it the next morning and replaced the install with a `brew` formula. Without the audit hook, I probably would have approved it in the moment and forgotten. ## What I tried that did not work Four antipatterns burned time, so you do not have to repeat them. A heavyweight Stop hook. My first version ran the full Vitest suite at every conversation end. Thirty seconds, every time, on every project. I told myself it was the right safety net. It was a tax on iteration speed. CI catches the same things. I replaced it with `bun typecheck`, which runs in about three seconds, and I run the full suite manually before pushing. Lesson: hooks must be cheap or they become friction you eventually disable. Mocking the database in tests. I had a test suite where every Dexie call was mocked. The tests passed. The first real migration failed in production because the mocks did not model index behavior. A user lost local task data when the schema upgrade silently corrupted the indexed lookup. I switched to `fake-indexeddb`, a real IndexedDB implementation in memory. Slower tests, fewer false positives. Lesson: prefer fakes over mocks when the boundary is structural. Letting `settings.local.json` grow unbounded. Every "yes, allow this" click added a line. After a year, I had 256 entries. Half were stale: pnpm commands from a different project, Ruby and CocoaPods leftovers, and parser-artifact junk like lone `done` and `fi` lines from heredocs. I ran the `fewer-permission-prompts` skill, pruned the file to 101 entries, and added a quarterly calendar reminder to do it again. Lesson: anything that grows monotonically needs an explicit shrink ritual. Trusting the AI to remember the gotchas. Early on, I documented a gotcha in a code comment. The comment got refactored away. The gotcha bit me again two weeks later. The fix was to move durable lessons into `tasks/lessons.md`, which gets loaded into context at the start of every session. Comments are for explaining why nearby code exists. `lessons.md` is for explaining what to never do again. ## The leadership lesson hiding inside the dotfiles This started as a solo-developer setup, but the pattern is bigger than personal productivity. The enterprise version of this is not "everyone copy my dotfiles." That would be a terrible operating model, and an even worse onboarding experience. At team scale, personal hooks become shared policy. Local preferences become governed defaults. Slash commands become team workflows. Subagents need ownership, versioning, review, and a path to retirement. Standards need stewardship. Permissions need a baseline. Logs need a purpose beyond "future-me may want this someday." In other words, this becomes platform work. That is the leadership lesson for me. The most useful AI engineering systems will not come from asking every developer to become a prompt whisperer. They will come from giving teams safe defaults, paved paths, observable behavior, reusable workflows, and enough room for senior engineers to adapt the system to real work. The same principles we use for cloud platforms apply here. Reduce undifferentiated decisions. Make the secure path the easy path. Instrument the system. Preserve local autonomy where it matters. Build for learning, not just control. That is where AI-assisted development gets interesting. Not in the demo where the agent writes code once. In the operating model where the system gets better every week. ## What changes Monday If you have read this far, you are probably weighing the cost of improving your setup against the cost of keeping the one you have. Here is the smallest version that returns most of the value. Five things, in order. Maybe two hours of work. Start with context, then fast feedback, then memory, then repeatable rituals, then auditability. That order matters. You are building a system of control before you add a system of speed. 1. Write a `CLAUDE.md`. Keep it to roughly 200 lines. Include project conventions, file locations, gotchas, and what not to do. This single file delivers more value than any other piece of configuration because it gives every session a shared starting point. 2. Add a fast typecheck hook. ```json { "hooks": { "Stop": [{ "matcher": "", "hooks": [{ "type": "command", "command": "bun typecheck 2>&1 | tail -10", "timeout": 60 }] }] } } ``` Replace `bun typecheck` with `tsc --noEmit`, `mypy`, `cargo check`, `swift build`, or whatever is fast in your stack. The point is to catch the obvious stuff before the conversation ends. 3. Add `tasks/lessons.md` and reference it from `CLAUDE.md`. When something bites you twice, add a line. Review it at the start of every session. This is the cheapest memory system you will ever build. 4. Build one custom command or skill for your most common ritual. For me, it was `/qcheck`. For you, it might be `/release-notes`, `/db-migration`, `/triage-bug`, or `/incident-summary`. Pick the thing you do every week and never want to re-invent again. 5. Add the `audit-command.sh` hook. Log every Bash command. You do not need to do anything sophisticated with the log on day one. You will be glad it exists the first time something breaks and you need to retrace what happened. Or, if you want to skip the assembly, the full configuration is at [github.com/vscarpenter/claude-code-build-system](https://github.com/vscarpenter/claude-code-build-system). The repo mirrors the `.claude/` and `~/.claude/` layout you would set up locally, so you can clone, copy, and run. That is enough for the first pass. No plugins, no MCP servers, no elaborate subagent fleet required. Once those five pieces are in place, the next thing to add will become obvious because you will feel its absence. The bigger point is not the configuration. It is the operating model. Discipline does not scale. Automation does. Standards belong in files. Specialists beat generalists. Rituals deserve commands. Memory is a feature. Permissions are safety equipment. Pick one. Start Monday. --- *Written April 2026. Configuration tested across 13 months of daily Claude Code use on macOS. This is a solo-developer perspective; team-scale configuration adds governance concerns I am still working through. Hooks shown here use Bash. Windows users will need WSL or PowerShell equivalents.* --- ## I Built a Design System in Two Hours. Figma, We Should Talk. - **Published:** 2026-04-18 - **Tags:** ai-strategy, design, engineering-leadership, future-of-work - **URL:** https://vinny.dev/blog/2026-04-18-claude-design-disruption-beyond-figma/ My Anthropic todo list is out of control. Every week brings another product that deserves a full write-up. Claude Code. Claude Cowork. Claude in Chrome. Claude in Excel. Claude for Mac. Opus 4.7. And on Friday, Claude Design, which pushed my backlog to comical lengths. I carved out two hours with it today. I rebuilt the landing page for one of my apps, reimagined the design paradigm for my task management app, and built a custom design system I can apply across my full portfolio. All three. In two hours. I have a take. If I am Figma, I am worried. But the bigger disruption is not the one everyone is writing about, and I will get to that. ## Two hours, three real deliverables I am a VP of engineering, not a designer. I have taste. I can spot good work. I cannot produce it quickly on my own. Claude Design collapsed that gap in an afternoon. Not mockups. Not mood boards. Actual, shippable design work that holds up under scrutiny. The landing page looks like a landing page. The task manager redesign is a legitimate new paradigm, not a coat of paint. The design system has tokens, components, typography, and spacing rules I can hand to Claude Code tomorrow morning. The moment it clicked came about 90 minutes in. Claude Design lifted the accent color from my existing app icon and threaded it through every new screen, without me ever naming it. That is not a template. That is a tool reading the work I had already done. ## Under the hood During onboarding, Claude Design reads your codebase and design files, then extracts a design system from what it finds. Colors, typography, components, spacing. Every project after that snaps to your visual language automatically. You seed it with prompts, documents, screenshots, or a web capture from your live site. You refine through chat, inline comments, direct edits, or sliders that Claude itself generates. When the design is right, you export as PDF, PPTX, or HTML, send it to Canva, or hand it to Claude Code to ship. Datadog compressed what had been a week-long cycle of briefs, mockups, and review rounds into a single conversation. Brilliant reported that the most complex pages required 20 or more prompts to recreate in competing tools but needed only 2 in Claude Design. I believe them. I lived a compressed version of that today. One caveat worth naming. Claude Design is token-hungry. Reviewers at The New Stack reported burning through more than half their weekly Claude allotment in a single sitting. That covered one design system, one prototype, some tweaks, and a short video. Budget accordingly, and pick your projects. ## The Figma question Figma's stock fell about 7% on Friday following the announcement. That is not subtle. Mike Krieger, Anthropic's chief product officer, resigned from the board of Figma on April 14, three days before Claude Design shipped. Also not subtle. Figma still owns the professional UX market, with an estimated 80% to 90% share. That moat is real, built on years of craft, plugins, file formats, and muscle memory. Claude Design will not dislodge it overnight. But Figma sells to people who need to produce design work. Claude Design sells to that same group, plus everyone who never bought Figma because the learning curve was too steep. The addressable market just expanded and fragmented in the same week. If I am Figma, I am not panicking. I am revising the five-year plan tonight. ## The bigger story Anthropic is not a model company anymore. It is a full-stack product company with unusual range. The portfolio now includes a coding agent, a knowledge-work assistant, a browser agent, a Mac agent, Office integrations, and a design tool. Each product feeds the others. You can prototype in Claude Design, hand the spec to Claude Code, and have Cowork manage the review loop. One platform, one foundation model, one login. This is the application layer that belonged to Figma, Adobe, Microsoft, Atlassian, and the rest of enterprise SaaS. Anthropic just planted a flag in the middle of it. ## The disruption is not what most people think Reading this as Figma's death notice misses what is happening. Claude Design does not kill professional designers. Taste, judgment, systems thinking, and user empathy are not going anywhere. Those skills just became more valuable, because more people need a designer who can ride the new tools without losing the plot. The threat runs in a different direction. ## The apprenticeship problem Here is the part nobody is writing about. What Claude Design kills is the bottom half of the design marketplace. The one-off landing page gigs. The pitch deck polish. The first-pass mockups. The commodity work that paid the bills while juniors developed judgment. That work is now an afternoon and a Claude subscription. Every profession builds its seniors out of its juniors. Designers learn taste by producing a hundred mediocre landing pages before they produce one great one. Engineers learn architecture by debugging a thousand CRUD apps. Writers learn voice by filing a decade of copy nobody reads. Claude Design does not threaten the designers at the top. It threatens the ladder that produced them. The craft survives. The on-ramp does not. That is the disruption worth writing about, and the one I do not yet know how to solve. My own engineering org will face the same question inside a year. Probably sooner. ## What I am watching I have no shortage of follow-ups. I want to see how Claude Design handles my real apps beyond a two-hour sprint. I want to stress-test the Claude Code handoff on production work. I want to see how my own team reacts when I show them what a VP of engineering can now build over lunch. I also want to figure out how to keep up with the shipping pace. Anthropic is moving faster than my weekends, and my todo list, once again, is out of control. That is a complaint I am happy to keep making. --- ## The Agentic SDLC: Uniting the AI Tool Sprawl - **Published:** 2026-04-15 - **Tags:** ai-strategy, ai-coding, agentic-sdlc, engineering-leadership, software-engineering, spec-driven-development - **URL:** https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/ On Friday afternoon, the integration fails. Product used Jira's AI to generate the user story and a rough component spec. Design used Figma's AI to turn the wireframe into React. Engineering fed the same wireframe and ticket into a coding agent and got a different implementation. Each tool produced something plausible, and none of them produced the same thing. Nobody noticed until the work converged. That happens whenever organizations add AI capability faster than they add a framework for how that capability should be used. We have never had more AI across the product development life cycle. Jira can generate stories, Figma can export code, Copilot can write functions, Claude Code can restructure files, and Cursor can refactor an entire feature. The power is real. The problem is that every tool now wants to participate in every layer of delivery, and few teams have decided where each one should stop. The result is context sprawl. Multiple systems generate overlapping artifacts, each with partial context, high confidence, and no shared source of truth. Teams end up with more output, but less clarity. The natural reaction is to compare tools and ask which one is best. The question that matters more is how work moves cleanly from intent to design to implementation to validation when every tool is now trying to help at every step. That is the challenge hiding inside the AI tooling boom, and it leads to one uncomfortable truth: > AI did not create the broken handoffs between product, design, and engineering. It exposed them. Those handoffs were already messy. We just didn't move fast enough for the mess to become this visible. Now we do, and now it does. Whether they intend it or not, organizations are building an agentic software development life cycle. The question is whether they build it deliberately or inherit it by accident. --- > *The bottleneck has inverted. Writing code is no longer what slows most teams down. Knowing what to build, and communicating it clearly, is now the expensive human problem.* --- ## The hourglass inversion For most of the modern software era, implementation was the narrowest point in the pipeline. AI is changing that. As code generation becomes abundant, the constraint moves upstream, and the bottleneck becomes defining what should be built, specifying it clearly, and handing it off cleanly across layers. For a growing share of routine implementation work, code generation is becoming abundant. A skilled engineer with strong tools can now produce in hours what once took days or weeks. Novel architecture, complex distributed systems, and deep domain logic still require experienced judgment. That hasn't changed. What has changed is the amount of standard implementation work that can now be accelerated dramatically. Once that happens, the constraint moves. The pipeline slows down at the upstream layers instead, because they are too vague, too fragmented, or too inconsistent to guide high-speed execution well. When the requirements are incomplete, the interfaces are unclear, or the design lacks enough annotation to express intent, AI doesn't pause and ask for organizational maturity. It produces something anyway. That means the old cost of ambiguity, which used to show up as delay, now shows up as high-speed rework. Teams can now ship plausible-looking garbage faster than ever. At small scale, that produces frustration. At larger scale, it produces something more dangerous: institutional debt. AI-generated code enters the codebase faster than humans build shared understanding of why it exists, how it fits, and what assumptions shaped it. The velocity looks great this quarter. The maintenance bill arrives later, usually after the original prompt, author, or design context has disappeared. That is what makes this an operating model conversation rather than a tooling one. ## Why every tool is trying to do everything Before going further, it helps to be precise. Most of what vendors label as "agents" today are AI-assisted features operating inside a narrow context window and a constrained product boundary, not autonomous agents in any rigorous sense. They still matter, and teams should design them into a pipeline according to what they can reliably do, not what a marketing page claims they can do. The boundary problem is structural. Every vendor is under pressure to expand its role in the development life cycle before a competitor does. Jira doesn't want to remain a ticket system, Figma doesn't want to remain a design surface, and coding assistants don't want to remain line-by-line completion tools. Each product is being pushed toward end-to-end ownership. That ambition collides directly with the upstream bottleneck. Vendors are racing into the very handoffs where organizations are already least disciplined. The result is duplicated context, inconsistent outputs, and AI features making decisions outside the domain they understand. A Jira-generated implementation may fit a ticket neatly while ignoring architectural constraints. A Figma-generated component may look correct while failing your design system, accessibility standards, or state-management patterns. A coding agent may generate reasonable code while knowing nothing about the compliance boundaries or deployment conditions that shaped the requirement. These tools have narrow context and high confidence, which is a risky combination. No single tool is going to become the operating model for your product delivery pipeline. The organizations that navigate this well will define which layer owns which artifact, which tool is canonical at that layer, and how that artifact moves downstream. ## A better mental model: the Intent Stack The most useful reframe is to stop organizing around tools and start organizing around layers of intent. AI works well within a layer when the job is to expand, translate, or accelerate work that is already bounded. It's much less reliable when it has to cross layers without structured input. The safest and most scalable pattern is to treat the development life cycle as a stack of intent, where each layer has a clear responsibility, a clear output, and a clear owner. ### The Intent Stack | Layer | Responsibility | Primary Output | Owner | | --- | --- | --- | --- | | 1. Vision & Strategy | Business goals, user problems, desired outcomes | Strategic Brief | Product Leadership | | 2. Requirements | User stories, flows, contracts, domain rules | Context Spine | Product + Engineering | | 3. Design | Interaction patterns, component behavior, annotated decisions | Annotated Design | Design + Engineering | | 4. Implementation | Code generation, testing, refactoring, integration work | Reviewed and Tested Code | Engineering | | 5. Validation | Integration checks, performance, security, policy gates | Verification Report | Engineering | | 6. Feedback | User behavior, outcomes, production signals | Insight Loop | Product + Engineering | One important point this makes explicit is that the upstream layers cannot be treated as fuzzy pre-work. Product and design don't simply hand engineering a loose direction and wait for the code to clarify it. In an AI-accelerated system, that ambiguity becomes expensive much earlier. If requirements and design are underspecified, the implementation layer will move quickly in the wrong direction. That is why the stack needs clean handoffs as much as it needs owners. ## The Context Spine Every layer transition needs an artifact the next layer can consume without guessing. That artifact is what I call the Context Spine. It's a lightweight, living specification that carries intent through the pipeline, and it holds the minimum structured context needed to let downstream humans and machines act without inventing missing meaning. What teams usually have instead is a ticket with a paragraph, a design file with sparse annotations, and a lot of assumptions hiding in meetings, chat threads, or somebody's head. In a slower system, that can limp along. In a faster one, it fails noisily. A useful Context Spine can often be built from five fields: - problem statement - acceptance criteria - explicit constraints - interfaces - non-goals That's enough to capture the shape of the work without dictating implementation. ### Example: Context Spine for a notification preferences API ````markdown --- id: CSPINE-001 title: User Notification Preferences API owner: product-engineering status: draft version: 1.0 linked_design: figma://notification-preferences linked_schema: /schemas/notification-preferences.v1.json acceptance_test_suite: /tests/contracts/notification-preferences last_updated: 2026-04-15 --- ## Problem Statement Authenticated users need to control which transactional and marketing notifications they receive across email, SMS, and push channels. Current behavior silently defaults all users to opted in, creating compliance risk and avoidable customer-service volume. ## Acceptance Criteria - Authenticated users can retrieve current preferences across all channels - Users can update one or more channels in a single request - Changes propagate to downstream senders within 60 seconds - All changes are written to the audit log with actor, timestamp, and prior value ## Constraints - Security: Valid session token required; no service-to-service access in v1 - Compliance: Must support opt-out requirements under applicable regulations - Performance: p95 read latency under 100 ms; write latency under 250 ms - Data: Preferences are user-scoped with no cross-account visibility ## Interfaces - GET /v1/users/{user_id}/notification-preferences - PATCH /v1/users/{user_id}/notification-preferences - Output conforms to NotificationPreferences schema - Emits preference.changed event to notification bus ## Non-Goals - Admin override workflows - Preference inheritance across linked accounts - Frequency caps by channel - Migration of previously opted-in users ```` *Hat tip to Dan Greller for the frontmatter YAML idea. It sharpens the point that the Context Spine is a real pipeline artifact.* The YAML at the top is part of what makes the artifact useful to the pipeline. That metadata gives the spine an identity, an owner, a version, and traceable links to adjacent assets. It turns the document from a better-written spec into a real control point in the system. Notice what the rest of the spine leaves out. There's no framework, language, database, or deployment target in it. What the spine does define is the problem, with enough precision that a capable engineer, or a code-generating system, can produce a correct implementation without guessing at the business intent. The non-goals are especially important. That's where teams prevent an eager engineer, or an eager model, from helpfully building the thing nobody asked for. The Context Spine also matters for a more technical reason. Model outputs are non-deterministic, so the same prompt can produce materially different implementations across runs. The only durable way to manage that variance is to make the governing intent precise enough that deviations are easy to detect and reject. In regulated environments, that's table stakes. In every other environment, it is quickly becoming good engineering hygiene. ## What humans must still own This kind of pipeline raises the value of the work only people can do well. Humans still need to own problem framing. A model can elaborate on a requirement, but it cannot decide whether the requirement reflects the right business tradeoff, the right customer need, or the right sequencing of value. Humans still need to own boundary decisions. Someone has to decide where flexibility is acceptable, where risk is not, and when an exception deserves judgment instead of automation. Humans still need to own approval at transitions. The reviews that matter most in an AI-enabled pipeline are less about line-by-line code and more about whether the output still matches the intent, whether the design still fits the requirement, and whether the implementation still respects the constraints. Most importantly, humans still own accountability. Models do not carry responsibility for customer harm, compliance failure, degraded resilience, or rising maintenance burden. Leaders and engineers do. The goal is to place people at the decisions that require judgment, not at every operation. ## The governance dividend This is where the Context Spine stops being just a productivity artifact and becomes a governance asset. When an internal auditor, regulator, or risk partner asks why a change exists, who approved it, and how the implementation traces back to the stated requirement, the answer usually comes from memory, scattered artifacts, and reconstructed intent. That is manageable when software moves slowly. It becomes much harder when generated output increases the pace of change. A disciplined Context Spine creates a durable chain from intent to implementation. It makes the reasoning behind the code visible even after the sprint ends, the engineer moves on, or the toolset changes. Regulated industries feel this first, but the pattern is broader. Once generated code exceeds shared human understanding, every organization inherits maintainability and accountability risk. This is one reason I believe the next phase of software delivery maturity will be defined by whether an organization built an auditable, comprehensible path from intent to output. Which coding assistant it bought will matter less. That's also why velocity alone is the wrong metric. Leaders should care about how quickly code appears, but they should care even more about whether that code matches the intent that justified it. A practical metric here is Spec-to-Code Alignment. One simple proxy is to have teams track the percentage of generated code that required structural rework after review, meaning changes to logic, interfaces, data models, or integration behavior, not style cleanup. Even a rough weekly number starts to reveal whether the pipeline is getting clearer or noisier. ## Six principles for getting this right ### 1. Spec before speed Once code becomes abundant, vague inputs become more expensive. A weak spec is now a fast path to confusion instead of a slow one. Teams should resist the urge to celebrate generation speed before they improve the quality of the upstream artifacts guiding it. This is the same shift I described in [*From Vibe Mode to Spec Mode*](https://vinny.dev/blog/2025-08-10-From-Vibe-Mode-to-Spec-Mode/), now operating at the level of the whole pipeline instead of a single coding session. ### 2. Declare canonical tools at each layer Overlapping AI features will keep appearing across Jira, Figma, IDEs, and other platforms, and fighting that is a losing battle. The realistic discipline is deciding which output is canonical at each layer and explicitly treating the rest as secondary. If Figma owns the design artifact, a Jira-generated UI suggestion is advisory. If the repo-resident spec is authoritative, a chat-generated summary doesn't get to overrule it. ### 3. Produce consumable artifacts Every layer should emit something structured enough that the next layer can act on it without interpreting vibes. Markdown, JSON, OpenAPI, schemas, annotated designs, and testable acceptance criteria all work. Hand-wavy prose and tribal knowledge do not. The same logic drove [the rise of MCP servers](https://vinny.dev/blog/2025-11-01-the-rise-of-mcp-servers/): agents can only act on what is exposed to them in a structured, consumable form. ### 4. Own the Context Spine The most valuable asset in an AI-enabled pipeline is not the model but the artifact that tells the model, and the humans using it, what good looks like. Treat the Context Spine as a first-class asset in the repo, version it with the work it governs, and make drift visible. ### 5. Checkpoint transitions, not every operation Human review belongs at layer transitions. [The pipeline should handle repeatable mechanical checks](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/) such as tests, policy enforcement, security scanning, and dependency analysis. Human attention should concentrate on the places where intent can drift, assumptions can creep in, and business meaning can be lost. ### 6. Close the feedback loop Learning, not shipping, is the hard part now. Production signals should feed back into requirements and strategy, not disappear into dashboards nobody uses. If teams generate more software without improving how they learn from real usage, they have built a faster waterfall. ## Three failure modes to avoid The first failure mode is letting every layer generate its own version of the truth. Once product, design, and engineering each ask different tools to elaborate the same problem independently, divergence becomes almost guaranteed. The second failure mode is treating prompts as the operating model. Prompts are useful, but they aren't durable artifacts, and they do not replace shared specifications, stable interfaces, or version-controlled intent. The third failure mode is measuring output speed without measuring downstream rework. A team that ships twice as many lines of code while also doubling integration churn has moved the cost somewhere less visible rather than moving faster. ## Why this is hard This is organizational change. Engineers have legitimate opinions about craft, control, and code quality. Designers have valid concerns about reducing their work to machine-ready instructions. Product managers are often asked to be more precise without getting more time or better frameworks to do it. Vendors are pushing broader AI surfaces into tools that were never designed to act as system-level coordinators. That makes this work messy. It touches process, identity, incentives, and habits. It asks teams to become more explicit at exactly the moment when the tooling makes it easy to fake clarity. That is why the right move is to start with one team, one product path, and one end-to-end flow rather than redesigning everything at once. Prove that better boundaries, better artifacts, and better measurements reduce rework. Then expand from evidence instead of enthusiasm. ## How to implement this without reorganizing everything Start small and make the experiment real. Choose one product path that runs from requirement to production, ideally a feature with clear customer value and manageable cross-functional scope. Don't start with the most politically charged or technically exotic initiative in the portfolio. Pick something representative enough to matter and contained enough to learn from. Define canonical tools and artifacts at each layer. Decide what is authoritative for requirements, what is authoritative for design, what governs implementation, and what validates release. Write those decisions down. Ambiguity here is the seed of drift later. Create a minimal Context Spine template and store it with the work. Don't make it heavyweight. Keep it short enough that a PM, designer, and engineer can review it together and notice what is missing. Add review checkpoints at transitions, not everywhere. Review the handoff from requirement to design, design to implementation, and implementation to release. Let the pipeline do the repetitive gatekeeping. Reserve human attention for moments where meaning can be lost. Measure one thing for the first four to six weeks: Spec-to-Code Alignment. Watch how often generated output requires structural correction. That single signal will tell you far more about your actual maturity than vanity metrics about suggestion counts or tokens consumed. Only expand after you have evidence. If the pilot reduces rework, improves clarity, and makes review easier, then scale the pattern. If it doesn't, fix the handoffs before you buy more AI. AI will generate bad code occasionally, the way engineers always have. The long-term risk is that teams accumulate large volumes of code that nobody fully understands, tied to intent that was never captured clearly enough to survive time, scale, and turnover. That is a problem of architecture, discipline, and operating model, and a better IDE will not solve it. --- ## Eleven Years, One Week, and an AI Co-Pilot: Rebuilding TravelTimes for iOS 26.4 - **Published:** 2026-04-12 - **Tags:** claude-code, ai-coding, side-projects, software-engineering, spec-driven-development - **URL:** https://vinny.dev/blog/2026-04-12-one-week-with-ai-copilot/ A decade-old side project became a laboratory for what AI-assisted development looks like on a real codebase with real constraints. --- About 11 and a half years ago, I opened Xcode and created a new project called TravelTimes. It was October 2014. Swift was three months old. I wanted a simple app that showed real-time Wisconsin DOT travel route data for my commute, and I wanted to learn this new language Apple had just dropped on the world. The first commit message was "Initial project creation." Twenty-two days later, I submitted it to the App Store. That app has been in continuous maintenance ever since. It survived the Swift 1.2 migration, the Swift 2.2 rewrite, the Swift 3 rename-everything apocalypse, and every major iOS release from 8 through 26. It picked up CocoaPods, then dropped them. It added Crashlytics, then Fabric, then buddybuild, then removed all of them. It has been my quiet companion through a decade of platform evolution. It is the kind of side project that teaches you things your day job never will, precisely because nobody is watching and the stakes are low enough to experiment. In April 2026, I rebuilt most of it in a week. Not because I mass-generated throwaway code, but because I had a collaborator that could keep up with the pace of my thinking. ## The spec that started the sprint I have [written before](https://vinny.dev/blog/2025-11-15-journey-with-trusting-genai-and-coding-workflow/) about the shift from vibe coding to spec-driven development: the idea that the highest-leverage thing you can do with an AI coding tool is give it clear constraints, defined interfaces, and unambiguous acceptance criteria before asking it to generate a line of code. On April 6, I wrote a feature spec for TravelTimes v9. It was not long (a page and a half), but it was specific. Here is the kind of thing it contained: > **iCloud Favorites Sync.** Migrate from UserDefaults to NSUbiquitousKeyValueStore. Create a FavoritesStore protocol so persistence can be faked in tests. Write to both local and cloud. Fall back to local when iCloud is unavailable. Handle one-time migration from local-only storage. Do not overwrite remote data with an empty local store on fresh install. Target: 8+ unit tests covering migration, fallback, and the empty-store edge case. Every feature had a block like that. Integration points with the existing `DataManager` and `AppDelegate` were called out explicitly. Error handling expectations were stated, not implied. Test coverage targets were numbers, not vibes. That spec became the contract between me and the AI for the entire week. Every session started with it. Every implementation was measured against it. The spec was not overhead. It was the force multiplier. ## Six features in six days Here is what landed between April 6 and April 12. iCloud Favorites Sync touches everything. The favorites store, the detail view's toggle, the settings screen, the Watch app: all of them read from the same source of truth, and I was about to move that source of truth to the cloud. Migrated from `UserDefaults` to `NSUbiquitousKeyValueStore` with a protocol abstraction so the persistence layer could be faked in tests. The system writes to both local and cloud, falls back gracefully when iCloud is unavailable, and handles the one-time migration from local-only storage. For conflict resolution, I went with last-write-wins keyed on the full favorites array. Simple, and the right trade-off for an app where favorites change infrequently and the data is cheap to rebuild. Eight unit tests cover the edge cases, including the critical "don't overwrite remote data with an empty local store" scenario, the one that would silently erase a user's favorites on a fresh install and make you wonder why your bug report says "all my routes are gone." Active Incidents is where the AI saved me the most time and also got something meaningfully wrong. The WisDOT feed publishes roadwork and closure events, but matching them to the app's routes turned out to be harder than parsing JSON. The feed uses "WI-33" while route labels say "WIS 33." It uses "US-45" while labels say "US 45." A compound highway like "I-41/US 45" needs to be split and each segment normalized independently. Claude Code's first attempt at the roadway matcher handled the basic cases but missed the compound splitting entirely. It normalized the full string "I-41/US 45" as a single token, which matched nothing. Zero incidents displayed on I-41. I caught it during manual QA against the live WisDOT feed, described the compound pattern, and the second pass nailed it. The matcher grew to handle three dialect variants, 12 unit tests pin down the normalization logic, and now the Route Details screen shows collapsible incident groups sorted by severity. That is the feature that makes the app genuinely useful during Wisconsin's endless construction season. Live Activities taught me that `ActivityKit` documentation and `ActivityKit` reality are two different things. The widget extension needs its own target. The `NSSupportsLiveActivities` key has to be in the *main* app's Info.plist, not the extension's. The extension's version and build number must match the host app exactly, or App Store Connect rejects the binary silently. No error, just silence. I burned a commit just surfacing the real `ActivityKit` error in a toast instead of a misleading "widget not installed" message, a debugging affordance that paid for itself immediately. The live activity shows route status on the lock screen, auto-expires after an hour to prevent stale data, and supports deep linking back into the app. Updates are pushed at 60-second intervals from the app process while it is in the foreground; there are no background push updates via APNs because the WisDOT feed does not support webhooks, and polling from a server I do not run was not worth the complexity for a side project. Share Sheet was the small feature that forced the best refactoring. Extracting the relative-time formatting logic into a reusable `RelativeTimeFormatter` and building a `ShareTextBuilder` as a pure, testable struct resulted in eight unit tests. The kind of feature where the tests took longer to write than the implementation, and the codebase is better for it. Route Details Redesign. The detail screen used to be a vertical stack of labels. It communicated data but not meaning. You had to read it to understand it. Replaced it with a horizontal three-column stats card, where each incident category renders as a tinted card row with a severity icon, count badge, and disclosure chevron. The stats card surface uses Liquid Glass, Apple's new material-based UI language in iOS 26: translucent, depth-aware, and layered in a way that establishes hierarchy without adding visual noise. The delay icon tint updates dynamically based on severity. Small details, but they transformed the screen from something you read into something that tells you at a glance whether your commute is going to be fine or terrible. Apple Watch Companion has a personal history. The original TravelTimes had Watch support in March 2015, back when WatchKit was brand new and Swift was at version 1.2. I removed it years ago when watchOS moved to native apps. Bringing it back felt like closing a loop. It is a SwiftUI app running on watchOS 26 that shows favorited routes synced from the iPhone via `WCSession.updateApplicationContext`. When the `session(_:didReceiveApplicationContext:)` delegate fires on the Watch side, the complication reloads its timeline via `WidgetCenter.shared.reloadAllTimelines()`. The watch app can also send a "refresh" message to the phone, the phone refetches from WisDOT, and the fresh data flows back through the session. One-directional data flow, event-driven updates, no polling, no battery waste. Testing this required a real device pair. The Simulator does not surface the `WCSession` timing issues that matter, like what happens when the phone delivers a context update while the Watch app is backgrounded. On hardware, I confirmed the data arrives on next foreground with no user intervention. ## The bugs that teach you things The feature work was only half the story. The other half was the parade of integration bugs that no amount of unit testing catches until you run the real thing. The WisDOT feed omits `plannedEndDate` for indefinite incidents. My decoder required it, so a *single* missing field caused the *entire* event array to fail decoding. Every event disappeared. The fix was making the field optional and adding a regression test, but the real lesson was about defensive JSON decoding in a world where you do not control the API schema. This is a place where the AI's instinct was wrong. It generated a strict `Codable` model with no optionals, which is the textbook approach but the wrong one for a government feed with inconsistent data contracts. The incident group header card intercepted touch events before they reached the expand/collapse button because the tinted background view was a subview of the button and `isUserInteractionEnabled` defaulted to true. The card looked right but did nothing when you tapped it. One line fix: `card.isUserInteractionEnabled = false`. App Store Connect hung in "Processing" for hours because the Watch widget extension had an export artifact from a local archive build embedded in the bundle. Validation passed. Upload succeeded. It just never finished processing. Finding that one required inspecting the built product with `find` and noticing a file that should not have been there. These are the kinds of bugs that take 15 minutes each once you know what to look for, but could eat an afternoon if you are encountering them for the first time. ## What AI-assisted development looked like I have been using AI coding tools on this project since mid-2025. The commit history reads like a timeline of the space: Codex for early refactoring, Cursor for performance analysis, Devin for specific fixes, Kiro for documentation, and Claude Code for the sustained feature work that made up the v9 sprint. A few things made the April sprint work, and a few things did not. What worked: context management. Each day I started a new Claude Code session, fed it the feature spec and pointed it at the relevant source files. The spec was the continuity mechanism, not the AI's memory. When I described the iCloud sync requirement, the implementation accounted for the existing `DataManager` notification pattern, the `DetailViewController` favorite-toggle flow, and the `AppDelegate` launch sequence, because the spec described those integration points and the model could read the existing code. When the Live Activity toast showed the wrong error, the fix came with an understanding of the full error propagation chain from `ActivityKit` through the manager to the view controller. What worked: speed on the well-specified path. The iCloud sync feature (protocol abstraction, dual-write strategy, migration path, eight tests) would have taken me a full weekend to build alone. Not because I did not know how; I have been writing `NSUbiquitousKeyValueStore` code since iCloud launched. The friction is in the typing, the test setup boilerplate, the context-switching between implementation and verification. With the spec and an AI collaborator, it landed in an evening session. That compression happened on every feature, and it compounded across the week. What did not work: trusting the first pass on unfamiliar data. The WisDOT feed normalization and the `Codable` strictness issues both came from the same root cause: the AI generated plausible code that matched the *documented* behavior of the API, not the *actual* behavior. I caught both in testing. This is the pattern I see over and over: AI-generated code is correct against the spec but brittle against the real world. The human's job is to be the one who knows the real world is messier than the spec. My review process: I read every line of generated code before committing. Not skimming. Reading. Every file, every test, every edge case handler. When something looked structurally wrong, I described the problem and asked for a revision rather than hand-editing. When something was a one-line fix, I just fixed it. The goal was to understand the entire codebase as if I had written it myself, because I was the one who would be debugging it at midnight when the WisDOT feed schema changed again. Here is the thing I keep coming back to: AI-assisted development is not about generating code faster. It is about compressing the feedback loop between *intent* and *working software*. The features I built in six days were features I already knew how to build. I have been writing UIKit for over a decade. I know how `WCSession` works. I know how `ActivityKit` fails. The AI did not teach me those things. My 30 years of shipping software did. What the AI did was eliminate the friction between knowing what I wanted and having it exist. ## Eleven years in the rearview The TravelTimes repo has 179 commits from October 2014 to today. Sixty Swift files. North of 20,000 lines of code. The app went from Storyboards to fully programmatic UIKit. From `NSURLConnection` to `URLSession` with retry logic and request deduplication. From a flat table view to an adaptive split-view layout with sidebar navigation, design tokens, and Liquid Glass. The contributor list includes me, buddybuild's SDK bot, GitHub Copilot, OpenAI's Codex, Cursor Agent, Devin AI, Kiro, and Claude Code. That is a strange sentence to write. It is also an honest representation of how software gets built in 2026. I think about what 2014-me would make of this codebase. He wrote the whole thing in 22 days using a language he was learning as he went. He would not recognize the architecture: the design tokens, the split-view layout, the Watch connectivity, the live activity lifecycle. But he would recognize the impulse. It is still the same app: a table view that shows how long it takes to drive home. The engineering grew up around a simple idea, layer by layer, year by year, and this last week added more layers than any week before it. ## The side project as laboratory Side projects have always been where I learn things first. TravelTimes taught me Swift before I used it professionally. It taught me Auto Layout when that was still painful. It taught me WatchKit, Today Extensions, and notification scheduling before any of those mattered at work. Now it is teaching me how AI-assisted development works at the feature level. Not on greenfield demos or toy apps, but on a real codebase with real history, real App Store constraints, and real users who will notice if the incident data disappears because the JSON decoder choked on a missing field. The laboratory has to be real, or the lessons do not transfer. If you have worked through the context-management problem in Claude Code, built against government APIs with inconsistent data contracts, or developed your own trust-but-verify process for generated code, I want to hear what you learned. Find me on [LinkedIn](https://www.linkedin.com/in/vinnycarpenter) or check out TravelTimes's [landing page](https://traveltimesapp.com/). --- ## The Dark Factory Model for AI-Driven Software Development - **Published:** 2026-04-05 - **Tags:** genai, agentic-sdlc, software-engineering, engineering-leadership, ai-coding - **URL:** https://vinny.dev/blog/2026-04-05-dark-factory-model-for-ai-software-development/ Most engineers still treat AI-generated code like work from a junior developer they do not fully trust. They read every line. They second-guess every pattern. They turn a productivity tool into a bottleneck. That is the wrong mental model. Simon Willison at [simonwillison.net](https://simonwillison.net) provides a better framework: the dark factory. Simon also made an observation that landed with particular force. In his work on Agentic Engineering, he wrote that AI tools amplify existing expertise. The more experience you have as a software engineer, the faster and better your results with coding agents. I have been writing software for more than 30 years. That reframed everything. ## What a dark factory is A dark factory, also called a lights-out factory, is a manufacturing facility that runs without humans on the floor. No workers. No lights needed. Robots operate from precise engineering blueprints, tight tolerances, and automated quality gates. Humans designed the system. The system builds the product. Real dark factories took decades and serious capital investment to get right. Engineers designed every constraint and mapped every failure mode. They built statistical process controls into each step, not just the final inspection. The destination looks clean. The build cost is real. The same is true here. The model I am describing is not a shortcut. It is a discipline. ## Experience is the raw material Simon is right. But the phrase "amplify existing expertise" deserves more precision. Vague inspiration does not help anyone act differently. What 30 years of experience gives you is a library of failure modes. I know which patterns look elegant but collapse under production load. I know where security assumptions get made silently and incorrectly. I understand idempotency guarantees across every layer of a distributed system. I can define that requirement so precisely that the AI has no room for misinterpretation. That specificity makes the model work. The AI does not guess what I mean. The interpretation gap closes because the input is precise. That precision draws on decades of accumulated judgment. This raises a fair question for engineering leaders: Does every engineer on your team need 30 years to participate? No. But they need enough. Enough pattern literacy to write a spec that constrains the AI. Enough honesty to recognize their own blind spots. ## The spec is the factory floor Before a line of code gets generated on my teams, we write. We produce specs, architecture decisions, expected patterns, and testing requirements. We establish a clear definition of done. The plan is not overhead. It is the factory floor. Two things matter here that manufacturing engineers would recognize immediately. First, the spec must stay within the system's capability envelope. Identifying the boundaries of that envelope is a core leadership responsibility. If you ask the AI to solve a problem that is genuinely novel or architecturally ambiguous, defect rates spike. Know what the system executes reliably and design your specs accordingly. Second, process control does not live only at the end. It runs through every checkpoint. This includes linting, type checking, unit tests, integration tests, and security scanning. The pipeline is the equivalent of statistical process control embedded at every step. Final testing confirms. The pipeline validates continuously. ## What you still review, and why I do not do line-by-line code review as my primary quality mechanism. That is a different statement from "I never look at the code." There are surfaces I always examine regardless of test results. These include security boundaries, authentication and authorization flows, data models, and API contracts. These are the places where an LLM can produce code that passes every test while being wrong in a way you did not think to test for. LLMs are stochastic, not deterministic. The same spec can produce different outputs across runs. A robot welder does not do that. That non-determinism is manageable, but it requires a testing strategy that goes beyond happy-path coverage. Adversarial testing and edge case enumeration are required layers. Simon's red/green TDD pattern is worth adopting explicitly. Write the tests before generation starts. Confirm they fail as expected. Then let the agent implement to green. This makes acceptance criteria structural rather than aspirational. ## The retooling problem Dark factories retool slowly. Reconfiguring a physical production line is expensive. Software requirements change fast, often mid-sprint. When the spec changes significantly, the factory does not adapt automatically. The guardrails and test suites may no longer fit the new requirements. Restarting generation without updating the spec is where the model breaks down most predictably. Treat the spec as a living document. Apply the same rigor you would to production code. Version it. Review it. When the spec drifts, the factory output fails. ## Who responds when the factory jams Dark factories have humans on call. Sensors surface anomalies. Exceptions route to people who can diagnose and intervene. The lights are off, but the dashboards are on. Your equivalent is observability and clear ownership of the pipeline. Someone must be accountable when a generated component fails in a way the tests did not catch. Name that person before the factory runs. Do not wait until it breaks. Guardrails also degrade over time. Standards erode as teams turn over. Build an audit loop into your process. Periodically review whether generated code still conforms to the architecture. The factory needs maintenance even when it runs well. ## The shift is real AI coding tools are not fancy autocomplete. They are a production system that requires design, constraints, and continuous monitoring. If you have the experience, this moment is an extraordinary amplifier. Your decades of pattern knowledge and failure memory flow directly into the guardrails that make the factory run. But the amplification multiplies what is already there. You must have something worth amplifying. Write the spec. Define the guardrails. Test the edges. Audit the drift. Stay upstream. The factory runs. You just have to build it right. --- *Hat tip to Simon Willison for the dark factory framing and the Agentic Engineering work. Read him at [simonwillison.net](https://simonwillison.net).* --- ## Open Weights, Real Stakes: Running Gemma 4 31B Locally - **Published:** 2026-04-04 - **Tags:** genai, open-source, engineering-leadership - **URL:** https://vinny.dev/blog/2026-04-04-gemma4-open-weights-blog/ Google dropped Gemma 4 yesterday. I had it running locally by last night. Here's what it looks like to pull a frontier-class open model onto your own hardware and why the local versus cloud question is getting more interesting, not simpler. If you're an engineer or architect trying to decide whether open-weight models belong in production or just in a lab, this is the practical view: what the license changes, what the hardware demands, where the model is good enough, and where cloud still wins. - Gemma 4 is the first Google open-weight release that feels materially different for enterprise and production conversations because Apache 2.0 removes the licensing ambiguity that held earlier Gemma releases back. - The 31B dense model is legitimately capable on local hardware, but the hardware reality still matters: quantization choice, memory headroom, and latency tradeoffs determine whether this is usable or merely impressive. - Cloud models still hold the frontier on raw reasoning quality and freshness, especially for tasks that depend on recent APIs, libraries, or events. - The most interesting architecture is not local or cloud. It's hybrid inference, where the orchestration layer routes each task based on sensitivity, complexity, and cost. ## What "open weights" means (and why Apache 2.0 is the real news) Proprietary models like Claude, GPT-4o, and Gemini Pro work like a service. You send a prompt, their servers do the work, you get a response. You never see the model. You pay per token. The provider sets the terms. Open weights flips that. The trained model parameters get published for anyone to download, run, and modify. Think of it as getting the recipe, not just the jar. It's worth being precise here: "open weights" is not the same as "open source." Open source would include training data, full reproducibility, and the complete training stack. Open weights is narrower: you get the trained model file. That's still an enormous amount of power. What makes Gemma 4 specifically notable is the license. Google shipped it under Apache 2.0, the most permissive commercial license in standard use. Previous Gemma models used Google's own Gemma license, which reserved the right to terminate access and restricted certain commercial deployments. Apache 2.0 removes both of those constraints entirely. You can modify it, fine-tune it, deploy it on-premises, embed it in a product, and Google cannot pull that access back. For enterprise use cases with data residency requirements, legal holds, or vendor dependency concerns, that distinction is not academic. It changes whether this is just interesting technology or something you can realistically build around. ## The four models: know what you're running Before pulling anything, know what you're getting into. Gemma 4 ships in four sizes: - E2B / E4B ("Effective" models): Built for smartphones and edge devices. The E2B runs in under 1.5GB of memory and supports native audio input. These are also the foundation for Gemini Nano 4 on Android. - 26B MoE (Mixture of Experts): 26 billion total parameters, but only 3.8 billion activate during any given inference pass. This makes it significantly faster and lighter on VRAM than a dense model of comparable size. The tradeoff is reasoning depth on long, chained tasks. MoE architectures excel at breadth, routing, retrieval, and classification-style work. They're less suited to sustained multi-step reasoning chains that require holding a lot of state. For most local use cases, this is the more practical option. - 31B Dense: Maximum raw quality. Ranks third on the Arena AI open model leaderboard among open models. This is what I've been running for all of the tests below. Hardware reality check before you pull the 31B: The Q8_0 quantized version requires approximately 35GB of VRAM to run. Q8_0 is worth choosing when you have the headroom. It is nearly indistinguishable from full bfloat16 precision, preserving essentially all the model's capability while reducing the file size. If your setup can't support 35GB, the 26B MoE at Q4_K_M is a better fit and still impressive. Both models ship with a 256K token context window. ## Local vs. cloud: the tradeoffs I run both frontier cloud models and local models for personal AI agents, mostly to learn and push local inference to its limits. These are genuinely different tools with different strengths. ### Where cloud models are still the right answer The best cloud models operate above what any locally runnable model can currently match on raw reasoning quality at the frontier. Anthropic isn't shipping Claude 3.7 to your laptop. Google isn't giving you Gemini Ultra to run in your garage. The capability gap at the absolute top is real. Cloud also wins on operational simplicity: no hardware to manage, no inference server to operate, continuous model updates, and clean API integration. For most teams building production AI features without data constraints, the cloud is still the right default. ### Where local changes the math Regulated and sensitive data. This is the most underappreciated argument for local inference. If your application touches PHI, PII, MNPI, attorney-client communications, or any data under a legal hold, every cloud API call is a compliance conversation. A local model eliminates that problem by design. No prompt ever leaves your network. Latency at the edge. Agentic workflows chain many model calls together. Cloud round-trip latency compounds across a long chain. Local inference removes the network hop entirely. For embedded, on-device, or real-time applications, this is often the only viable path. Cost at volume. Per-token API pricing is easy to underestimate at scale. Running your own inference converts a variable operational cost into a capital cost on hardware. Rough math: a workstation-class GPU setup capable of running Gemma 4 31B costs somewhere in the $3,000 to $8,000 range depending on configuration. At moderate inference volume, the API equivalent can exceed that in months. Fine-tuning and customization. Apache 2.0 means you can take these weights and train on your own domain-specific data. That capability is enormously valuable for enterprise use cases where the general model needs to learn your terminology, your workflows, or your internal knowledge. You own the resulting model outright. Learning the system. Running your own model forces you to engage with how these systems work: quantization levels, context window management, inference parameters, and prompt engineering that accounts for local model behavior. The feedback loop for understanding is dramatically tighter than routing everything through an API. ## Running Gemma 4 31B (Q8_0): what I found I ran this on a Mac Mini M4 Pro with 48GB of unified memory using Ollama. Here's what I tested and where I landed. ### Vision: seeing what's there Gemma 4's multimodal capabilities are native across all model sizes, not bolted on. I fed it real images to find out how well they work in practice. First test: a photo of a classic red Ferrari alongside a person. The model identified the specific model family, the "cheese grater" side strakes as a signature design element of that era, the paint color by its proper name, and described the person's attire in detail. No prompting tricks. Just the image and a simple question. ![Vision demo: Ferrari image analysis](/images/blog/2026/04/Ferrari-image-analysis.png) *The model identified the Testarossa body style, era, and design details from a single photo. Thought for 34.1 seconds before responding.* Second test: a professional headshot. I used a real photo from a recent headshot session to keep the test grounded. The model analyzed subject expression, clothing details including the specific tie pattern, lighting, and composition quality, all accurately. ![Vision demo: Professional headshot analysis](/images/blog/2026/04/Professional-headshot-analysis.png) *Accurate detail extraction from a standard portrait: attire, expression, composition, and lighting conditions.* What's interesting here is the thinking time. Both vision prompts showed 30 to 50 seconds of deliberation before output. You can expand that thinking chain and see it reasoning through observations before synthesizing them. ![Expanded thinking chain for headshot analysis](/images/blog/2026/04/extended-thinking-headshot-analysis.png) *The expanded thinking block shows the model cataloging observations before drafting its response. Image analysis broken into discrete reasoning steps.* ### Reasoning chain: where it gets interesting This is the capability I care about most for engineering work. Configurable extended thinking mode lets the model reason step by step before committing to an answer. More importantly, it exposes the kind of intermediate correction and reframing that matters when you're evaluating whether a model can be trusted inside a workflow. I gave it a realistic cloud migration scenario: 400 workloads, 18-month timeline, 200 engineers with only 30 having significant cloud experience, a hard PCI-DSS compliance deadline at month 12, and a 30% cost reduction target by month 18. The thinking block tells the real story. The model identified four separate challenges, began structuring a sequencing strategy, and then stopped mid-reasoning to question its own approach. The exact moment: *"Wait, let's refine the Sequencing Strategy."* It revised the wave structure before producing the final answer. ![Raw thinking block: cloud migration reasoning](/images/blog/2026/04/cloud-migration-reasoning.png) *The model caught its own sequencing flaw mid-thought and corrected it before responding. That's the reasoning chain doing its job.* The final output landed on a "Hybrid Phased Wave Strategy" with four distinct migration waves, sequenced to address the skill gap constraint first, compliance deadline second, and cost optimization third. It named the traps (lift and shift fails the cost goal; full refactor fails the timeline and skill gap), then built around them. ![Final output: Hybrid Phased Wave Strategy](/images/blog/2026/04/Hybrid-Phased-Wave-Strategy.png) *78 seconds of local inference, no network call, no token bill. The output structured a four-wave migration plan around the constraints in the prompt.* Instruction following is sharper than I expected. Instruction adherence has historically been the weakest point of local models below the frontier. Gemma 4 31B holds complex instructions well across long contexts and follows structured output formats consistently. Native function calling support is a genuine upgrade over earlier Gemma generations that required prompt engineering workarounds. Code generation is competitive on mid-complexity tasks. I ran real engineering problems at it: refactoring patterns, code explanation, generating boilerplate with specific constraints. For problems that don't require deep contextual reasoning across a large codebase, the output quality was solid enough to use as a first pass. The knowledge cutoff is a real operational constraint. Training data ends at January 2025. That is 15 months of missing context as of this writing. For anything involving recent frameworks, recent events, or current API versions, you will hit that wall. This isn't a footnote limitation. It's a meaningful filter on which use cases make sense. The 256K context window holds up. I fed a large document corpus into a single prompt. It processed cleanly without degradation. Context length has historically been the Achilles' heel of local models. That gap is closing. Where it still struggles: Multi-step reasoning chains requiring sustained state, nuanced creative tasks, and anything requiring knowledge from the last year and a half. For those, I still route to Claude via the cloud. Gemma 4 also ships with configurable thinking modes across all model sizes. You can dial reasoning depth up or down depending on task complexity, which is a practical tool for managing latency on a local setup. ## The architecture worth building: hybrid inference Here is the pattern I keep coming back to, and the one I think is most interesting for engineering teams right now. Not every task in an agentic workflow needs the same model. A pipeline that summarizes internal documents, routes them to the right team, and drafts a response has at least three distinct inference steps with very different requirements. The summarization step might involve sensitive data that cannot leave your network. The routing step is simple classification. The drafting step might benefit from the best reasoning model available. A hybrid inference architecture picks the right tool for each step: local model for the data-sensitive or high-volume steps, cloud model for the steps that need maximum capability and have no data constraints. The orchestration layer, not the model itself, decides where each call goes. This is roughly what that routing seam looks like in practice: ```ts // Task metadata is the contract between agents and the routing layer. type Task = { kind: 'summarize' | 'classify' | 'draft' | 'code'; sensitivity: 'public' | 'internal' | 'regulated'; complexity: 'low' | 'medium' | 'high'; tokens: number; payload: unknown; }; enum TargetModel { LocalGemma4 = 'gemma4-31b-local', CloudFrontier = 'cloud-frontier-model' } function route(task: Task): TargetModel { const isSensitive = task.sensitivity === 'regulated' || task.sensitivity === 'internal'; const isHighVolume = task.tokens > 64_000; if (isSensitive || isHighVolume) { return TargetModel.LocalGemma4; } const needsFrontierReasoning = task.kind === 'draft' && task.complexity === 'high'; if (needsFrontierReasoning) { return TargetModel.CloudFrontier; } return TargetModel.LocalGemma4; } async function handleTask(task: Task) { const target = route(task); if (target === TargetModel.LocalGemma4) { return callLocalGemma4(task); } return callCloudFrontier(task); } ``` In practice, that's the right mental model. Agents should describe intent. The policy layer should decide where inference runs based on sensitivity, complexity, latency, and cost. This isn't theoretical. It's the natural evolution of what teams are already building with retrieval-augmented generation and multi-model pipelines. Open weights models like Gemma 4 31B make the local leg of that architecture genuinely viable for the first time. ## So: learning tool or production asset? The gap argument keeps shifting shape. A year ago, local models were clearly better for tinkering than for production. Today, Gemma 4 31B ranks third among open models on standard benchmarks, runs on hardware many engineers already own or can buy with a single capital request, and ships under a license that lets you deploy it anywhere without asking permission. For privacy-constrained data, high-volume inference, edge devices, and domain-specific fine-tuning use cases, this is a production asset right now. For tasks requiring frontier reasoning quality with no data constraints, cloud is still the right answer, and the ceiling there keeps rising. The most interesting question is not which one wins. It's how you design the seam between them. That's where the real architecture work is now. What are you building with open models? Have you pushed one into production, or is local inference still sitting in the experimentation column for you? I'm particularly curious whether anyone is running a hybrid architecture in a real environment and what the orchestration, observability, and policy layer look like. I want to know what's working. --- --- ## From Copy-Paste to Skill: What Thousands of AI Coding Sessions Taught Me About Guardrails - **Published:** 2026-03-28 - **Tags:** claude-code, genai, software-engineering, learning, engineering-leadership - **URL:** https://vinny.dev/blog/2026-03-28-coding-standards-skill/ About a year ago, I had a text file. Maybe 40 lines. Pasted into Claude Code at the start of every session. "Don't forget to run the tests." "Use conventional commits." "Please don't rewrite my entire codebase when I ask you to fix a typo." The kind of guardrails you write after your AI assistant confidently ships code that breaks in ways you didn't anticipate. That file became a markdown doc. The doc became a system. And now, after thousands of sessions across Claude Code, Codex, Kiro, and every LLM-based CLI and IDE I could get my hands on, it's a full Claude Code Skill (version 10.0) that I'm sharing publicly. The real story isn't the version number. It's what those sessions taught me about how to make these tools trustworthy, not just fast. ## The problem isn't the model Here's the thing nobody says clearly: the AI tools aren't the problem. I've used Claude Code, Codex, and Kiro extensively. I've run the Copilot integrations, the IDE plugins, the agentic workflows. Each has real strengths. Each has the same failure mode. They're fast. Impressively, dangerously fast. And without direction, that speed works against you. The tools are not interchangeable, and I want to be precise about that. Claude Code has persistent memory via `CLAUDE.md`, which means corrections compound over time. Kiro has spec-driven agents baked into its core workflow. Copilot lives in the editor and has no shared project context by default. The mechanics differ. But the failure mode is identical across all of them: they'll produce code that works technically and misses the point entirely. Early on, I'd start a session, ask for something, and get back code that worked. Technically. It wouldn't match the patterns in my codebase. It wouldn't have tests. It would reach for an unfamiliar library when the standard library had a perfectly good solution. It would "finish" without committing, and when the context window ran out, the work evaporated. The problem wasn't the model. The problem was me. I hadn't told it how we do things. ## What "fast and wrong" costs Before I get to the solution, let me be direct about the tradeoffs, because I don't want to oversell this. Adding guardrails has a cost. The skill adds context overhead to every session. More tokens, slightly longer startup. The PostToolUse hooks add a formatting step on every file write. If you're on a tight token budget or optimizing for raw session startup time, you'll feel it. What you get in return is harder to measure precisely, but real. Across more than a dozen projects and multiple teams over the past year, the outcomes were consistent: fewer review cycles because the code matched our patterns on the first pass, faster onboarding because new engineers got the same guardrails automatically, and (the one I didn't fully anticipate) PR reviewers started trusting AI-assisted contributions in a way they hadn't before. That last one matters more than the speed. Speed is table stakes. Trust is what changes how your team works. ## Version 1: any constraints beat no constraints The first version was embarrassingly simple. Six rules, pasted in at the start of every session: 1. Read the codebase before writing code. 2. Write tests. 3. Use conventional commits. 4. Don't modify files outside the task scope. 5. Commit frequently. 6. Run the test suite after every change. Even this was a big improvement. Not because the rules were sophisticated, but because any constraints beat no constraints when you're working with an LLM. The model wants to help. If you don't define what "helpful" means, it'll define it for you, and you won't always like the definition. ## Version 2: corrections are the raw material Every time I didn't like what I got, I added a rule. Every correction became a line item. Claude used a TypeScript enum? "Prefer literal unions over enums." Claude wrote a 200-line function? "Functions should be 30 lines or fewer." Claude swallowed an exception silently? "Never swallow exceptions. Use typed errors." My wife asked me one night why I was furiously typing at 11pm. I told her I was writing rules for an AI that keeps making the same mistakes. She gave me the look. You know the one. But this was the breakthrough: corrections are the highest-signal input you have. Every mistake Claude made that I caught was a rule waiting to be written. Don't just fix it. Capture it. The document grew from 40 lines to 200, then 400. I organized it into sections: agentic behavior, code quality, testing, security, git workflow. I added a "Definition of Done" checklist because Claude kept telling me things were "done" when they clearly weren't. I added a "Red Flags" section to pattern-match on recurring mistakes. Here's a concrete example of what that looked like in practice. Before guardrails, asking Claude to add error handling to an async function would often produce something like this: ```typescript try { const result = await fetchData(); return result; } catch (e) { console.log(e); } ``` Silent failure, untyped catch, no re-throw. With the rule "never swallow exceptions, use typed errors, always re-throw or return a typed Result" in place, the same request produced: ```typescript try { const result = await fetchData(); return { ok: true, data: result }; } catch (err) { if (err instanceof NetworkError) return { ok: false, error: err }; throw err; } ``` Same prompt. Different standards document. Completely different output. ## Version 7: learning from the community By early 2026, Boris Cherny (the creator of Claude Code) started publishing his workflow tips on Twitter. I want to be precise here about what I already had and what I learned, because the distinction matters. I had spec-driven development, subagent delegation, the re-planning trigger, and the correction-to-rule pipeline. Those came from my own sessions. What Boris surfaced that I hadn't considered: give Claude a domain-specific verification strategy before you start coding, not just a checklist at the end. Define how you'll prove correctness upfront, and output quality improves substantially. I was reviewing at the end. Boris built verification into the beginning. He also showed me that PostToolUse hooks could auto-format on every file write, and PostCompact hooks could re-inject critical context when Claude compressed the conversation. Here's what a PostToolUse hook looks like in practice: ```json { "hooks": { "PostToolUse": [ { "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "npx biome format --write $FILE" }] } ] } } ``` Every file write triggers the formatter. No discipline required. Standards enforced by automation beat standards enforced by willpower, every time. The `CLAUDE.md` pattern was the one I most wished I'd arrived at myself: update it directly after every correction, and let Claude write its own rules. The `@.claude` pattern in PR reviews is particularly powerful. Tag Claude in a review comment, and the feedback automatically becomes a permanent rule in `CLAUDE.md`. The compound effect over time is significant. One note on portability: the principles here aren't Claude Code-specific. Anywhere you can inject a system prompt, you can apply this approach. The Skill format is Claude Code-native, but the underlying logic works in any tool that accepts context at session start. ## Version 10: from document to skill By this point the document was solid across dozens of projects. The distribution was still manual, and that was the problem. Sometimes I'd forget to reference it. New engineers would start sessions without it. The fix was making it a Claude Code Skill: a markdown file with YAML frontmatter that Claude Code loads automatically when the task matches the description. Once installed, you don't invoke it. It governs every session without being prompted. The package is simple: ``` .claude/ skills/ coding-standards/ SKILL.md # auto-loaded for all coding tasks commands/ qspec.md # /qspec: generate a feature spec on demand qcheck.md # /qcheck: run a skeptical staff engineer review ``` The two slash commands are the only pieces requiring explicit invocation. `/qspec` forces spec-writing mode before implementation starts. `/qcheck` runs a skeptical staff engineer review against the full standards. Everything else is automatic. ## What's in it Rather than walk you through every section like a README, here are the parts that changed how I work. Agentic behavior comes first: how Claude should orient on a codebase before touching anything, when to write a spec versus implement directly, how to handle ambiguity, and when to stop and re-plan. It also defines a two-layer memory system. Project-specific lessons live in `tasks/lessons.md`. Persistent rules live in `CLAUDE.md`. Every correction writes to one of these. Nothing gets lost. Verification-first development gets its own section because it's the highest-leverage practice in the document. Define how you'll prove correctness before writing code, with domain-specific strategies for backend, API, frontend, data, and infrastructure work. This single habit cuts rework more than any other rule in here. The hooks section is where the skill earns its keep. PostToolUse auto-formats on every write. PostCompact re-injects critical context after conversation compaction. Stop hooks act as verification gates before Claude declares something done. For subagents, the model selection guidance is deliberate: Haiku for read-only analysis tasks (fast, cheap, sufficient for codebase orientation), Sonnet or Opus for architecture and complex reasoning (the cost is worth it when the output matters). The logic is cost-capability tradeoff matched to task risk. The Definition of Done is a single unified checklist: Correctness and Quality, Self-Review, Documentation and Process. One checklist, not three. If it's not on the list, it's not blocking. If it is, it's not optional. ## A word on governance One question I get from other engineering leaders: who owns the skill when it drifts? The answer is the same as any shared standard: it needs an owner, a version, and a review cadence. We treat `SKILL.md` like a dependency. It lives in version control, changes go through PR review, and the team has a standing agenda item to surface corrections that should become permanent rules. The `@.claude` PR pattern helps here. Every correction that surfaces in code review is a candidate for the standards document. When the correction recurs, it becomes a rule. When the rule is widely adopted, it goes into `SKILL.md`. The pipeline closes. ## What changes on day one If you clone the repo and drop the `.claude/` directory into your project today, here's what's different by the end of your first session: Claude will read your codebase before writing anything, commit in logical increments rather than one giant blob at the end, run the test suite after each change, and tell you when it's uncertain rather than improvising. Those four behaviors alone will change the quality of the output. The trust takes longer. But it compounds. After a few weeks of sessions where the output consistently matches your patterns, you'll notice reviewers stop flagging the same classes of issues on AI-assisted PRs. That's the signal that the guardrails are working. ![Using it in Claude Code](/images/blog/2026/03/claude-code-coding-standard-skill.png) ## The GitHub repo I've published the full skill, slash commands, and README on GitHub: **[github.com/vscarpenter/coding-standards-skill](https://github.com/vscarpenter/coding-standards-skill)** Clone it, drop the `.claude/` directory into your project, and commit it. PRs welcome. This thing got better every time someone contributed a pattern, and I'd love to keep that going. --- The recursive part of this that still gets me: I'm writing rules for an AI that writes code for me, and the AI helps me refine those rules, and the rules make the AI better, which surfaces new corrections, which become new rules. It's a strange loop. It's also just engineering. Define the standard. Capture the deviation. Raise the floor. We're living in the future. Might as well bring some standards with us. --- ## Pipeline-First Is Not a DevOps Initiative - It's a Culture Shift. - **Published:** 2026-03-26 - **Tags:** platform-engineering, engineering-leadership, security, software-engineering - **URL:** https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/ The technical case is easy. The human case is where it gets real. Everyone sells pipeline-first delivery the same way. Remove direct production access. Route all changes through automation. Enforce consistency. Reduce drift. Improve auditability. None of that is wrong. Pipelines do reduce incidents. They do create audit trails. They do enforce controls that humans skip under pressure. What the slide deck leaves out is the part that determines whether this works. The gap between the kickoff meeting and the moment your last engineer gives up production access is not a tooling problem. It is a culture problem. And culture problems do not yield to Terraform. ## The person who built it Picture your most senior infrastructure engineer. They have been here for over a decade. They built half the environment they run today. When something breaks at 2 a.m., they fix it, not because they have to, but because their hands are the only ones the organization truly trusts to touch the heart of the system. You are asking them to stop being the hero. The technical argument is that manual changes cause drift. The human reality is that you are asking them to trade their "heroics" for "systemic integrity." To them, pipeline-first feels like taking away their tools and handing them a rulebook. If you want this to work, you have to help them make a shift in how they view trust. In the old world, trust was a localized, manual resource. We trusted their judgment at 2 a.m. In the pipeline-first world, we move that trust from their hands into the code they write. This isn't a demotion; it is trust-scaling. When they fix a production issue manually, they save the company once. When they codify that fix into a hardened pipeline, they save the company ten thousand times over, across every future deployment, even while they're sleeping. The shift is from: "I am the one who fixes production." (Individualized trust) "I am the architect of the system that protects production." (Scaled trust) ## The on-call hero There is a second character. They treat bypass as a feature. "The pipeline is too slow. If something is burning and I have a one-line fix, I should not have to wait twenty minutes." It sounds pragmatic. It is the most dangerous failure mode in the entire program. Because every bypass is justified in the moment. The system was down. The fix was obvious. The risk was low. And each time it happens, the team learns the rule has an exception clause. The exception clause becomes "when I decide it applies." Pipelines do not fail because engineers are malicious. They fail because urgency feels like permission. The answer is not to eliminate urgency. It is to remove the incentive to bypass. If your pipeline takes 25 minutes for a trivial change, that is not a culture problem. That is a product problem. Fix the pipeline. Then enforce the rule. ## The manager who looks the other way The third character is the one that rarely shows up in the postmortem. They are a good manager. They care about their team. An engineer bypasses the process, ships a hotfix, and the system recovers. They say thank you. They mean it. What they do not do is correct the behavior. Not because they disagree with the policy. Because they are caught between two pressures: the organizational directive to enforce discipline, and the immediate reality that their team delivered under pressure. In that moment, the result feels concrete. The policy feels abstract. But a manager's gratitude in a crisis is a "dark signal": it tells the team that the rules don't apply when things get hard. Leadership has to close that gap. Success is not: "Did the system stay up?" Success is: "Did we ship through the pipeline?" If you measure the first, you will get bypass. If you measure the second, you will get discipline. ## What leaders consistently get wrong Most organizations do not fail on intent. They fail on execution. The pattern is predictable: - They invest heavily in tooling and lightly in change management. - They announce the policy but do not align managers on enforcement. - They tolerate "temporary exceptions" that quietly become permanent. - They measure uptime instead of adherence. Every organization says they want pipeline-first. What they actually want is pipeline-first, except when it is inconvenient. That is not a constraint system. That is a suggestion. ## What the access conversation is There is a moment every leader eventually has. You sit across from someone who has had production access for years and tell them it is going away. You have the policy. You have the security rationale. You have the compliance requirement. They already know all of that. What they are trying to understand is something else: Do you understand what you are asking them to give up? Do you respect the expertise that access represents? Are they a partner in this change, or a risk to be managed? How you answer those questions determines what happens next. Engineers who feel respected become advocates. They model the behavior you need. They bring others with them. The ones who feel dismissed do the opposite. This is a people problem wearing a security costume. ## The architecture of the change If you strip away the narrative, pipeline-first is a constraint system. You are building an environment where the right path is the fastest path. That requires a few things to be true: Speed is a control. Pipelines have to be fast. Under 10 minutes for most changes. If someone can deploy faster by skipping the pipeline, they will. Audit the glass. Break-glass access has to exist, be real, and be audited. If there is no legitimate emergency path, engineers will create illegitimate ones. Observability. You must track the percentage of changes shipped via pipeline and the number of break-glass events. If nobody is watching these, nobody is running the program. ## Why the framing matters Most organizations treat this as a technical rollout and then wonder why adoption stalls. They miss that this changes the relationship between engineers and production. It changes who has authority. How trust is expressed. What it means to be a senior engineer. That is not a DevOps initiative. It is a culture shift. Culture shifts require repetition. They require visible leadership alignment. They require managers who close the loop every time, especially when it is uncomfortable. Tell your engineers this is hard. Tell them you understand what they are giving up. Tell them the outcome is worth it. And then make sure the outcome actually is. ## What you are actually building When pipeline-first works, you get more than clean audit logs. You get a team that trusts the system. You also get the substrate for [getting better at getting better](https://vinny.dev/blog/2025-12-31-getting-better-at-getting-better-in-2026/): every improvement lands in the pipeline once and compounds for everyone. Engineers understand the constraint exists to protect them as much as the environment. On-call responders diagnose before they act. A production system reflects what the code says, not what someone typed at a terminal six months ago. The pipeline is the artifact. The culture is the product. If you get the culture right, the pipeline will hold. --- ## Meet Roci: My Always-On Personal AI Agent, One Month In - **Published:** 2026-03-23 - **Tags:** side-projects, genai, software-engineering, aws, agentic-sdlc, platform-engineering - **URL:** https://vinny.dev/blog/2026-03-23-meet-roci-always-on-personal-ai-agent/ Back in January, I wrote about a simple idea: what if your AI assistant wasn't something you opened, but something that was always there? At the time, it was mostly theory: something interesting to think about but not yet something I relied on. Over the past two months, that changed. I've been running a personal AI agent I call Roci, and she now operates continuously on a dedicated EC2 instance in my AWS account. She monitors systems, checks feeds, summarizes information, and interacts with parts of my home environment. This is no longer a chatbot I occasionally prompt. It has become something I depend on in small but meaningful ways, and that shift turned out to matter more than I expected. This is not really a story about naming an agent or wiring together tools. It is about what changes when AI stops being something you reach for and starts becoming infrastructure you live with. ## The shift: from tool to presence Most of us still experience AI the same way we experienced early search engines. You open it, ask a question, get an answer, and then move on. That model is useful, but it is inherently reactive and limited to the moments when you remember to engage with it. Roci operates differently. She runs whether I am thinking about her or not, checks things on a schedule, notices when something drifts, and surfaces useful information without being prompted. In a few constrained ways, she can also take action. None of this feels like autonomy in the science fiction sense. Instead, it feels like a system quietly operating alongside you, handling small pieces of work that would otherwise require attention. Over time, that presence starts to feel less like a tool and more like a layer of support built into your day. ## The setup (without getting lost in it) Roci runs on a small, dedicated EC2 instance in a tightly controlled environment. The stack itself is straightforward: Amazon Linux 2023, a modest amount of compute and memory, Docker for runtime isolation, and OpenClaw orchestrating the agent loop. The "heartbeat" of the system is a persistent loop that wakes up every 15 minutes to check high-priority signals, with a deeper sweep performed once an hour. Those details matter less than the design choices behind them. The goal was not to build something complex or impressive, but to build something reliable, predictable, and always available. This system runs continuously and operates within a clearly defined surface area, and that constraint shaped far more decisions than any specific technology did. ## What she does The most useful things Roci does are not flashy, which is exactly why they matter. Each morning, she generates a briefing that summarizes my calendar, lists updates from selected blog feeds, checks system health, and surfaces anything that looks unusual or worth attention. It is not perfect, but it consistently reduces a small amount of cognitive load. > **Typical Morning Briefing:** > * **Schedule:** 8 meetings today (first at 9:00 AM). > * **Tech Feeds:** 2 new posts on the AWS Engineering blog; 2 PRs from Dependabot merged overnight. > * **Infrastructure:** All 4 EC2 health checks are green; SSL cert for vinny.dev is valid for 45 more days. > * **Commute to work:** Commute to work is slow with traffic; Estimating 45 minutes to work. > * **Environment:** It's 35°F in Brookfield and so bundle up. Throughout the day, she continues to monitor things in the background. That includes checking blog feeds for publishing issues, validating endpoint availability, and watching for subtle signals that something is off. In one case, she flagged a stale RSS feed that had silently stopped updating. It was not urgent, but it was exactly the kind of issue that typically lingers unnoticed longer than it should. She is also connected to Home Assistant, which allows her to interact with lights and other IoT devices in simple, bounded ways. This is not a fully autonomous smart home, and I would not want it to be. Instead, it shows up as quiet delegation, fewer manual adjustments, and less friction in the background. ## The trust model (the part that matters most) The hardest part of building this was not getting it to work. It was deciding what it should be allowed to do. Roci operates within clear and intentional boundaries. These constraints are not incidental; they are the foundation of trust. | **Allowed** | **Forbidden** | | :--- | :--- | | Read RSS feeds & system logs | Send outbound emails autonomously | | Monitor EC2/AWS health | Modify production infrastructure | | Toggle Home Assistant devices | Access financial or banking systems | | Generate private summaries | Execute irreversible CLI commands | Without these hard lines, a system like this might be interesting, but it would not be something I would feel comfortable keeping online continuously. ## What surprised me A few things stood out once this moved from idea to reality. Naming the system had a bigger impact than I expected. I chose the name Roci as a nod to the *Rocinante* from *The Expanse*, a "legitimate salvage" workhorse that just gets the job done. Referring to it by name subtly changed how I interacted with it. Not because I think it is human, but because it created a sense of continuity. It feels less like a disposable session and more like a persistent system with defined responsibilities. I was also surprised by how much of the value comes from the boring work. The most useful behaviors are consistent monitoring, summarization, and small nudges. None of those are impressive on their own, but together they reduce friction in ways that add up. Most importantly, I came to appreciate that boundaries matter more than capability. The question is not what the system can do, but what it should be allowed to do. That shift in perspective changes how you design everything around it. ## What I got wrong Early on, I spent time thinking about whether people should run systems like this at all. That framing turned out to be less useful than I expected. The better question is whether you can define clear enough boundaries to run them responsibly. Autonomy is not the goal. Reliable, scoped usefulness is. Once you view it through that lens, the problem becomes much more practical and much less abstract. ## Design principles emerging from this A few patterns have started to emerge from running this day to day. Systems like this benefit from being persistent rather than flashy, narrowly scoped rather than broadly permitted, and grounded in clear trust boundaries. In practice, usefulness consistently outweighs raw autonomy. These systems do not need to do everything. They need to do a few things reliably. ## A few months in Roci is not revolutionary, and she is not autonomous in any meaningful sense. What she is, however, is present and useful, and that combination changes how you think about AI over time. The real shift is not better chat interfaces. It is the emergence of persistent, bounded systems that quietly take work off your plate. Instead of one large, generalized system, the future may look more like a collection of smaller agents, each with clear responsibilities and well-defined limits. We are still early in this transition. Most people are experimenting with prompts, and a smaller group is experimenting with agents. Very few are treating these systems as infrastructure. That is where things start to get interesting, because once something is always on, scoped, and trusted, it stops being a demo and starts becoming part of how you operate. --- ## Strip the Assumptions: What Enterprise AI Adoption Actually Is - **Published:** 2026-03-22 - **Tags:** genai, software-engineering, engineering-leadership, platform-engineering - **URL:** https://vinny.dev/blog/2026-03-22-strip-the-assumptions-enterprise-ai/ Most enterprise conversations about generative AI are arguments about assumptions, and nobody is questioning the assumptions. I've sat in enough of those rooms to recognize the pattern. Someone presents a business case with a tidy ROI model. Someone else raises a governance concern, and a third person references what a competitor is doing. The conversation sounds strategic, but it's a negotiation between inherited frames, and the inherited frames are wrong. First principles thinking means refusing to carry forward what you borrowed. You start from what is provably true and build only from what survives the stripping. Here is what that exercise produces. ## The five assumptions running every enterprise AI conversation 1. This is a technology adoption problem. The analogy says: we adopted cloud, we adopted SaaS, now we adopt AI. The analogy breaks immediately. Cloud replaced infrastructure and SaaS replaced packaged software. Generative AI reduces the marginal cost of specific cognitive outputs without replacing either one. That's a different category of change, and it requires a different adoption model. 2. ROI is measurable in the short term. Finance wants a business case before anything moves, but knowledge work output has never been reliably measurable, even before AI entered the picture. Generative AI just adds a new variable to an equation that was already unsolved. 3. The model is the limiting factor. Get a better model, or the right model, and adoption accelerates. This inverts the actual constraint. In almost every enterprise deployment I've seen or heard about, the bottleneck is the organization's capacity to evaluate whether outputs are trustworthy. 4. Governance must be solved before scaling. Get the policy right, get the guardrails right, then scale. It sounds responsible, and it's a risk trade made implicitly. Waiting carries its own costs: capability gap, adoption debt, a slower organizational learning curve. Governance is a continuous calibration rather than a precondition. 5. The value lives in automation. Replace the headcount, eliminate the process. The math on full automation looks appealing until you account for the error correction problem. Automated errors compound, while augmented humans correct in real time. ## What survives the stripping Remove every assumption. Strip the analogies, the vendor narratives, the org chart pressure. Six statements remain, and they hold regardless of which model you use, which vendor you select, or what industry you're in. Knowledge work is a bundle of discrete cognitive tasks, each with a frequency, a difficulty, and a cost. Human attention is the scarcest and most expensive resource in any organization. Generative AI reduces the marginal cost of producing certain cognitive outputs, primarily text, code, analysis, and synthesis. The value of reduced-cost output depends entirely on whether the humans receiving it can evaluate whether it's correct. Organizational capability builds through use, and planning isn't a substitute for it. Risk is never eliminated, only traded, which makes inaction its own risk position. That's the foundation, and everything else is strategy layered on top. ## Rebuilt from zero If you build from only those six truths, the picture changes shape. Adoption is a task economics problem. Rather than "what is our AI strategy," the right first question is: which cognitive tasks consume the most attention in this organization? Which of those tasks can generative AI produce acceptable outputs for? What is the cost of an error in each task, and do our people have the domain skill to catch it? That question produces a ranked list of high-leverage use cases. The list is empirical, so you can act on it Monday morning. Measurement shifts from activity to decisions. Tokens generated, prompts run, and seats licensed all measure activity, while the question worth answering is whether specific decisions improved. Did engineering shipping velocity change? Did first-draft communication quality improve? Did analysts spend more time on interpretation and less on data assembly? Activity metrics are proxies, and decision quality is the signal. Governance becomes empirical. Instead of asking "is this safe to deploy before we start," you ask "which tasks, at which error rates, with which humans in the loop." Governance is a continuous risk calibration built on actual usage data. The policy document written before anyone used the tool is mostly fiction. Talent investment changes direction, away from prompt engineering and broad "AI fluency." The scarce resource is evaluation capacity: people who can distinguish good AI output from bad output in their specific domain. A senior engineer who immediately spots a plausible but incorrect code suggestion is more valuable than someone who generates more suggestions faster. You need fewer generators and more evaluators. The build, buy, or partner question sharpens once you stop asking "which model is best." Which tasks are high enough leverage, common enough in our workflows, and stable enough in their requirements to warrant building durable evaluation infrastructure around? That produces a much shorter list and a much clearer investment thesis. ## The table that matters | Inherited frame | First principles frame | |---|---| | Measure adoption rate | Measure decision quality | | Strategy before deployment | Experiments before strategy | | Governance as a gate | Governance as a signal | | Hire AI talent | Build evaluation capacity | | Automate the task | Augment the person doing it | | Chase the best model | Find the highest-leverage tasks | | Move fast to win | Learn fast to compound | ## The shift that stings a little The most disorienting change is the last one, where speed of learning beats speed of deployment. Plenty of organizations deployed tools in 2024 and 2025. The ones that compound fastest built the tightest loop between use, evaluation, correction, and improvement. That loop is not a technology problem. It is a leadership problem. Most enterprise AI conversations never reach it, because they're still negotiating the assumptions they inherited and never questioned. Stop arguing about the assumptions, start from what is true, and build from there. --- ## They're Using Claude to Ship Claude (And It Shows) - **Published:** 2026-03-21 - **Tags:** genai, software-engineering, claude-code, platform-engineering - **URL:** https://vinny.dev/blog/2026-03-21-theyre-using-claude-to-ship-claude/ I've been watching the Claude team work lately, and I can't stop thinking about one thing. They're dogfooding their own product to build their own product. That's not a hot take. That's just what's happening. And the output is starting to feel like proof of concept at scale. In the last few weeks alone: Projects in Cowork, Dispatch (the remote-control feature that works now), scheduled recurring tasks inside Cowork, Claude Code Channels for controlling your session from Telegram or Discord, two new flagship models in Sonnet 4.6 and Opus 4.6, Excel and PowerPoint add-ins that now share full conversation context, a plugin marketplace, a persistent agent thread for Pro and Max users, and inline custom visualizations in chat. Count those up. That's not a quarter's worth of releases. That's a few weeks. ## The meta part is the point There's something beautifully recursive happening here. You're using an AI assistant to build features that make the AI assistant more useful. Every improvement compounds. Every workflow they fix internally probably turns into a shipped feature two weeks later. It's Inception, but for product development. Dream within a dream, except the dream is a Claude Code session running scheduled tasks overnight while someone sleeps in San Francisco. I've used the term "dogfooding" professionally for years. Most teams give it lip service. They use the product occasionally, file a ticket or two, and call it good. What Anthropic appears to be doing is different. The pace of iteration suggests they're living inside these tools, hitting real edges, and shipping fixes faster than the release notes can keep up. That's not marketing. That's what it looks like when a team eats the food. ## The features that signal something bigger Claude Code Channels caught my attention the most. Announced March 20, 2026 as a research preview, it ships with Telegram and Discord support first, with a plugin architecture designed to expand from there. The idea is straightforward: you message a bot from your phone, and the Claude Code session running on your machine picks it up, executes the work, and replies back through the same channel. It's two-way. Claude reads the event and responds through the channel. Your presence at the terminal is optional. I know exactly what that setup looks like. I've been building it myself. My OpenClaw project, an always-on personal agent named Roci running on an AWS EC2 instance behind Tailscale, exists precisely because this gap existed. *(Roci is short for Rocinante, the ship from The Expanse, itself named after Don Quixote's horse. A creature that kept moving regardless of whether the quest made sense. For an always-on agent, I couldn't think of a better namesake.)* If you wanted a persistent AI worker you could message from anywhere and have it do real work while you stepped away, you had to roll it yourself. Axiom is my sandbox for that problem: a SOUL.md, a USER.md, a TOOLS.md, identity configuration, the works. Infrastructure I provision and maintain, trade-offs I make consciously. Claude Code Channels is Anthropic shipping that same idea as a first-party, five-minute setup. The architectural choice here is worth noting. The channel plugin runs locally on your machine and polls the messaging platform's Bot API. No inbound port opened on your machine. No webhook endpoint exposed to the public internet. No reverse proxy needed. Compare that to what it takes to route traffic through a Tailscale mesh to an EC2 instance. Both approaches solve the same problem. One of them involves considerably more yak shaving. This is the tell. When the tool you've been building on your own time starts shipping as a native product feature, you're not ahead of the curve anymore. You're validating it. OpenClaw, Roci, every homebuilt persistent agent hack out there: demand signals. Anthropic read them. What Roci taught me is that the hard part isn't the messaging layer. It's context persistence, identity configuration, and deciding what you trust the agent to do unsupervised. Those problems don't go away with Claude Code Channels. They just become accessible to more people, which shifts the interesting work upstream. The real architecture question becomes: what does your agent do while you're not watching, and what guardrails do you put around that? Because Channels is built on MCP, the community can build connectors for Slack or WhatsApp without waiting for Anthropic to ship them. That's not a small design choice. That's Anthropic acknowledging they can't cover every surface themselves, so they're making the protocol extensible from day one. OpenClaw's whole appeal was reach: iMessage, WhatsApp, Telegram, Slack, all in one personal AI worker. Anthropic's answer isn't to match every surface. It's to build the protocol layer and let the community fill the gaps. The scheduled recurring tasks in Cowork carry the same signal. Someone hit a real problem: "I want this to run on a cadence without me triggering it manually." They built the solution, then shipped it. That loop is fast. Projects in Cowork and Dispatch point at something else entirely. Persistent, organized workspaces with their own files, context, instructions, and memory. A remote control for your desktop agent that you pair from your phone via QR code and use from anywhere your Mac stays awake. These are harder problems. The fact that they're shipping alongside the more tactical features suggests depth of execution, not just velocity. ## What this means for builders like me I've been building with Claude Code since the early days of the product. I've watched it get meaningfully better, not in a "we added a setting" way, but in a "the fundamental workflow just shifted" way. That's rare. Most tools plateau. They hit good enough and stay there because the incentive to keep pushing drops off. The Anthropic team doesn't have that problem. Every improvement they make to Claude is an improvement to the tool they use to make improvements to Claude. The flywheel is real, and it is spinning fast. My practical take: if you're a builder who hasn't revisited Claude or Claude Code in the last 30 days, you owe yourself 20 minutes this week. The tool you used then is not the tool you'll open today. And by the time you finish reading this, they've probably shipped something else. ## A note on the remote control fix Dispatch works now. That's all I'll say. Sometimes the most important release note is the one that just says: fixed. --- ## Yesterday's Feature Is Today's Bug - **Published:** 2026-03-15 - **Tags:** engineering-leadership, software-engineering - **URL:** https://vinny.dev/blog/2026-03-15-yesterdays-feature-is-todays-bug/ *On building IT strategy that outlasts the people who built it.* There's a phrase I keep coming back to in my work as an engineering leader: *"Yesterday's feature is today's bug."* It started as a way to describe something familiar to every software team. That moment when you realize the thing you built on purpose, the thing you celebrated at launch, is now the thing causing problems. No one made a mistake. The context around it changed. The more I've sat with this idea, the more I've realized it applies far beyond software. It describes something fundamental about how technology strategy works inside organizations, and what it means to build something that lasts. ## The revolving door is a feature, not a bug Leadership transitions are inevitable. CIOs move on, CTOs get promoted or recruited away, and new VPs come in with fresh mandates and fresh eyes. If you've been in technology long enough, you've lived through at least one of these moments where someone new walks in and the first question they ask is some version of *"why are we doing it this way?"* It's easy to feel defensive in that moment. Your team built that thing, you made that call, and it worked. I've come to see the revolving door of leadership as a test of good strategy. If your IT strategy can't survive a leadership transition, it probably wasn't a strategy. It was a preference, someone's aesthetic, a personality expressed as architecture. When a new leader looks at your platform and asks hard questions, that's the system working. Fresh eyes see what familiarity hides. And if your strategy is sound, if it's built on real outcomes and real principles, it will hold up under scrutiny. It might even get better because of it. ## Build on principles, not personalities The most durable IT strategies I've seen are anchored to outcomes rather than opinions. *"We do it this way because the last CTO liked it"* won't survive a transition. *"We do it this way because it reduces toil, increases deployment frequency, and keeps our teams safe"* will. Security, developer experience, reliability, and speed are compasses. Compasses don't need to be re-validated every time someone new joins the executive team. When I think about the work my teams are doing right now, pipeline-first delivery, cloud migration, platform consolidation, I try to ask myself a simple question: *Is this rooted in a principle, or a personality?* If I left tomorrow, would the team know *why* they're doing what they're doing? Would the next leader be able to pick this up and run with it? That's the standard I'm working toward. I want a strategy that keeps working after I've moved on, even if it never makes me look good. ## Design for succession The best engineering leaders build platforms that outlast them. They write things down. Documentation, architecture decision records, and runbooks all read as bureaucracy right up until the person who comes next needs them. They build teams that don't depend on any one person, including themselves. If you're building monuments to yourself, you're building tomorrow's technical debt. Succession is an architectural philosophy as much as a talent management conversation. It means asking: if I walked out the door tomorrow, what would break? Then you go fix it, whether or not you're leaving, because fragility is fragility, regardless of who holds the seat. ## Use the quote as a diagnostic, not a verdict When a new leader looks at your roadmap and labels something a bug, something the last team called a feature, the instinct is to defend it or bury it. Neither is right, and both skip the real question: *what changed?* Was it the customer need, the competition, the organization's risk tolerance, or the technology itself? Sometimes the answer is that the new leader just has a different aesthetic, and that's worth acknowledging. But often, something real *did* change, and the "bug" label is a signal worth paying attention to. "Yesterday's feature is today's bug" is a prompt to understand the present. Context drift is real. The best thing you can do is build a culture where that conversation happens honestly, with genuine curiosity instead of blame or defensiveness. ## What durable strategy looks like Building an IT strategy that can survive the revolving door comes down to a few habits. It starts with documenting the *why* behind a decision, not just the *what*. You measure outcomes, and you're honest when they aren't being achieved. Your teams own the platforms they work on. New leaders get room to contribute and challenge and improve without feeling like they're tearing something down. Maybe most important of all is letting go of the idea that your strategy is *yours*. The best thing any of us can build is something that keeps getting better after we're gone. That's the whole job. --- ## Dark Fiber, Bright Future: Why the AI Infrastructure Boom May Need Its Bust - **Published:** 2026-03-11 - **Tags:** genai, software-engineering, ai-economics, platform-engineering, engineering-leadership - **URL:** https://vinny.dev/blog/2026-03-11-dark-fiber-bright-future/ The companies that built the modern internet went bankrupt doing it. In the late 1990s, firms such as WorldCom, Global Crossing, and Qwest spent hundreds of billions of dollars laying fiber-optic cable across continents and oceans. They financed most of it with debt. They justified it with a forecast that internet traffic was doubling every 100 days. In reality, traffic was doubling annually. The consequences were brutal. Global Crossing filed for bankruptcy in 2002 with more than $12 billion in debt. WorldCom collapsed shortly afterward in what became the largest accounting fraud in U.S. history. By 2005, roughly 85% of all installed fiber remained dark, completely unused. Bandwidth prices had cratered by 90%. From a financial perspective, it was a disaster. From a technological perspective, it was the foundation of the modern internet. The fiber networks built during that speculative boom later enabled cloud computing, streaming media, global SaaS platforms, and video communication at planetary scale. Infrastructure that bankrupted its builders ultimately powered the digital economy. The companies building AI infrastructure today may follow the same path. That is not a cautionary tale. It is how technological revolutions work. ## The largest infrastructure buildout in the history of software Artificial intelligence has triggered a massive global investment cycle in computing infrastructure. The world's largest technology companies are rapidly expanding data centers, purchasing specialized AI accelerators, and building high-capacity networks to support the training and operation of large models. The numbers are extraordinary. The five largest U.S. hyperscalers (Amazon, Microsoft, Google, Meta, and Oracle) are projected to spend roughly $600 billion to $690 billion on infrastructure in 2026. That is a 36% increase over 2025, and roughly 75% of it targets AI compute directly. Capital intensity at some of these companies has reached 45% to 57% of revenue, ratios that resemble industrial utilities, not the asset-light software businesses they were five years ago. The trend is unlikely to slow. Goldman Sachs estimates that cumulative hyperscaler capex from 2025 through 2027 will reach $1.15 trillion, more than double the $477 billion spent from 2022 through 2024. McKinsey projects that data-center investment associated with AI could reach $3.7 trillion to $7.9 trillion by 2030, depending on demand scenarios. In 2025, tech capex as a percentage of GDP nearly matched the combined scale of the largest capital projects of the 20th century: nationwide broadband, the interstate highway system, the Apollo program, and the Manhattan Project. In other words, the AI revolution is not just a software story. It is an infrastructure story. And infrastructure cycles rarely follow smooth economic curves. ## The revenue gap Despite rapid progress in generative AI tools, revenue remains strikingly small compared with the scale of infrastructure investment. AI-related services generated roughly $25 billion in revenue in 2025. The hyperscalers spent more than $400 billion on infrastructure in the same period. That is a ratio of roughly 16 to 1. Consulting firm Bain & Company has argued that the AI ecosystem may ultimately need to generate roughly $2 trillion in annual revenue to justify the infrastructure spending currently underway. Even the most aggressive forecasts for enterprise AI adoption fall well short of that figure, leaving a gap measured in hundreds of billions of dollars. Meanwhile, the largest pure-play AI companies are burning cash at historic rates. OpenAI posted a $13.5 billion net loss in the first half of 2025. Internal projections show losses of $14 billion to $17 billion in 2026. The company expects cumulative cash burn of $218 billion between 2026 and 2029 before reaching profitability. Anthropic is on a more conservative path, projecting breakeven by 2028, but even disciplined players face enormous capital requirements. The gap between infrastructure investment and realized revenue is striking. But it is not unprecedented. In fact, it is one of the most consistent patterns in technological revolutions. ## The installation phase of a technological revolution Economic historian Carlota Perez spent decades studying how major technologies transform economies. In her landmark work *Technological Revolutions and Financial Capital*, she found that industrial transformations tend to follow a recurring sequence. First comes a breakthrough technology. Then comes a surge of financial speculation as investors race to build the infrastructure required to exploit it. Eventually, a correction occurs as overcapacity and unrealistic expectations collide with economic reality. Perez describes this period as the installation phase of a technological revolution. During this phase, capital floods into infrastructure projects. Railways in the 19th century, electrical grids in the early 20th century, and fiber networks during the internet boom all followed this pattern. Infrastructure is built faster than the economy can initially use it. Speculative excess is common. And financial collapse often follows. But the infrastructure survives. Once the financial bubble bursts and assets are repriced, a new phase begins. Perez calls this the deployment phase, when the technology spreads throughout the economy and productivity accelerates. This is the phase where the real value of the infrastructure emerges. ## Infrastructure before productivity History offers many examples of this dynamic. The economist Paul David demonstrated that electrification did not immediately increase industrial productivity because factories initially replaced steam engines with electric motors without redesigning production systems. Only after manufacturers reorganized factories around electric power did productivity surge. Similarly, the internet required decades of infrastructure development before it produced global digital platforms, cloud computing, and the modern SaaS economy. Technological revolutions often follow a pattern: Infrastructure first. Transformation later. Artificial intelligence appears to be following the same trajectory. Large models and compute infrastructure are being built at extraordinary speed. But the organizational, economic, and societal transformations required to fully exploit them are still emerging. ## The risk embedded in the current boom None of this guarantees that the current AI investment cycle will produce financial winners. Infrastructure booms are notorious for destroying capital even as they enable long-term technological progress. During the telecom bubble, dozens of competing companies built fiber networks. Most of them went bankrupt. The infrastructure remained. Today, a similar dynamic is unfolding in AI infrastructure. Hyperscalers are competing to build the largest compute platforms in the world, while specialized providers and "neoclouds" are financing massive GPU clusters with layers of private credit, securitized debt, and off-balance-sheet vehicles. In 2025 alone, Big Tech issued over $100 billion in bonds to fund AI capex. Google co-founder Larry Page has reportedly told colleagues he is willing to go bankrupt rather than lose the AI race. That statement reveals the Darwinian pressure driving these decisions. Companies are spending not because the ROI is clear, but because the cost of falling behind feels existential. Some of these investments will succeed. Others will not. History suggests that the companies that ultimately capture the most value from a technological revolution are often not the ones that spent the most building the infrastructure. ## Creative destruction and the economics of innovation The Austrian economist Joseph Schumpeter described economic development as a process of "creative destruction," in which waves of innovation displace existing firms while creating entirely new industries. Infrastructure bubbles are often one of the mechanisms that make this process possible. Speculative capital accelerates the construction of networks, factories, and systems that would otherwise take decades to build. When the bubble bursts, those assets are repriced and become accessible to a much wider range of innovators. The telecom crash of the early 2000s offers a clear example. While investors lost billions, the fiber networks built during that period enabled the rise of global streaming services, cloud platforms, and digital collaboration tools. The infrastructure outlived the balance sheets that financed it. The same will likely be true of the AI infrastructure being built today. ## What this means for technology leaders If you lead engineering teams, the question is not whether AI will transform your organization. It will. The question is how you position your teams and your architecture for a market where platform providers may not survive the cycle that created them. Build skills, not dependencies. Every major AI provider is competing to lock you into their ecosystem. Invest in your team's ability to use AI tools effectively. But do not anchor your architecture to any single provider's survival. The infrastructure will outlast some of the companies that built it. Your abstractions and your people need to outlast them too. Diversify your AI supply chain. If you are running production workloads on a single AI platform, you are carrying concentration risk that most enterprise leaders would never accept in any other part of the stack. Treat AI providers the way you treat cloud providers: with multi-vendor strategies, clean interfaces, and exit plans. Measure outcomes, not activity. The pressure to "do something with AI" is intense right now. Resist the urge to optimize for visible AI adoption. Optimize for measurable business value. The organizations that thrive through technology transitions focus on solving real problems, not chasing installation-phase hype. Lead with empathy. As a servant leader, recognize that these cycles create immense pressure. Protect your teams from the "installation phase" burnout of chasing every hype cycle, and focus them on solving real business problems. Prepare for the repricing. When the correction comes, and it will come, the cost of AI compute will drop dramatically. The organizations that have already built the skills and the organizational muscle to use AI effectively will be the ones positioned to move fastest during the deployment phase. That is where the real value gets created. ## The paradox of infrastructure bubbles The paradox of technological revolutions is that they often require enormous financial excess in order to move quickly enough to transform the economy. Infrastructure bubbles look wasteful in quarterly earnings. Measured over decades, they are the price of progress. The data centers and compute clusters being built today will likely outlive the balance sheets that financed them. Some companies will fail, but the infrastructure itself will power the next generation of innovation. The future will be brighter than the balance sheets that built it. --- ## From iOS to Android in a Weekend: How I Used Claude Code to Build a Complete App Without Writing a Single Line of Code - **Published:** 2026-03-10 - **Tags:** genai, software-engineering, ai-coding, claude-code - **URL:** https://vinny.dev/blog/2026-03-10-from-ios-to-android-app-in-a-weekend/ I've been shipping software for over two decades. I've seen plenty of "no-code" promises come and go. So when I tell you that I took an existing iOS application, pointed an AI at it, and had a fully functional Android app, complete with notifications, offline support, local database, and accessibility features, in about eight hours over a weekend, I understand if you're skeptical. I was too. Until I did it. If you read my recent post about [building PourCraft Coffee, a brand new iOS app, in 32 minutes](https://vinny.dev/blog/2026-03-01-vibe-coding-with-coffee/), you saw what Claude Code can do with a greenfield project. This time, I wanted to push it further: take an existing, production iOS app and port it to an entirely different platform. Same AI, bigger challenge. ## The starting point: TravelTimes [TravelTimes](https://traveltimesapp.com/) is an iOS app I built that displays real-time Milwaukee freeway travel times from the Wisconsin Department of Transportation API. It's a focused, well-scoped utility app, not a toy project. The iOS version features: - Real-time route data with color-coded delay status - Favorites with reordering and swipe gestures - Scheduled notifications for your commute - Offline support with graceful degradation - Search with debounced filtering - A "What's New" dialog for version updates It's the kind of app that exercises a broad surface area of a mobile platform: networking, local persistence, background work, push notifications, accessibility, and thoughtful UI/UX. Porting it to Android the traditional way would mean weeks of work, learning (or re-learning) Android-specific idioms, setting up the Gradle build, wiring up Hilt dependency injection, configuring Room for local storage, writing Jetpack Compose UI, and handling all the platform quirks that come with Android development. I decided to see if Claude Code with Opus 4.6 could do it instead. ## The approach: show, don't tell My approach was deliberate. I didn't just say "build me an Android app." I gave Claude structured context: 1. The iOS source code. I pointed Claude at my Swift codebase so it could understand the data models, API contracts, business logic, and feature set. 2. Four screenshots of the running iOS app. These showed the routes list, favorites screen, route detail view, and notification scheduling UI. Claude used these to understand the visual design intent. 3. My coding standards document. This is a comprehensive set of guidelines I use across all my projects, covering everything from function length limits (30 lines max) to naming conventions, DRY principles, error handling patterns, and architectural preferences. 4. A CLAUDE.md project file. This gave Claude the Android-specific architectural context as the project evolved: build commands, data flow diagrams, tech stack decisions, and the patterns I wanted it to follow. That was it. I provided the *what* and the *standards*. Claude figured out the *how*. ## What Claude built The numbers tell part of the story: 43 Kotlin files, ~5,300 lines of code, organized into a clean MVVM + Clean Architecture structure. But the architecture doesn't capture how *right* the decisions were. Claude didn't just transliterate Swift to Kotlin. It built an idiomatic Android application. Hilt for dependency injection with proper module separation and a `HiltWorkerFactory` for WorkManager integration, including the non-obvious step of disabling the default WorkManager initializer in the manifest. Room database with versioned migrations. When I asked Claude to add notification schedules in a later iteration, it created a proper v2 schema with `AutoMigration(1→2)` rather than nuking the database. Kotlin Flows and coroutines throughout, including the connectivity observer, the repository's caching layer, and the debounced search. Material 3 with dynamic theming, swipe-to-dismiss gestures, and custom TalkBack accessibility actions on route cards. It didn't just make the app work; it made it accessible. Proper Android permission handling: runtime permission requests for notifications on API 33+, exact alarm scheduling on API 31+, and a boot receiver to reschedule alarms after device restart. The app targets SDK 35 (Android 15) with a minimum SDK of 26 (Android 8.0), covering approximately 95% of active devices. Claude set up the Gradle build with a signing configuration that loads from `local.properties` for local development, with an environment variable fallback for CI/CD. ## The process: guiding, not coding I want to be honest about what "I didn't write a single line of code" actually means, because it's not the same as not working. I was actively guiding the process the entire time. The first iteration got the core structure and most features in place. From there, it was a series of focused conversations: - "The swipe behavior on the favorites screen should snap back after adding a favorite, not dismiss the row." - "The notification scheduling needs to support per-day-of-week configuration." - "Add an offline banner that appears when connectivity is lost." - "The search should be debounced. Users shouldn't hit the API on every keystroke." Each of these was a natural-language conversation. I described the behavior I wanted, and Claude translated that into the correct implementation. When something wasn't right, I described what was wrong, and Claude fixed it, usually identifying the root cause faster than I would have navigating an unfamiliar codebase myself. The total time was about eight hours spread over a weekend. The part that still surprises me: I spent more time wrestling with Android Studio's IDE quirks and setting up my Google Play developer account than I did on the actual application code. ## What made it work The quality of Claude's output was directly proportional to the quality of my input. A few things separated this from a mediocre result. A clear reference implementation. Having the iOS codebase as a reference gave Claude an unambiguous spec. There was no guessing about features, edge cases, or UI flows. Every behavior was defined by working code. Explicit coding standards. My `coding-standards.md` document isn't just style preferences. It covers architectural patterns, error handling strategies, and quality guardrails. Giving Claude these standards upfront meant I rarely had to send code back for quality issues. Behavioral descriptions over implementation details. I described what I wanted the app to *do*, not how to *code* it. "The favorites screen should let users reorder favorites using up/down controls in edit mode" is a better prompt than "implement a RecyclerView with drag handles." Letting Claude choose the implementation gave it room to pick the most idiomatic approach. Iterative refinement. I didn't try to specify everything upfront. I let Claude build the foundation, then refined through focused follow-up conversations. This mirrors how real software development works: build, review, iterate. The code quality reflected all of this. Functions were focused and small. The architecture was layered properly. Error handling was thoughtful, with exponential backoff on API retries, graceful offline fallbacks, and proper null safety. The visual fidelity was high too. From four screenshots, Claude reproduced the design while keeping a native Android look and feel. The app doesn't look like an iOS port; it looks like it belongs on Android. ## What this means for developers I've seen too many "AI will replace developers" hot takes, and that's not what happened here. What happened was that an experienced developer with clear requirements, strong coding standards, and good judgment used AI to dramatically compress the implementation timeline. The skills that mattered were: - Knowing what to build: understanding the requirements deeply - Knowing what good looks like: having standards and being able to evaluate output - Knowing how to guide: giving clear, behavioral direction when things needed adjustment - Knowing when something's wrong: reviewing the generated code with a critical eye These are all engineering skills. The AI didn't replace the engineer; it amplified the engineer. If you're a developer who has been thinking about porting an app to another platform, or building something you've been putting off because the implementation time felt too daunting, the barrier just got a lot lower. The time from idea to working application is now measured in hours, not weeks. ## Current status The Android version of TravelTimes is currently under review for the Google Play Store. The app has feature parity with the iOS version: all priority items are implemented, the build is clean, and all tests pass. From a single iOS codebase, four screenshots, and a set of coding standards, Claude Code with Opus 4.6 produced a production-ready Android application in a weekend. That's not a demo. That's not a prototype. That's a real app, heading to a real app store, built by a developer who guided an AI instead of writing code manually. The future of software development isn't about AI replacing developers. It's about developers who know how to work with AI building things that used to be impossible on a weekend timeline. --- ## From Caffeine Addict to App Builder: How I Vibe Coded a Pour-Over Coffee App in One Afternoon - **Published:** 2026-03-01 - **Tags:** genai, software-engineering, ai-coding - **URL:** https://vinny.dev/blog/2026-03-01-vibe-coding-with-coffee/ I have a problem. Not the kind that requires an intervention. More the kind where I own three different coffee grinders, have opinions about water temperature measured in single-degree increments, and once spent 20 minutes explaining to a barista why their bloom time was too short. I am, by any clinical definition, a coffee person. What I did not expect was to create another one. ![PourCraft iOS App](/images/blog/2026/03/PourCraft-Collage.png) ## The origin story (blame the gooseneck kettle) It started innocently enough. My wife asked for a gooseneck kettle for Christmas. I bought her a nice one. She made a cup. Then she made another cup. Then she asked me what the difference was between a 1:15 and a 1:17 ratio. Then she asked about water temperature. Then she started reading the roast dates on bags at the grocery store, frowning and putting them back. I had created a monster. A wonderful, discerning, "is this single-origin?" monster. Within a few weeks, she was weighing beans on a kitchen scale, timing her pours, and gently correcting my technique. The student had become the master. And the master, being an engineer, thought: "I should build an app for this." ## A brief history of me vs. Swift I've been building iOS apps for over a decade. My app [TravelTimes](https://traveltimesapp.com/) has been in the App Store since 2014. It provides real-time commute data for Milwaukee drivers, and I still maintain it today. Most recently, I [built a full production notification system](https://vinny.dev/blog/2026-02-06-building-notification-system-with-claude/) for TravelTimes in a single day using Claude Code. But let me be honest about what iOS development used to look like for me. Before AI-assisted development, building a new feature in Swift meant weeks of work. Not because the logic was complex, but because the surface area was enormous. You'd spend a day just setting up the project structure. Another day fighting Auto Layout constraints (or, in the SwiftUI era, figuring out why your preview wasn't rendering). A few more days writing boilerplate for data models, view models, navigation, persistence, and the dozen other things a modern iOS app requires before it does anything useful. My TravelTimes app took weeks of evenings and weekends to reach its first version. Every feature after that was measured in days, sometimes longer. The notification system I built recently was a turning point: one day, start to finish, 1,800 lines of production code. That was with Claude Code and Opus 4.5 acting as a thinking partner. But PourCraft? PourCraft was different. PourCraft was an afternoon. ## The vibe coding session I sat down on a Saturday with a clear idea, a warm cup of coffee (medium roast, 1:16, since you asked), and a detailed prompt. Not a vague prompt. A real spec: features, color palette, data model, file structure, typography choices, and design direction. I've [written before](https://vinny.dev/blog/2025-11-15-journey-with-trusting-genai-and-coding-workflow/) about how spec-driven development is the difference between vibe coding that works and vibe coding that produces expensive garbage. This was the former. Here's what the app needed to do: 1. Let you select a roast level (light, medium, or dark). 2. Enter your coffee weight in grams. 3. Calculate the exact water amount using the Golden Ratio. 4. Provide a step-by-step brew guide with bloom water, pour water, and temperature guidance. 5. Offer pro tips on grind size, water quality, and technique. Simple in concept. But "simple" in iOS still means MVVM architecture, a SwiftUI color system with light and dark mode, computed properties for real-time calculation, @AppStorage for user preferences, proper typography hierarchy, and enough visual polish that my wife would want to use it instead of just Googling the ratio. The spec covered all of it. And Claude Code turned that spec into a working application structure in hours, not weeks. ## What changed (and what didn't) Let me be clear about what AI-assisted development does and doesn't do. It does not think for you. Every architectural decision in PourCraft was mine. The choice to use MVVM with @Observable. The decision to compute bloom water as 2x coffee weight. The color palette inspired by the gradient of coffee, from morning gold to dark walnut. The typography pairing of a warm serif for headers with a clean sans-serif for body text. Those are design decisions, and they require taste, context, and intent. What AI-assisted development does is collapse the implementation timeline. The distance between "I know what I want to build" and "I have working code that does it" has shrunk from weeks to hours. That's not a small change. That's a fundamental shift in what's possible for builders who have ideas but limited time. I think about this a lot in the context of my day job leading 250+ engineers. The bottleneck in software has never been typing speed. It's always been the gap between intent and execution. Tools like Claude Code are compressing that gap, and it changes how individuals and teams can operate. ## The coffee nerd details For those who care about the brewing science (and if you've read this far, you care), here are the ratios baked into PourCraft: **Dark roast (1:15):** Bold, heavy body. 20g of coffee gets 300g of water. This is for people who want their coffee to make a statement. **Medium roast (1:16):** The sweet spot. Clean, balanced, and the best representation of what the bean tastes like. 20g of coffee, 320g of water. This is where most specialty coffee drinkers live. **Light roast (1:17):** Bright, floral, sometimes tea-like. 20g of coffee, 340g of water. If you're drinking a washed Ethiopian Yirgacheffe and not using this ratio, we need to talk. The bloom step is universal: pour double the weight of the coffee (40g for 20g of coffee) and wait 30 seconds. That releases the CO₂ trapped during roasting and sets up even extraction. Skip this step and your cup will taste uneven. I have strong feelings about this. ## What I learned (again) Every side project teaches me something I bring back to my teams. PourCraft reinforced a few lessons: Specs beat vibes. A detailed prompt with clear requirements, a defined color system, and an explicit file structure produced better results than any amount of iterative prompting would have. This mirrors what I see at scale: teams that invest in clear requirements before writing code ship faster and with fewer defects. The tools are accelerating faster than most people realize. A year ago, I was writing about trusting GenAI with more of my code. Six months ago, I was building production features in a day. Now I'm scaffolding entire applications in an afternoon. The trajectory is steep, and it rewards people who invest in learning how to work with these tools. Side projects keep you sharp. I lead a large engineering organization, and it would be easy to let my hands-off-keyboard time grow. Building PourCraft reminded me what our developers experience daily: the friction of tooling, the joy of seeing something work, and the quiet satisfaction of shipping something real. ## The real win My wife uses the app. That's the whole point. She opens it in the morning, taps her roast, adjusts the weight, and follows the brew guide. No Googling. No guessing. No asking me (which, if I'm honest, was the secondary goal all along). She still corrects my pour technique, though. Some things even the best app can't fix. --- *The code, color palette, and full Claude Code prompt for PourCraft are available on my blog. If you're a builder with an idea and a free afternoon, I'd encourage you to try spec-driven vibe coding. The gap between "what if" and "it's on my phone" has never been smaller.* --- ## The Companies Spending the Most on AI Have the Most to Gain From Convincing You It Will Take Your Job - **Published:** 2026-02-17 - **Tags:** software-engineering, genai, future-of-work, ai-economics, ai-coding - **URL:** https://vinny.dev/blog/2026-02-17-you-cant-automate-demand-ai-jobs-narrative/ **The companies spending the most on AI have the most to gain from convincing you it will take your job.** Most conversations about AI and jobs get framed one of two ways: *inevitability* or *competition*. Either the technology improves and your job disappears, or it's you versus the machine, and the machine is faster, and cheaper. Both are oversimplifications. And both conveniently serve the interests of the companies selling the technology. There is a lot of hyperbole from the large hyperscalers and AI companies like Microsoft, Google, Amazon, and Meta, who are projected to spend over $300 billion on AI infrastructure in 2025 alone. That capital needs a return. And the math only works at scale if human labor is replaced. When executives warn that jobs may vanish, they're often not forecasting the future. They're trying to keep their investors happy. If there are no jobs, there are no consumers. And without consumers, growth stories collapse. There's no market for the products these companies are building. The narrative breaks down under its own weight. I live in the world of technology and software. As someone who's spent my career building and rebuilding software systems, I'm genuinely excited about how accessible coding has become. But I don't believe AI will replace software developers, and the history of our craft backs that up. Every major leap in abstraction was *supposed* to eliminate developers. Higher-level languages were going to make assembly programmers obsolete. Cloud platforms were going to replace infrastructure teams. Instead, each wave produced more software, more complexity, and more demand for skilled engineers. What we're seeing with generative AI is simply the next step in that progression. Nothing more. Nothing less. If anything, this wave will drive extraordinary demand for higher-quality software, built with greater care, clarity, and discipline. When everyone can generate code, differentiation shifts to the people who understand: - What to build - Why it matters - How to build it well The scarce skills become problem framing, system design, judgment, and taste. If you lead teams, your job isn't to figure out which roles AI replaces. It's to figure out how your people become *more valuable* with it. I'm bullish on the future. And it's not humans *versus* machines. It's humans *with* machines, compounding value. That's not naive optimism. That's how every major technology shift has played out. I'm curious as to what skills on your team become more valuable, not less, as AI gets better? *Originally published on [LinkedIn](https://www.linkedin.com/posts/vinnycarpenter_%F0%9D%97%A7%F0%9D%97%B5%F0%9D%97%B2-%F0%9D%97%B0%F0%9D%97%BC%F0%9D%97%BA%F0%9D%97%BD%F0%9D%97%AE%F0%9D%97%BB%F0%9D%97%B6%F0%9D%97%B2%F0%9D%98%80-%F0%9D%98%80%F0%9D%97%BD%F0%9D%97%B2%F0%9D%97%BB%F0%9D%97%B1%F0%9D%97%B6%F0%9D%97%BB%F0%9D%97%B4-share-7429703650924511232-UYtB?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAAMPBgBfbBH6Q-lntjTWCdKSP-iU9Wex3A).* --- ## How I Built a Production Notification System for TravelTimes in One Day with Claude Code - **Published:** 2026-02-06 - **Tags:** claude-code, ios, ai-coding, side-projects, software-engineering - **URL:** https://vinny.dev/blog/2026-02-06-building-notification-system-with-claude/ **From "users want commute alerts" to 1,800 lines of shipped, App Store-ready code in a single coding session.** ## The problem that started it all [TravelTimes](https://traveltimesapp.com/) is a personal iOS app I've maintained for over 10 years. It does one thing: shows you how long your commute will take, right now. You open the app, you see travel times for your saved routes, you leave. Simple. Useful. And completely useless at 6:45 AM when you're pouring coffee and haven't opened the app yet. The most requested feature since I launched v8.0.0 with iPad support was obvious: *"Can it just... tell me? Before I leave?"* Notifications. Scheduled, recurring, per-route notifications that deliver fresh travel time data at the moments you need it. Before your morning commute, before you leave the office. Not push notifications from a server. Not a one-size-fits-all daily alert. Personalized, schedule-driven, locally-managed notifications tied to exactly the routes you care about. This is not a trivial feature. It touches persistence, background refresh, thread safety, iOS notification APIs, permission flows, and a full CRUD interface. It lives at the intersection of several iOS subsystems, and historically it's the kind of feature I'd block out a week for. I built it in a day with Claude Code and Opus 4.6. Here's how. ## The architecture conversation The first thing I did was *not* write code. I described the feature to Claude Code and we talked architecture. ![Prompt for Claude Code](/images/blog/2026/02/travel-times-notification.png) *I started a conversation with Claude Code using this prompt.* What emerged was a clean separation of concerns: a dedicated data model to represent what a schedule *is*, a manager class to own all interactions with iOS's notification system, two full view controllers for the user interface, and targeted modifications to the existing persistence, networking, and app lifecycle layers. The key architectural decision was giving each concern a single owner. One class owns notification scheduling. A separate class owns data persistence. Neither knows too much about the other. The notification engine asks the persistence layer for routes and schedules. The persistence layer tells the notification engine when data changes. Clean boundaries, minimal coupling. The pipeline that holds it all together is straightforward in concept: every time fresh route data arrives (whether from a manual refresh, a pull-to-refresh, or a background fetch) the data gets cached, and then notifications are immediately re-scheduled with that current data. The user never sees stale information in a notification. That pipeline is the heartbeat of the entire feature. ## The data model: getting the foundation right Good features start with good models. A notification schedule, at its core, is just seven pieces of information: a unique identifier, a list of route references, a set of days, an hour, a minute, an enabled flag, and a creation timestamp. That's it. But the design choices embedded in those seven properties ripple through the entire system. References instead of copies. Schedules store route IDs, not full route objects. This was the single most important design decision. When fresh travel time data arrives from the network, we don't need to find and update every schedule that mentions a route. We just re-resolve those IDs against the latest data at the moment a notification fires. One decision, and an entire category of data consistency bugs simply can't exist. Sets instead of bitmasks. Days of the week are represented as a set of enum values rather than a bitmask or ordered array. Checking whether a schedule includes Monday reads like plain English, and toggling a day in the UI is a one-line set insertion or removal. The enum's raw values match the iOS calendar system, so converting a weekday into a notification trigger requires zero translation logic. The data model and the platform API speak the same language. Domain knowledge baked into presets. Rather than forcing users to configure every new schedule from a blank slate, the model includes factory methods for common patterns: a morning commute preset (weekdays at 7:00 AM) and an evening commute preset (weekdays at 4:30 PM). Claude suggested these during our initial design conversation, recognizing that reducing friction at schedule creation time would be critical for adoption. Smart display formatting as a first-class concern. The model itself knows how to describe its days in human-readable terms. If all five weekdays are selected, it says "Weekdays," not "Mon, Tue, Wed, Thu, Fri." Saturday and Sunday together become "Weekends." All seven become "Every day." These aren't cosmetic afterthoughts. They demonstrate how thinking about the user experience at the model layer produces cleaner UI code, because the view controllers don't need to reinvent that logic. ## The scheduling engine and the 64-notification cap The notification manager is where iOS-specific complexity lives. It's a singleton (appropriate here, because there's exactly one notification center per app) and it handles three responsibilities: managing permission requests, scheduling notification triggers, and responding when users interact with delivered notifications. The most interesting aspect is how a single human-readable schedule becomes multiple system-level notification requests. iOS local notifications trigger on calendar date components: a weekday, an hour, and a minute. A schedule that says "weekdays at 7:00 AM" doesn't produce one notification. It produces five, one repeating trigger for each weekday. A user with both a morning and evening commute schedule is already at 10 pending notification requests. The system fans out quickly. This is where Claude Code caught a production issue I wouldn't have anticipated until real-world testing. iOS imposes an internal limit on how many pending notification requests a single app can hold. Exceed that limit, and the system silently drops the overflow. No error. No callback. No delegate method. Notifications just stop firing. From the user's perspective, the app is broken, and there's no diagnostic breadcrumb to explain why. We implemented a hard cap of 64 pending requests. The scheduling engine tracks how many requests it has registered and stops adding more once it hits the limit. The math works out generously for a commute app: nine schedules at seven days each produces 63 notifications, just under the wire. But the cap exists because without it, a power user who creates 10 or more schedules would silently lose their oldest notifications. The kind of bug that generates one-star reviews saying "notifications randomly stopped working" with no reproducible steps for the developer. This safeguard came from a follow-up commit, after Claude and I traced through the scheduling flow and asked ourselves: "What happens at scale?" The answer was "silent failure," so we fixed it before shipping. ## Threading data forward (and the stale content bug) The persistence layer coordinates access between the main thread (where the UI lives), background refresh tasks (which iOS can wake at any time), and the notification engine (which reads and writes schedules as part of its re-scheduling flow). Three separate locks protect three separate domains: one for cached route data, one for the user's favorite routes, and one for notification schedules. Each lock is scoped to exactly one data type, which means concurrent operations on different data types don't block each other. This is unglamorous code. It will never make a conference talk. But it's the code that prevents the app from crashing when a background refresh fires while the user is in the middle of editing a schedule. Two threads touching the same data at the same instant. The kind of race condition you'd never hit during development on a single device and would hit once a week in production with thousands of users. The first version of the notification update flow had a subtle bug hiding in exactly this territory. When a background refresh completed, the system would fetch fresh routes from the network, save them to the cache, and then tell the notification engine to update its content. So far, so good. But the notification engine, when asked to update, would reach back into the persistence layer and load the user's *favorite routes* list, a separate data store from the route cache. Here's the problem: the favorites list stores route objects as they existed when the user last opened that screen. The route cache stores whatever the network just returned. A route might show a 45-minute commute in the cache (fresh from the network five seconds ago) but still show a 30-minute commute in the favorites list (from yesterday afternoon). The notification would display yesterday's travel time. The fix was surgical. Instead of having the notification engine re-read from persistence, we changed it to accept fresh route data as a parameter. The persistence layer, immediately after saving the fresh data, hands that same data directly to the notification engine. No round-trip through storage. No chance for the data to go stale between "I just saved this" and "now let me read it back." This pattern shows up repeatedly in iOS development: the gap between "data you just fetched" and "data you read back from persistence" is where bugs hide. Two sources of truth, even briefly, create a window for inconsistency. The fix is always the same: thread the data forward instead of reading it back. ## The UI: full CRUD The notification feature needed two complete screens: a schedule list and a schedule editor. ![App Screenshots](/images/blog/2026/02/travel-times-ios.jpg) The schedule list follows a familiar pattern improved by small touches. Each schedule appears as a cell modeled after Apple's own Clock app alarm interface: a large time display, a secondary line summarizing which days are active, a tertiary line showing how many routes are included, and a toggle switch on the trailing edge for quick enable/disable. Toggle switches animate the cell's text opacity, so enabled schedules are fully opaque and disabled ones fade to half transparency. It's a subtle visual cue that communicates state at a glance without requiring the user to parse the toggle itself. Swipe-to-delete includes a confirmation dialog that names the specific schedule being removed ("This will stop notifications at 7:00 AM on Weekdays"), because destructive actions should always tell you exactly what you're about to destroy. An empty state view appears when no schedules exist, complete with an explanatory message and a call-to-action button that navigates directly to the editor. The test notification button fires a sample notification after a five-second delay, giving the user time to background the app and see the banner in real conditions. The editor is a scrollable form with three sections: route selection, day selection, and time selection. Route selection presents the user's favorite routes as a list with checkmark toggles. The day picker is a custom view: seven circular buttons arranged horizontally, each representing a day of the week. Selected days fill with the app's accent color; unselected days show as outlined rings. It's roughly 100 lines of code that produces a component indistinguishable from something you'd find in a first-party Apple app. Time selection uses a standard date picker in wheel mode. Nothing custom needed. Sometimes the best UI decision is knowing when the platform's built-in component is already correct. Validation happens at save time with specific error messages. "Please select at least one route" and "Please select at least one day" are two different prompts, because telling a user "invalid input" when you know exactly what's missing is a UX failure. Every interactive element generates appropriate haptic feedback: light taps for selections and toggles, a medium pulse for saves, a success confirmation for deletions, and a warning bump for validation errors. Claude added these consistently across every action without being asked. It had internalized the existing haptic patterns from the codebase and applied them to every new interaction point by default. That kind of pattern recognition (reading hundreds of lines of existing code and extracting the implicit conventions) is where AI-assisted development adds real value. ## Background refresh: keeping notifications current The background refresh integration is what takes this from a demo feature to a production system. The app registers for periodic background refresh at a minimum interval of 15 minutes. When iOS wakes the app silently in the background, a chain of events fires: the network layer fetches fresh travel times from the API, the persistence layer caches the response, and inside the save completion handler, the notification engine re-schedules every pending notification with the updated data. This means a notification that fires at 7:00 AM on a Tuesday morning contains travel times that were refreshed within the last 15 to 30 minutes, not the stale times from when the user last opened the app three days ago. The notification tells you what your commute looks like *right now*, which is the entire point. A 25-second timeout guard ensures the app doesn't get terminated by iOS for exceeding its background execution budget. If the network call doesn't complete in time, we cancel cleanly and let the next scheduled background refresh try again. Resilience without complexity. ## Cleanup: when favorites change One edge case that's easy to overlook: what happens when a user unfavorites a route that's included in one or more notification schedules? The system handles this through cascading cleanup. Removing a favorite triggers a scan of all notification schedules. Any schedule that references the removed route has that route stripped from its list. If a schedule loses its last route (meaning it would fire notifications with no content) it's deleted entirely. The remaining schedules are then re-saved, which triggers a full re-schedule of all pending notifications. A schedule monitoring routes A, B, and C that loses route B becomes a schedule monitoring routes A and C. A schedule that loses its only route disappears. The user is never left with phantom schedules pointing at routes they no longer care about, and no orphaned notifications fire with empty content. ## Accessibility Every element of the notification UI is fully accessible. VoiceOver labels on all interactive elements describe available actions ("Double tap to toggle," "Swipe left to delete"). Dynamic Type support ensures text scales with the user's preferred size. State-aware values communicate "Selected" or "Not selected," "Enabled" or "Disabled." Full contextual labels on schedule cells read as "Enabled notification at 7:00 AM, Monday, Tuesday, Wednesday, Thursday, Friday, 3 routes." This isn't accessibility as a checkbox exercise. It's woven into every configuration method and every UI setup function from the start. Claude Code treated accessibility as a first-class concern throughout the implementation, not as a cleanup pass after the "real work" was done. The cost of building it in from the beginning was negligible. The cost of retrofitting it later would have been substantial. ## What Claude Code did Let me be specific about the human-AI collaboration here, because the nuance matters. I provided: The feature vision, the architectural constraints (programmatic UIKit, thread-safe persistence patterns, an existing design system), the quality bar (App Store submission ready, no unsafe unwraps, full accessibility), and code review at each step. Claude Code provided: The implementation across roughly 1,800 new lines and modifications to four existing files. It followed the codebase's existing conventions: design tokens for colors and typography, the established haptic feedback utility, debug-only logging guards on every print statement. It caught the stale notification content bug during review, suggested the 64-notification cap as a safeguard, and built comprehensive accessibility support without being prompted. The work landed in two commits: the initial feature implementation, and a targeted follow-up fix for the stale content and notification cap issues. That second commit is the telling one. It came from reviewing the first implementation and asking: "What are the edge cases?" The ability to iterate this quickly (implement, review, identify subtle bugs, fix) is where AI-assisted development changes the velocity of solo development. Total new code: ~1,850 lines across 4 new files + modifications to 4 existing files. One coding session. Two commits. Zero unsafe unwraps. 100% accessibility coverage on interactive elements. Three dedicated thread safety locks. Platform edge cases handled: notification cap, stale content, orphaned schedules, permission denial. ## Lessons learned Model design is leverage. The decision to reference routes by ID instead of embedding full route objects eliminated an entire category of data consistency bugs. Time spent getting the model right pays compound interest across every layer that touches it. Thread your data forward. Don't fetch data, persist it, then read it back when you need it two function calls later. Pass it through. The stale content bug existed because the "read it back" path crossed a persistence boundary. Respect platform limits. iOS's silent notification cap is poorly documented and devastating in practice. Always ask yourself: "What happens when the user does more of this than I expect?" If the answer is "silent failure," you have a bug, not a feature. Accessibility isn't a feature, it's a quality attribute. Building it in from the start costs almost nothing. Bolting it on later costs a rewrite. Treat it like type safety: something you'd never consider adding "in a future sprint." AI-assisted development is pair programming, not autopilot. I made every architectural decision. Claude executed with precision, consistency, and an awareness of the existing codebase that would take a human pair programmer days to develop. The best results came from clear constraints and iterative review, not from handing over a vague prompt and hoping for the best. The notification system shipped as part of [TravelTimes](https://traveltimesapp.com/) v8.1.0. It works exactly as designed: users schedule alerts for their commute routes, and every morning they get a notification with current travel data before they've even reached for their phone. That's what building with Claude Code looks like. Not magic. Just fast, precise, production-quality software engineering. --- ## OpenClaw and the Rise of the 'Real' AI Assistant - **Published:** 2026-02-03 - **Tags:** software-engineering, genai, side-projects, open-source - **URL:** https://vinny.dev/blog/2026-02-03-openclaw-and-rise-of-ai-assistant/ Like a lot of people, I've been closely following the recent buzz around OpenClaw, an open-source AI personal assistant that's generating real excitement in the developer community. And honestly, it makes sense. Most of us have been promised "smart assistants" for over a decade. We were told Siri, Alexa, and Google Assistant would manage our lives. Instead, we got tools that can set timers, mishear us, and occasionally turn on the wrong lights. So when something like OpenClaw shows up promising a truly capable personal AI agent, people pay attention. Over the past few weeks, I've been running OpenClaw at home. My honest assessment: it's very early-stage software, not ready for most people to use safely. But the potential here is enormous. ## What is OpenClaw, really? At its core, OpenClaw is a persistent AI agent that runs as a background service on your machine. Once installed, it operates continuously, maintaining long-term memory and context. It can connect to large language models from providers like Anthropic, OpenAI, and Google, as well as locally hosted models. But this isn't just "ChatGPT with a wrapper." OpenClaw can access your file system, execute shell commands, browse the web, call APIs, read your email, and trigger automation tools. It doesn't just talk. It sees. It remembers. And it acts. ![OpenClaw Architecture](/images/blog/2026/02/openclaw-architecture.png) *OpenClaw sits at the center, connecting to LLM providers, your file system, shell, browser, APIs, and messaging platforms.* The key differentiator is persistence. Your sessions don't disappear when you close a window. The agent keeps context over time, learns your environment, understands patterns, and builds continuity. That's the difference between a chatbot and a digital coworker. ```yaml # Example OpenClaw configuration (simplified) agent: persistence: true memory_store: local providers: - name: anthropic model: claude-sonnet-4-20250514 api_key: ${ANTHROPIC_API_KEY} integrations: filesystem: enabled: true sandboxed: true allowed_paths: - ~/projects - ~/documents messaging: telegram: enabled: true webhook_url: ${TELEGRAM_WEBHOOK} ``` ## What I tried Over two weeks, I tested OpenClaw on practical workflows. I had it monitor a project folder and summarize changes daily. I used it to draft commit messages based on diffs. I tested the Telegram integration for remote file lookups while away from my desk. The results were inconsistent but occasionally impressive. When it worked, it felt like having a junior developer who never sleeps. When it didn't, it reminded me why we're still in the early innings of this technology. ## From assistant to autonomous agent Where things get even more interesting (and more concerning) is OpenClaw's ability to integrate with messaging platforms like WhatsApp, Telegram, and Signal. With the right configuration, you can message your assistant remotely and trigger actions. Imagine this: you're away from home, you send a message, and your AI agent turns on lights, checks files, runs scripts, or initiates workflows. You're no longer "using" software. You're delegating to it. At that point, OpenClaw stops being a tool and starts becoming an autonomous agent. That's incredibly powerful. It's also dangerous. ## Power comes with real risk Giving software deep access to your system, data, and communication channels is not a trivial decision. OpenClaw can read sensitive files, execute system commands, access private communications, and trigger automated actions. If something goes wrong (whether through a bug, misinterpretation, or malicious prompt) the consequences could be real. Right now, major questions remain unanswered around security boundaries, permission models, auditability, data governance, abuse prevention, and failure modes. Because of that, I would strongly caution against running this on your primary personal machine. If you want to experiment, do it in a sandbox. Use a separate device. Keep personal and financial data out of reach. Understand exactly what you're enabling. This is not plug-and-play consumer software yet. This is experimental infrastructure. Treat it that way. ## Why this still matters With all that caution, you might wonder why I'm excited about this at all. Because OpenClaw shows us what's coming. For the first time, we're seeing practical demonstrations of what happens when you combine large language models with long-term memory, giving the agent continuity across sessions and the ability to learn your patterns. Add tool access, and it can do things in the real world, not just talk about them. Layer in automation and messaging interfaces, and suddenly you can delegate tasks remotely. Wrap it all in a persistent identity, and you have something that feels less like software and more like a collaborator. | Capability | Traditional Assistants | Agent-Based Assistants | |------------|----------------------|------------------------| | Persistence | Session-based, context lost | Continuous, maintains history | | Memory | Minimal, starts fresh | Long-term context retention | | Actions | Predefined skills only | Arbitrary tool access | | Integration | Walled garden ecosystems | Open APIs and local tools | | Autonomy | Reactive to commands | Proactive capable | That combination creates something fundamentally new. Not a chatbot. Not a search engine. Not a voice assistant. A true digital agent. Once people experience that, there's no going back. The question is no longer "Will this exist?" It's "Who will build it responsibly?" ## A path forward: enterprise-grade agents I've been a big fan of Claude Code and have enjoyed watching its evolution, especially with the emergence of Claude Cowork. What excites me is the possibility that companies like Anthropic can take the raw ideas being explored in projects like OpenClaw and bring them into secure, governed, enterprise-grade environments. Imagine strong permission models with transparent audit logs. Sandboxed execution with human-in-the-loop controls. Compliance by design with safety-first defaults. That's how this becomes trustworthy. That's how it becomes scalable. That's how it becomes something people can rely on, not fear. OpenClaw today is rough, unstable, risky, and unfinished. But it's also a preview. It's a glimpse into a future where AI doesn't just answer questions. It collaborates. It remembers. It executes. It operates alongside us. We are moving from "AI as a tool" to "AI as a partner." That transition will be messy. It will create new risks. It will force new governance models. It will demand better engineering discipline. But it's coming. And projects like OpenClaw are showing us what that future might look like, for better and for worse. If you're curious, explore carefully. If you're building, build responsibly. If you're leading, start thinking now about what this means for your organization. The first generation of real AI assistants is here. They're clumsy. They're dangerous. They're incomplete. And they're going to change everything. --- ## The Open Source Paradox AI Created - **Published:** 2026-01-11 - **Tags:** software-engineering, genai, open-source - **URL:** https://vinny.dev/blog/2026-01-11-the-open-source-paradox-ai-created/ In early January 2026, Tailwind Labs, the company behind Tailwind CSS, made headlines after co-founder Adam Wathan shared that the company laid off 75% of its engineering team. In absolute terms, that meant going from four engineers to one. Small numbers. Big implications. This was not a story about product failure. Quite the opposite. It was a signal that Generative AI has fundamentally altered the economics of certain open-source business models, even as the underlying software becomes more popular than ever. ## Popularity without sustainability Tailwind CSS is arguably at the height of its influence. It reportedly exceeds 75 million monthly downloads and is used by roughly 51% of developers worldwide. By traditional open-source standards, that is overwhelming success. And yet, revenue dropped by approximately 80%. This is the paradox AI has introduced. Adoption is rising. Usage is exploding. But the mechanisms that once converted usage into sustainable funding have collapsed. The problem is not relevance. It is funnel collapse. Historically, Tailwind's documentation served as the primary discovery channel for its paid products, including premium UI kits and tooling. Today, developers increasingly bypass documentation entirely. With GenAI tools, they generate Tailwind-compatible code and UI patterns directly, often without ever visiting the project's site. Reported traffic declined by roughly 40%, and premium offerings shifted from essential to optional. This is not unique to Tailwind. It is a structural change in how knowledge is consumed. ## Value creation vs. value extraction At the heart of this shift is a growing imbalance between value creation and value extraction. Open-source projects like Tailwind create immense public value. They embody thousands of design decisions, best practices, and hard-won lessons accumulated over years. Generative AI systems now ingest that value at scale, synthesize it, and deliver it instantly to users. The result is remarkable productivity. It is also a broken economic loop. The creators remain responsible for maintenance, security, and evolution. The economic upside increasingly accrues elsewhere. This same tension is now visible beyond software. Artists, writers, and other content creators are suing AI companies over copyright and training practices. While the legal arguments vary, the underlying issue is consistent: value is absorbed upstream at scale, while the people who created it struggle to sustain their work. Different domains. Same incentive failure. ## Open source as critical infrastructure For those building modern software systems, this is not an abstract concern. It is a supply-chain risk. Open-source frameworks and libraries are not interchangeable commodities. They represent accumulated judgment, shared security standards, and collective problem-solving. They function more like public infrastructure than optional tooling. Frameworks and libraries were a human solution to human complexity. If we allow them to wither in favor of ever-more efficient AI generation, we risk losing more than convenience. We risk eroding the foundations that make innovation possible. History offers a familiar lesson. Infrastructure that is widely used but poorly funded eventually degrades. Roads crack. Bridges fail. Software is no different. ## The limits of "content as a funnel" Many open-source companies rely on documentation, examples, and educational content as their primary funnel to paid offerings. GenAI quietly breaks that model. When AI systems summarize, remix, and deliver knowledge directly, traffic disappears. Discovery shifts. Monetization assumptions fail. The content still creates value, but it no longer creates leverage for the creator. Any business model built on "content as a funnel" should be reassessed under this new reality. This does not mean open source disappears. But it does mean that legacy funding models will not survive unchanged. ## Toward a new social contract The open-source ecosystem did not emerge by accident. It thrived because incentives aligned. Contributors gained reputation, employment, or funding. Companies invested because the returns were clear. Generative AI breaks that alignment. If AI platforms continue to harvest open-source value without reinvesting in its creation, the incentives to build the next Tailwind, the next React, or the next foundational library will erode. This is not primarily a legal question. It is a policy and governance challenge. Possible paths forward include: - Licensing models that explicitly address AI training and derivative use - Revenue-sharing or usage-based compensation for foundational projects - Public or industry-funded support for critical open-source infrastructure - Clear norms around attribution, reinvestment, and stewardship in AI systems None of these solutions are simple. All are preferable to ignoring the problem. Open source will not vanish. But the economic assumptions that sustained it for decades are no longer safe. Generative AI has exposed a paradox at the heart of modern software. We are extracting more value than ever from open-source ecosystems while investing less in their long-term viability. The question is not whether AI should exist. It is whether we are willing to design incentive structures that allow the foundations of innovation to endure. What would a new social contract between AI platforms and open-source communities look like? --- ## References & further reading - Adam Wathan, comments on Tailwind Labs layoffs (January 2026) https://x.com/adamwathan - Nadia Eghbal, *Working in Public: The Making and Maintenance of Open Source Software* https://press.stripe.com/working-in-public - Electronic Frontier Foundation, *AI Training, Fair Use, and the Commons* https://www.eff.org/issues/ai - U.S. Copyright Office, *Copyright and Artificial Intelligence* (2023-2024) https://www.copyright.gov/ai/ - Bruce Perens, writings on open-source sustainability https://web.archive.org/web/2024/https://perens.com/ --- ## Building StillView 3.0: Raising the Quality Bar with Claude Code and Opus 4.5 - **Published:** 2026-01-03 - **Tags:** software-engineering, genai, claude-code - **URL:** https://vinny.dev/blog/2026-01-03-opus45-thinking-partner/ At some point, every side project crosses an invisible line. It still works. Features keep shipping. Tests pass. But something feels off. Changes take longer. Small edits create surprising side effects. You hesitate before touching certain files, not because they are hard in a productive way, but because you are no longer confident you fully understand them. That was [StillView](https://stillviewapp.com/). Not broken. Not failing. Just quietly accumulating risk. StillView began as a simple macOS image viewer, built for speed and focus. Over time, convenience won. Magic numbers crept in. Placeholder implementations overstayed their welcome. Methods accumulated responsibilities because it was faster to add "one more thing" than to stop and rethink structure. Nothing was catastrophic. But the codebase had crossed a threshold where intuition alone was no longer reliable. StillView 3.0 was about resetting that trajectory. ## The problem wasn't speed. It was confidence This was not about writing code faster. The real issue was trust. There were parts of the app where I could no longer say, with confidence, *why* something worked. Refactors succeeded but felt brittle. Bug fixes landed, followed by a quiet question: *what else did this destabilize?* That uncertainty is expensive. It slows every future decision. I needed a way to slow down without stalling, to reason more deliberately, and to surface design debt before it hardened further. That is where Claude Code and Opus 4.5 became interesting. As StillView matured, I wanted to go beyond basic viewing and introduce lightweight AI insights that added real value, while staying true to the app's performance and privacy principles, which led me to Apple's on-device ResNet-50 model. ## On-device intelligence with Apple's ResNet-50 In StillView 3.0, that enrichment takes the form of on-device image classification, implemented using Apple's ResNet-50 model. Classification happens entirely on device. No images, metadata, or user data ever leave the machine. That was a non-negotiable requirement from day one. Apple provides ResNet-50 models converted to Core ML, allowing them to run efficiently on the Neural Engine. The result is fast, low-latency inference that feels instantaneous, without the privacy or reliability tradeoffs of cloud-based calls. This choice reflects a broader principle in StillView: push intelligence as close to the user as possible, maximize performance, and treat privacy as a first-class constraint, not a feature toggle. ## Opus 4.5 as a thinking partner Claude Code with Opus 4.5 did not behave like an autocomplete engine. It behaved like a careful senior engineer joining the project for the first time, skeptical of legacy decisions and unimpressed by historical convenience. It questioned unclear abstractions. It flagged methods doing too much. It asked why responsibilities lived where they did. More importantly, it forced articulation. Any time I struggled to clearly justify a design decision, that friction usually pointed to a real problem. In that sense, Opus was not writing code for me. It was exposing where my reasoning lacked clarity. The value was not speed. It was pressure applied to my thinking. ## A necessary disagreement: enforcing my own standards This partnership was not frictionless. One recurring issue was that Opus did not automatically internalize my [design and coding standards](https://github.com/vscarpenter/SimpleImageViewer/blob/main/coding-standards.md). These standards cover naming, architectural boundaries, and the principles I expect the codebase to honor. I had to repeatedly prompt the model to apply them. At first, this felt like a failure. Why should I restate rules I had already written down? Then the lesson became obvious. AI does not replace intent. It amplifies it, but only when that intent is made explicit. Once I consistently grounded Opus in those standards, the quality improved dramatically. Refactors aligned with the architecture. Suggestions respected constraints. The output felt native to the codebase, not imported from somewhere else. Judgment still mattered. Leadership still mattered. Even in code. ## What changed in StillView 3.0 The result was not flashy. StillView 3.0 is quieter than previous versions, by design. - Responsibilities are explicit. - Boundaries are sharper. - Refactors are easier to reason about. - Changes feel safer. The app improved, but more importantly, my relationship with the codebase did. I trust it again. AI did not replace my judgment. It demanded more of it. Claude Code and Opus 4.5 worked best when treated as thinking partners, not tools. When I showed up with clear intent, explicit standards, and a willingness to be challenged, the quality bar rose naturally. Clean code is not a style preference. It is a confidence strategy. And for StillView, that made all the difference. --- **Try StillView** If you are looking for a fast, focused image viewer for macOS, StillView is available on the [Apple App Store](https://apps.apple.com/us/app/stillview-image-viewer/id6749210445?mt=12) --- ## Getting Better at Getting Better in 2026 - **Published:** 2025-12-31 - **Tags:** engineering-leadership, software-engineering, learning - **URL:** https://vinny.dev/blog/2025-12-31-getting-better-at-getting-better-in-2026/ As we head into 2026, I'm watching a familiar cycle begin: big resolutions, elaborate plans, and promises of transformation that often fade by February. After years of leading engineering teams and working on my own growth, I've learned something simple and inconvenient: the most meaningful change rarely comes from dramatic gestures. It comes from building systems that make improvement unavoidable. ![The secret is there is no secret](/images/blog/2025/12/no-secrets.png) *Figure 1: Consistency over intensity. Progress over perfection.* ## Systems beat surges James Clear talks about this in *Atomic Habits*: improve just 1% each day and you're 37 times better after a year. Helpful, but incomplete. What really compounds is something deeper: getting better at getting better. It's the difference between a one-off win and a durable capability. - The engineer who doesn't just fix a bug, but improves the test suite. - The leader who doesn't just have better 1:1s, but builds a culture where feedback flows without friction. - The team that doesn't just solve problems, but sharpens how it solves them. In engineering terms, outcomes are the feature. Systems are the platform. ## Meta-improvement: the compounding advantage A single improvement is valuable. A system that *produces improvements* is powerful. Meta-improvement is the practice of investing in your ability to improve. It means treating learning, feedback, and iteration as part of the operating model, not as a side project. This can look like: - Reducing the cost of feedback (faster signals, tighter loops) - Making the "right thing" the default ([guardrails, automation, standards](https://vinny.dev/blog/2026-03-26-pipeline-first-culture-shift/)) - Capturing lessons as reusable assets (runbooks, templates, shared patterns) - Designing work so improvement happens during delivery (not after) When you do this consistently, progress stops being dependent on motivation. It becomes a byproduct of how you work. ## Kaizen, not as a slogan This is the heart of *kaizen* in Toyota's philosophy: not improvement as an event, but improvement as a discipline woven into daily work. It's not always exciting. It's rarely glamorous. But it is effective. We're constantly tempted by the new framework, the trendy methodology, and the latest productivity hack. Those can help. Sometimes they even matter. But what transforms individuals, teams, and organizations is far less dramatic: - Consistency over intensity - Progress over perfection - Fundamentals over fads Over and over again. ## What I'm focused on in 2026 This year, I'm not just chasing better outcomes. I'm investing in better systems for improvement. I want improvement to be the default behavior, not something I have to summon through willpower. ### A question for you What's one small system or habit you're putting in place to improve *how you improve* in 2026? --- ## The New Abstraction Layer: AI, Agents, and the Leverage Moving Up the Stack - **Published:** 2025-12-30 - **Tags:** genai, software-engineering, productivity, ai-coding - **URL:** https://vinny.dev/blog/2025-12-30-ai-abstraction-layer/ Andrej Karpathy, computer scientist, AI educator, OpenAI founding member, and former Senior Director of AI at Tesla, put words to something many engineers are quietly feeling right now. ![Andrej Karpathy put words to something many engineers are quietly feeling right now](/images/blog/2025/12/IMG_3540.png) He says he's never felt more behind as a programmer, yet believes he could be 10x more productive if he fully used what's emerged over the past year. Not doing so, in his words, starts to look like a skill issue. That tension is the moment we're in. ## A new layer of abstraction The profession isn't just adding new tools. It's absorbing a new layer of abstraction: agents, prompts, context, memory, MCP, and workflows. Engineers now have to build intuition for systems that are inherently stochastic and fallible, operating alongside the deterministic engineering many of us grew up on. His metaphor lands hard. We've been handed a powerful alien tool with no manual, and we're all learning how to use it in real time. His advice is simple: roll up your sleeves to not fall behind. That resonates. ## Rolling up my sleeves Between exploring Claude Code, Cursor, Kiro, and MCP-driven integrations, I'm firmly in the roll-up-your-sleeves camp. Much of my recent thinking and writing reflects this shift, from treating AI as a feature to designing agentic workflows that change how work actually gets done. This isn't about abandoning good engineering. It's about recognizing that the leverage has moved up the stack. ## The question So here's the question I'm wrestling with. Which parts of this new layer are you deliberately investing in learning, and which are you choosing to ignore for now? *Originally shared on [LinkedIn](https://www.linkedin.com/posts/vinnycarpenter_andrej-karpathy-computer-scientist-ai-educator-activity-7411978248407965696-Jn3E/)* --- ## The Year Ahead in AI, Enterprise Software, and the Future of Work - **Published:** 2025-12-20 - **Tags:** genai, software-engineering, productivity, ai-coding - **URL:** https://vinny.dev/blog/2025-12-20-year-ahead-in-ai-future-of-work/ ## The Year Ahead in AI, Enterprise Software, and the Future of Work 2025 has been the year we stopped debating whether generative AI matters and started living with it. We moved beyond simple autocomplete and clever demos. We began to see AI as a partner, something that thinks, generates, and in some cases acts across workflows, not just responds to prompts. That shift from tool to partner is where the real value begins. This moment feels familiar. Every major technology shift follows a similar arc. Automation reshapes work, replaces old models, and creates new opportunities we cannot fully define at the outset. That process has a name: creative destruction. AI is simply the latest, and perhaps most consequential, chapter. ## From experimentation to real systems Over the past year, many teams crossed an important threshold. We saw a move from curiosity-driven experimentation to the construction of real agentic systems, systems that execute tasks with context, memory, and intent. Developers started running increasingly capable models locally on their laptops, optimizing for privacy, speed, and control. Perhaps most importantly, we shifted away from chaotic prompt tinkering toward something more durable: spec-driven engineering. Structured workflows. Agentic IDEs. Disciplined iteration. Clear interfaces between humans and machines. The lesson is simple but powerful. AI is not replacing work. It is transforming how work happens. The future belongs to teams and leaders who treat AI as a strategic delivery partner, not just another gadget in the toolbox. ## What excites me most about 2026 As I look ahead, three themes stand out. ### 1. Enterprise software, reimagined We are entering an era where AI is embedded at the workflow level, not bolted on as a feature or an assistant panel. The next generation of enterprise platforms will use AI as the default interface. They will anticipate needs, enforce context, and automate outcomes end to end. Organizations still layering AI on top of legacy user experiences will struggle to keep up. ### 2. "Human in the loop" becomes a discipline Routine work will continue to disappear. What grows in importance are roles where humans define why something should be done, what success looks like, and how outcomes should be stewarded. The combination of human judgment and AI execution is a genuine superpower, but only if it is designed intentionally. Human-in-the-loop is not a checkbox. It is a craft. ### 3. Autonomy with accountability Here is a less popular take. Teams that slow down to build governance, guardrails, and oversight will outperform those chasing speed alone. As AI agents gain autonomy, thoughtful accountability becomes a competitive advantage, not a bottleneck. In the long run, trust compounds faster than velocity. If you are building or leading teams right now, focus on learning systems and tight feedback loops. Measure outcomes, not activity. Resist the temptation to adopt every shiny tool. The winners in 2026 will not be the teams that used AI the most. They will be the teams that built with it in disciplined, intentional ways. What is your team betting on for 2026? I would love to hear what patterns you are seeing. --- ## Frontier Models, Small Language Models, and a New Middle Path - **Published:** 2025-12-04 - **Tags:** genai, software-engineering, aws, cloud - **URL:** https://vinny.dev/blog/2025-12-04-frontier-models-small-language-models-aws-nova/ The most strategic AI decision isn't choosing the right model. It's knowing when generic intelligence isn't enough. Over the past year, the AI ecosystem has organized into two camps. Frontier foundation models like GPT-5, Claude Sonnet 4.5, and Gemini 3 are broad generalists. They reason, plan, analyze, code, and adapt across countless domains. They shine when the task is ambiguous, complex, or requires deep creativity. Small Language Models (SLMs) are built for speed, scale, and repeatability. They excel at focused tasks like classification, compliance checks, or domain-specific automation. They don't try to do everything. They do one thing extremely well. Neither is "better." They serve different purposes. The real power comes from using the right model for the right job. ## Then AWS introduced something new at re:Invent Amazon announced Nova Forge, a service that bridges off-the-shelf models and fully custom enterprise-trained models. Here's what caught my attention: building a frontier model from scratch typically costs hundreds of millions (sometimes billions) of dollars. Nova Forge starts at roughly $100K per year. With Nova Forge, organizations can: - Start from Nova model checkpoints (pre-trained, mid-trained, or post-trained) - Blend proprietary data with Amazon's curated training corpus - Preserve general intelligence while infusing deep institutional knowledge The result? Your own "Novella," a custom frontier model shaped by your business, not just prompted by it. ## Why this matters Nova Forge represents a shift from *consuming* AI to *owning* a specialized slice of it. It's ideal for use cases where even powerful generic models fall short, where you need deep industry terminology, regulatory frameworks, or your organization's unique institutional knowledge baked in at the training level. This is a strategic middle ground: you avoid the cost and complexity of training from scratch, while gaining far more capability than fine-tuning or RAG alone. ## The bigger shift The key question for leaders is no longer "Which model will win?" It's now: "Which model architecture best fits this specific use case, cost structure, and risk profile?" Sometimes the answer is a lightweight specialist. Sometimes it's a broad frontier model. And increasingly, the right answer may be a custom frontier model trained with Nova Forge and tuned to your domain. That changes competitive advantage. It changes the value of enterprise data. And it changes who gets to define the next generation of intelligent systems. We're entering a phase where winning won't come from simply *using* models. It will come from *shaping* intelligence that reflects your domain. Where do you see the biggest opportunity for domain-specific frontier models in your industry? --- *Also shared on [LinkedIn](https://www.linkedin.com/posts/vinnycarpenter_genai-machinelearning-cloudcomputing-share-7402529196025245696-ckec)* --- ## My Journey to Trusting GenAI With More of My Code - **Published:** 2025-11-15 - **Tags:** genai, software-engineering, productivity, ai-coding - **URL:** https://vinny.dev/blog/2025-11-15-journey-with-trusting-genai-and-coding-workflow/ Over the past few years, my development workflow has gone through a quiet but profound shift. It did not happen all at once, and it did not follow a carefully designed plan. It evolved the way most good engineering habits do: a lot of experimentation, a few guardrails, some hard lessons, and the occasional moment of wondering when this new normal became so normal. What started as a fun experiment with early GitHub Copilot has turned into a completely different way of building software. ## From autocomplete to something smarter When Copilot first arrived in beta, it felt like autocomplete with personality. Helpful, playful, sometimes uncanny, but still an assistant. It could finish a function or guess the next few lines, but you would never mistake it for a co developer. It was a spark of what might be possible, not a partner. Then the models got better. Fast. ## The shift from coding to specifying Somewhere along the way, I noticed I was writing fewer lines of implementation code, not because I was coding less but because I was coding differently. I started spending more of my time writing tests, defining interfaces, describing expected behavior, and validating outcomes. I moved upstream in the thought process. Instead of asking how to implement something, I focused on how I wanted it to behave. The implementation came second. Bit by bit, the act of writing code shifted into the act of defining intent. GenAI could take a well specified feature and generate a solid first draft of both the implementation and the tests. My job became more about shaping that intent and less about typing the logic. And honestly, the transition felt natural. ## A meaningful threshold Recently, it hit me that I have crossed a real trust threshold. My workflows, guardrails, and instructions are now tuned enough that I am confident in the quality of the generated code and the testing structure behind it. It is not blind confidence. It is a healthy trust backed by verification. For example, I now begin every feature with a test specification and clear acceptance criteria. Only after those are locked in do I ask the model to generate an implementation. The discipline of starting from the tests has made a significant difference in the predictability and correctness of the output. I still review everything. I still refactor. I still catch mistakes. But the overall quality and consistency have reached a point where the trust is real, and the productivity gains are undeniable. ## The pivot to spec driven development Looking at the bigger picture, the most important change has been the move from vibe coding to spec driven development. Vibe coding is that creative, exploratory style where you start writing code and figure it out as you go. It is fun, but it does not scale well with GenAI. Spec driven development, on the other hand, plays to the strengths of these models. When the constraints are clear, the inputs and outputs are defined, and the acceptance criteria are unambiguous, the model can produce remarkably trustworthy code. It is predictable, it is consistent, and it is easier to validate. The surprising part is that the discipline required for spec driven development has made me a better engineer too. The clarity I need to give the model forces clarity in my own thinking. ## Why this matters We are stepping into an era where developers act more like architects, testers, and system designers. The models write the first draft. The humans ensure it is correct, safe, scalable, and consistent with the broader architecture. This shift is not about outsourcing our work. It is about improving it. Instead of spending energy on boilerplate, syntax, and repetitive logic, we can focus on higher level design, testing rigor, and the strategic aspects of building systems. ## The trust but verify spectrum Engineers fall across a wide spectrum in their comfort with GenAI generated code. Some do not trust any of it and review every token. Some trust it for small tasks but not for anything critical. Some let it generate entire files and only step in when tests fail. Some run fully automated flows with human review near the end. There is no correct position. There is only progress. Wherever you are today, you likely were not in that same place six months ago. And you will not be in the same place six months from now. The tools evolve. Our skills evolve. Our guardrails evolve. ## What I'm curious about I would love to hear how others are navigating this shift. - Where are you on the trust but verify spectrum? - What guardrails, tests, workflows, or design patterns have helped you lean into GenAI with confidence? - How have your instructions or prompting style changed over time? - Are you writing more tests? More specs? Fewer lines of code? This is a shared evolution, and the more we compare notes, the faster we learn. GenAI did not take away my coding. It changed it. I still build. I still design. I still debug. I just do it with a different set of tools and a different mindset. And I would not want to go back. --- **Also published on [LinkedIn](https://www.linkedin.com/posts/vinnycarpenter_%F0%9D%97%A0%F0%9D%98%86-%F0%9D%97%9D%F0%9D%97%BC%F0%9D%98%82%F0%9D%97%BF%F0%9D%97%BB%F0%9D%97%B2%F0%9D%98%86-%F0%9D%98%81%F0%9D%97%BC-%F0%9D%97%A7%F0%9D%97%BF%F0%9D%98%82%F0%9D%98%80%F0%9D%98%81%F0%9D%97%B6%F0%9D%97%BB%F0%9D%97%B4-activity-7395490903798243329--T7t/?utm_source=share)** --- ## When Winning Teams Lose: A Ferrari Leadership Lesson - **Published:** 2025-11-13 - **Tags:** engineering-leadership, software-engineering, formula1 - **URL:** https://vinny.dev/blog/2025-11-13-f1-ferrari-leadership-lesson/ ## When Winning Teams Lose: A Ferrari Leadership Lesson John Elkann, Chairman of Ferrari, recently made waves with his comments about the F1 team's performance. He opened with praise for the mechanics ("winning the championship with their pit stop performances") and engineers ("the car has undoubtedly improved"). Then came the sharp turn: "We have drivers who need to focus more and talk less." That single line reveals everything wrong with Ferrari's leadership culture. It is a masterclass in what *not* to do. ![Lewis Hamilton and Charles Leclerc](/images/blog/2025/11/ferrari-drivers.jpg) ## The pattern is clear Ferrari has one of the largest budgets in F1, world-class facilities in Maranello, and a driver lineup featuring Lewis Hamilton and Charles Leclerc. Yet the team hasn't won a Constructors' Championship since 2008 or a Drivers' Championship since 2007. Nearly two decades of underperformance with enormous resources is not a driver problem. It is a leadership and culture problem. ## What Ferrari gets wrong - Blame flows downward Praising the mechanics while publicly criticizing the drivers deflects accountability from leadership. - Image over improvement Telling drivers to "talk less" protects the brand instead of inviting real problem-solving. - Silencing feedback When leaders discourage dialogue, issues do not disappear, they deepen. - Politics above performance Internal positioning becomes more important than winning. ## What real leadership looks like - Own the failures Accountability starts at the top. - Welcome hard truths Psychological safety fuels stronger decisions. - Progress over perfection You cannot fix what you refuse to face. - Accountability flows upward Celebrate your team's wins. Own the losses yourself. ## Beyond Ferrari: lessons for engineering teams In engineering organizations, the temptation is similar. When outcomes fall short, it is easy to point at execution when the real challenges often sit in strategy, culture, or leadership choices. Sustainable success comes from self-awareness, honest reflection, and leaders willing to look in the mirror first. I'm fortunate to work with colleagues and leaders who strive to build exactly that kind of environment. It makes all the difference. Ferrari has the talent and the resources. What it needs is leadership that listens instead of silencing, learns instead of deflecting, and builds culture instead of guarding image. Teams win championships, in F1 and in technology, when leadership creates an environment of trust, accountability, and continuous learning. What leadership anti-patterns have you seen hold teams back from their potential? --- Continue the conversation on [LinkedIn](https://www.linkedin.com/posts/vinnycarpenter_leadership-engineeringleadership-culture-activity-7394538576178442240-SgdD?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAAMPBgBfbBH6Q-lntjTWCdKSP-iU9Wex3A) --- ## The Rise of MCP Servers: Why Every Developer Will Have a Personal AI Toolchain - **Published:** 2025-11-01 - **Tags:** open-source, software-engineering, genai, agentic-sdlc - **URL:** https://vinny.dev/blog/2025-11-01-the-rise-of-mcp-servers/ If you've been paying attention to the *Model Context Protocol* world lately, you've probably noticed the same trend I have: suddenly every vendor, every open-source project, every platform team is shipping an MCP server. This isn't a coincidence. It's a shift. And just like Docker in 2013 or GitHub Actions in 2019, we're early enough to feel the energy but late enough to know this is not a fad. ### A new layer in the dev stack The idea behind MCP is simple, a standard way for AI agents and IDE-integrated assistants to talk to tools, services, APIs, docs, CLIs, and infra, without writing glue code, wrapping SDKs, or duct-taping local scripts together. Instead of your editor "knowing about AWS," you run an MCP server that exposes AWS actions. Instead of your AI agent hallucinating how to fix a Dockerfile, it literally asks the Docker MCP server. That means: - No more embedding secrets or tokens inside prompts - No more "copy this JSON from the console into ChatGPT" workflows - No more AI tools guessing. They *execute* AI stops being an autocomplete engine and starts behaving like a teammate that can run code, read docs, take actions, and reason with context. ### My local MCP stack Here's what's currently running in my personal dev environment: ![MCP servers screenshot](/images/blog/2025/11/claude-code-mcp-server.png) That's not a toy setup. That's my daily workflow. - `aws-core` gives my AI assistant real-time insight into AWS services, infra, config, and deployments - `aws-documentation` eliminates "what's the API for X again?" Google searches - `github` lets me query PRs, issues, branches, test runs - `next-devtools` integrates with local Next.js projects so I can refactor or debug with conversational commands - `podman` gives container-level visibility and control - `playwright` means "write me a test" turns into an *actual file*, not a suggestion And all of it runs locally, not through a vendor cloud. That's a very different world from the one we lived in 18 months ago, where AI tools were mostly text predictors dressed up as copilots. ### From "chat about code" to "operate the system" Before MCP, AI tools were like a junior dev who could explain things well but wasn't allowed to log into production or touch a shell. Lots of talk, limited action. Now? They're becoming operators. - Ask "what Lambdas were deployed last week?" → it runs an AWS query - Ask "write an integration test for this API route" → it generates, validates, runs, and fixes - Ask "clean up dangling containers and volumes" → Podman server handles it The line between *developer* and *developer-plus-agent* is getting blurry. The dream isn't "AI replacing engineers," it's engineers spending less time clicking and more time creating. ### The implications - Every SaaS tool will ship an MCP server - Every platform team will build internal MCP endpoints - Every IDE will become "AI-native" by speaking MCP - Every dev will eventually have a personal AI runtime environment, just like we all ended up with Homebrew, Git, Docker, and a password manager The real change is not that AI can *read* your code but that it can act on your environment with the same privileges you have, with guardrails you define. This is the shift from "AI as a chat tab" to "AI as part of the operating system." ## A quick reality check: security isn't fully solved yet Of course, anytime a new layer gets added to the developer stack (especially one that can execute real actions against cloud resources, source control, and production systems), the security folks start sweating. And right now, they're not wrong. MCP servers are still early in how they handle: - Auth and permission scoping (most are running with full trust, not least privilege) - Secret management and token handling (too many `.env` files, not enough vaults) - Auditability and action logging (great for devs, uncomfortable for compliance teams) - Cross-tool privilege escalation (an MCP server that can call another MCP server has real blast-radius potential) We're in the "ssh into prod with a shared key" phase of the curve, not the "Zero Trust, signed identity, fine-grained RBAC" phase. But that will come fast, because the productivity upside is too massive, and nobody wants to be the company that blocks developers from using the tooling every other team already has. Expect to see: - Enterprise-grade MCP gateways and policy engines - Vault-backed credential injection instead of static tokens - Explicit capability whitelisting ("can read PR metadata but can't merge branches") - Per-user audit logs and just-in-time permissioning - Cloud providers baking MCP into IAM instead of treating it as an add-on In other words, security will catch up because the demand is unavoidable. Once teams see what it feels like to have an AI agent that can *actually* query infrastructure, fix pipelines, refactor code, and open PRs, nobody will want to go back. We're watching the next interface layer of software take shape in real time, and yes, it's messy, but it's also the most exciting shift in developer tooling since GitHub, Docker, and LSPs. And just like those, it's going to feel obvious in hindsight. ### So what happens next? - Companies will publish *MCP packages* the same way they publish NPM modules - Devs will start curating "MCP stacks" the same way we build dotfiles or Neovim configs - AI tools will stop hallucinating because they'll have real context, real APIs, real execution - The default answer to "Can AI do that yet?" will switch from "Not really" to "Yeah, install the server" And just like Docker Compose rewired how teams collaborate on infra, MCP might end up being the thing that rewires how we collaborate with AI. We're not replacing developers. We're finally giving them superpowers. *Update, April 2026: this thread grew into [the agentic SDLC](https://vinny.dev/blog/2026-04-15-agentic-sdlc-uniting-ai-tool-sprawl/), where MCP-style tool access becomes one layer of an orchestrated pipeline.* --- ## From Procrastination to Privacy-First Productivity (Part 2) - **Published:** 2025-10-26 - **Tags:** productivity, open-source, software-engineering, genai, agentic-sdlc - **URL:** https://vinny.dev/blog/2025-10-26-task-management-to-mcp/ A while back, I wrote about my long-running battle with procrastination and my endless quest for *the perfect productivity app*. After testing nearly every tool under the sun, I did what any reasonable engineer would do. I built my own. That's how [Cascade](https://cascade.vinny.dev) and [GSD Task Manager](https://gsd.vinny.dev) were born: two open-source, privacy-first task managers that run entirely in your browser. No accounts, no tracking, no data harvesting. Your tasks never leave your device: they're stored locally using your browser's IndexedDB. Lightweight, fast, and private by design. But of course, no good side project stays simple for long. One of the most popular feature requests was syncing across devices. So, I built an optional, secure-by-design cloud sync powered by Cloudflare Workers. It stays true to the original principles: privacy, simplicity, and transparency. Under the hood, GSD Task Manager uses OAuth 2.0 with OpenID Connect (OIDC) for authentication and PKCE (Proof Key for Code Exchange) to protect the authorization flow. Everything runs on a zero-trust architecture, with user data encrypted using passphrase-derived keys, meaning *you* hold the keys, not me. TL;DR (for non-tech folks): Your data stays private and secure. You can sync your tasks safely between devices without giving up control of your information. And because I can't stop tinkering, the next most-requested feature was support for an MCP Server, the Model Context Protocol that lets AI tools like ChatGPT or Claude securely connect to external data sources. Folks wanted to query their tasks and metadata through AI tools for deeper insights, analysis, and automation. So, I built that too. GSD Task Manager now ships with an MCP Server, letting your tasks talk to your favorite AI assistant. ### Acronym decoder for the rest of us Let's be honest, tech folks love acronyms. Here's a quick cheat sheet so you don't need a decoder ring: - OAuth 2.0: a fancy way of saying "log in safely without giving away your password." Think of it as a secure valet key for your data. - OIDC (OpenID Connect): the protocol that remembers *who* you are, not just *that* you got in. It's OAuth's responsible older sibling. - PKCE (Proof Key for Code Exchange): a security handshake that prevents sneaky hackers from stealing your login ticket mid-air. - MCP (Model Context Protocol): a universal translator that lets AI models talk to apps and data sources. It's like giving ChatGPT a passport and a map. - IndexedDB: your browser's secret storage closet. That's where your tasks quietly live when no one's looking. So, if all those acronyms started sounding like a new boy band, don't worry: they just keep your data safe, synced, and private. ### How to use the MCP Server ```bash # What Users Need to Do 1. Install MCP Server: npm install -g gsd-mcp-server 2. Configure your AI tool of choice: Add the following configuration: { "mcpServers": { "gsd-taskmanager": { "command": "npx", "args": ["-y", "@gsd/mcp-server"], "env": { "GSD_API_BASE_URL": "https://gsd.vinny.dev", "GSD_AUTH_TOKEN": "your-jwt-token", "GSD_ENCRYPTION_PASSPHRASE": "your-passphrase" } } } } 3. Restart your AI app of choice and test ``` --- If you want to kick the tires, the repo's open and waiting for you. I'd love your feedback and ideas on what to build next. [Read the original story and get the links](https://vinny.dev/blog/2025-10-09-a-procrastinators-journey) Shared on [LinkedIn](https://www.linkedin.com/posts/vinnycarpenter_gsd-task-manager-activity-7388281355589095424-ickt?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAAMPBgBfbBH6Q-lntjTWCdKSP-iU9Wex3A) --- ## The Art of Enough: Why Minimalism Matters in Software Engineering - **Published:** 2025-10-20 - **Tags:** software-engineering, productivity, architecture - **URL:** https://vinny.dev/blog/2025-10-20-the-art-of-enough/ I was reflecting on how often we "simplify" things in tech, only to end up with something even more complex. A recent conversation about Kubernetes and React made me realize how often our good intentions lead us toward maximalism in the name of progress. We look around and realize our new tools are heavier, slower, and more complex than ever. Maybe it's not the tools that changed, but our tendency to chase maximalism in the name of progress. ## Wirth's Law: a warning from 1995 In 1995, computer scientist Niklaus Wirth warned us in *A Plea for Lean Software*. His insight, now known as Wirth's Law, was simple and devastating: > Software gets slower faster than hardware gets faster. He was describing what happens when we equate more features with more value. The faster our machines get, the more bloat we add on top. ## You can see it everywhere - We reach for Kubernetes to deploy a single service - We spin up React for a static web page - We over-engineer because big tools feel like progress But innovation often swings like a pendulum. After each wave of maximalism, there's a moment when we rediscover restraint. ## The case for working with the platform Carson Gross, the developer behind HTMX, captures this perfectly: > I might encourage minimalism in web development, but only because there's this incredibly complicated piece of software called a browser. We can take advantage of that complexity rather than putting a lot of complexity on top of it. I've been exploring this philosophy firsthand by learning HTMX as an alternative to the complexities of React and other JavaScript frameworks. What started as curiosity about a simpler approach led me to discover Carson Gross's compelling rationale: why add layers of abstraction when the browser itself is already a powerful, battle-tested platform? HTMX uses what HTML and browsers do best: handling hypermedia, rather than rebuilding these capabilities in JavaScript or TypeScript. It's been refreshing to see how much we can accomplish by working with the platform instead of on top of it. That's the mindset shift. Minimalism is not about doing less. It's about using what already exists more intelligently. ## The challenge - When you design or build, ask if your problem really needs the full machinery - Choose maximalism only when scale demands it - Choose minimalism when clarity and speed matter more Wirth's Law reminds us that unchecked growth creates drag. Gross's philosophy reminds us that simplicity can be strategic. Real progress might not be about adding more at all. It might be about mastering the art of enough. --- *Originally shared on [LinkedIn](https://www.linkedin.com/posts/vinnycarpenter_softwaredesign-minimalism-simplicity-activity-7385889433843269632-R7CS?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAAMPBgBfbBH6Q-lntjTWCdKSP-iU9Wex3A)* --- ## Building My Own Productivity Tools: A Procrastinator's Journey - **Published:** 2025-10-09 - **Tags:** productivity, open-source, side-projects, security - **URL:** https://vinny.dev/blog/2025-10-09-a-procrastinators-journey/ ## Confession time: I'm a procrastinator. There, I said it! Self-awareness is the first step to improvement, and I'm very aware of my procrastination habits. Over the years, I've built elaborate systems to outsmart myself: gadgets, apps, notebooks, and probably a few too many browser tabs. Like many productivity nerds, I share Marques Brownlee's obsession with to-do list apps. If you've ever listened to the Waveform podcast, you know the running gag where Marques keeps searching for the "perfect" productivity tool. I feel seen. So after testing every app under the sun and still not finding "the one," I did what any reasonable engineer would do… I built my own. Actually, I built two. Both are open-source, privacy-first, and free to use: ## The tools [Cascade](https://cascade.vinny.dev): a lightweight Kanban-style task manager that's simple, fast, and secure. [GSD](https://gsd.vinny.dev/): a task manager inspired by the Eisenhower Matrix to help you Get Stuff Done. All your data stays local in your browser: no tracking, no accounts, no cloud. Just focus. ## Try them out I'd love your feedback! Try one (or both!) and tell me what helps you stay productive and on track. And if you're the tinkering type, check out the GitHub repos, fork them, and send me your ideas for improvement. Because let's be honest, procrastinators unite… tomorrow. --- *Originally shared on [LinkedIn](https://www.linkedin.com/posts/vinnycarpenter_gsd-task-manager-activity-7381829778322075648-4cm6?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAAMPBgBfbBH6Q-lntjTWCdKSP-iU9Wex3A)* **Links:** - Cascade: [https://cascade.vinny.dev](https://cascade.vinny.dev) - Cascade GitHub Repo [https://github.com/vscarpenter/kanban-todos](https://github.com/vscarpenter/kanban-todos) - GSD: [https://gsd.vinny.dev](https://gsd.vinny.dev) - GSD GitHub Repo [https://github.com/vscarpenter/gsd-task-manager](https://github.com/vscarpenter/gsd-task-manager) --- ## When Winning Feels Like Losing: Leadership Lessons from McLaren’s F1 Drama - **Published:** 2025-10-07 - **Tags:** engineering-leadership, software-engineering, formula1 - **URL:** https://vinny.dev/blog/2025-10-07-leadership-lessons-mclaren-f1/ **When Winning Feels Like Losing: Leadership Lessons from McLaren's F1 Drama** Formula 1 is the pinnacle of motorsport, where precision, pressure, and performance collide at 200 mph. Among its legendary teams, *McLaren* stands out for its storied history, innovation, and fierce pursuit of excellence. With 10 Constructors' Championships, they have long embodied speed and strategy in equal measure. This season, McLaren clinched their *10th Constructors' title* at the Singapore Grand Prix. But instead of pure celebration, headlines focused on a first-lap clash between teammates *Lando Norris* and *Oscar Piastri*, and the growing controversy around the team's so-called *Papaya Rules*, guidelines meant to ensure fairness and respect between drivers. The problem? Formula 1 isn't fair. Only one driver can win the championship. When leadership promises equality in a system built on competition, confusion takes the wheel. McLaren's attempt to balance fairness with performance, sometimes intervening (like at Monza) and sometimes not, has blurred the lines of trust and accountability. This is a classic leadership dilemma: trying to please everyone when clarity, not consensus, is what the moment demands. Teams do not fracture because of conflict; they fracture because people do not know where the boundaries are. Leadership takeaway: Define the line between fairness and performance. Clarity does not kill morale; it builds trust. McLaren's challenge is every leader's challenge: how to steer ambition without collision. --- *Where have you seen this tension between fairness and performance in your teams?* --- ## Beyond the Hype: Why GenAI Adoption in Development Isn't the Silver Bullet We Expected - **Published:** 2025-09-30 - **Tags:** engineering-leadership, software-engineering, genai - **URL:** https://vinny.dev/blog/2025-09-30-genai-adoption-in-development/ A curious paradox is unfolding across enterprise development teams right now. While AI-assisted coding tools have become nearly ubiquitous [with 84% of developers now using or planning to use AI tools in their workflows](https://survey.stackoverflow.co/2025/ai/), there's a growing cohort of talented engineers who remain skeptical, hesitant, or outright resistant to adding these capabilities to their toolkit. As someone who leads Cloud, Platform, and DevOps engineering teams, I've had countless conversations with peers across financial services, healthcare, retail, and technology sectors. The pattern is undeniable: despite the promise and the breathless headlines, GenAI adoption isn't happening as smoothly or as universally as many predicted. ## The Mr. Beta perspective I'll admit my own bias upfront: I'm an unabashed early adopter. My wife lovingly (and sometimes exasperatedly) calls me "Mr. Beta" because our home is a constantly evolving testbed for the latest automation and productivity tools. If there's something new that promises to improve efficiency, I'm diving in headfirst. Our smart home setup is perpetually in flux, much to her frustration. This same tendency extends to my professional life. I've been using AI-assisted development tools for years now, starting with GitHub Copilot and ChatGPT, and evolving through to Claude, Claude Code, Cursor, and Gemini. For me, these tools have delivered tremendous value, accelerating my ability to prototype solutions, explore unfamiliar codebases, learn & implement new ideas, and think through architectural decisions. But here's what I've learned: my experience isn't universal, and that matters. ## The trust paradox The data tells a story that goes beyond anecdotal resistance. [While 80% of developers are now using AI tools in their workflows, trust in the accuracy of AI output has fallen from 40% in previous years to just 29% this year](https://stackoverflow.blog/2025/07/29/developers-remain-willing-but-reluctant-to-use-ai-the-2025-developer-survey-results-are-here). Even more striking, [positive favorability toward AI tools has decreased from 72% to 60% year over year](https://stackoverflow.blog/2025/07/29/developers-remain-willing-but-reluctant-to-use-ai-the-2025-developer-survey-results-are-here). This isn't the trajectory of a technology living up to its promise. It's the signature of disillusionment setting in. [The number-one frustration, cited by 66% of developers, is dealing with "AI solutions that are almost right, but not quite"](https://stackoverflow.blog/2025/07/29/developers-remain-willing-but-reluctant-to-use-ai-the-2025-developer-survey-results-are-here): that maddening experience of code that looks correct at first glance but contains subtle bugs or misunderstands context in ways that require more time to debug than it would have taken to write from scratch. Recent research from METR (Model Evaluation & Threat Research) adds an even more surprising dimension to this story. [In a randomized controlled trial with 16 experienced open-source developers working on their own repositories, researchers found that when developers used AI tools, they took 19% longer to complete tasks than without AI assistance](https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/). This directly contradicted the developers' own expectations; they had predicted AI would speed them up by 24%. ## What's really driving resistance? Through my conversations with friends, peers, fellow engineering leaders, and teams, I believe I've identified several factors contributing to this resistance: ### 1. Change fatigue is real The last few years have asked developers to continuously adapt. New frameworks, new processes, shifting work models, organizational restructures, and now AI tools. [Research from Gartner found that in 2023, employees experienced four times as many organizational changes as they did in 2016](https://sdtimes.com/softwaredev/how-to-address-change-fatigue-to-sustain-business-agility/). When you're already stretched thin, being asked to integrate yet another new tool, even one promising productivity gains, can feel like one more burden rather than a benefit. [According to Gallagher's 2025 Employee Communications Report, 44% of HR and communications leaders across 55 countries now identify change fatigue as one of their top five barriers to success](https://whatfix.com/blog/change-fatigue/). ### 2. The hype cycle has burned people before Many developers have lived through multiple waves of "revolutionary" tools that promised to transform development but delivered incremental improvements at best. There's a pattern recognition at play: breathless marketing, inflated expectations, and eventual disappointment. Some developers are protecting themselves from that cycle by simply opting out until the dust settles. ### 3. The learning curve is steeper than marketed AI coding tools aren't just "plug and play." Achieving real value requires developing new skills, such as prompt engineering, understanding when to trust AI output and when to be skeptical, and learning to work iteratively with AI as a collaborator rather than a replacement. This investment can feel daunting when you're already an expert in your craft. Here's the uncomfortable truth: organizations aren't addressing this. We're asking developers to become proficient with fundamentally new tools without providing the systematic skills development, time, or support structures needed. It's like handing someone a new programming language and expecting immediate productivity without any training or ramp-up time. ### 4. The quality bar in enterprise development [Bain & Company's 2025 Technology Report found that while two-thirds of software firms have rolled out GenAI tools, developer adoption remains low, and teams using AI assistants see only 10% to 15% productivity boosts](https://www.bain.com/insights/from-pilots-to-payoff-generative-ai-in-software-development-technology-report-2025/). Even those modest gains often don't translate into positive returns because the time saved isn't redirected toward higher-value work. In enterprise environments with stringent code review processes, security requirements, and quality standards, the "almost right" code that AI generates can create more work than it saves. When you're building systems that handle millions of customer transactions or sensitive financial data, "close enough" isn't good enough. ### 5. We're repeating classic transformation mistakes This is where the wisdom from McKinsey's *Rewired* becomes particularly relevant. The book makes a compelling case that successful digital transformations require fundamentally rewiring how organizations operate, not just deploying new technology. Companies need to address six interconnected capabilities: strategy, talent, operating model, technology, data, and adoption. Sound familiar? We're making the same mistake with AI tools that companies make with digital transformation. We're focusing on tool deployment (the easy part) while ignoring the organizational rewiring required to capture value. We're not: - Reskilling systematically: Where's the investment in helping developers build AI-assisted development skills? - Redesigning workflows: How do code review processes need to evolve when AI is generating significant portions of code? - Measuring what matters: Are we tracking actual value creation, or just adoption metrics? - Building the right operating model: Do our team structures and processes support effective AI-tool usage? AI tools aren't failing developers. We're failing to create the conditions for developers to succeed with AI tools. ## The measurement gap Here's another uncomfortable reality: most organizations are measuring the wrong things. They're tracking: - How many developers have access to AI tools - What percentage are using them daily - License usage rates But they're not measuring: - Whether AI-generated code is making it to production - Developer satisfaction with the tools - Time spent debugging AI-generated versus human-written code - Whether "time saved" translates to meaningful value creation Without better measurement, we can't have honest conversations about what's working and what isn't. ## Moving forward: a more nuanced conversation Here's what I believe: GenAI tools are valuable, but they're not universal accelerators for all developers in all contexts. The conversation we need to have is more sophisticated than "adopt or be left behind." For individual developers: Consider giving these tools a genuine try in low-stakes environments. Start with tasks where getting 80% of the way there quickly has real value, such as documentation, test generation, and exploring unfamiliar APIs. Build your intuition for when AI is helpful and when it's not. But also honor your own assessment of whether these tools improve your workflow. Your skepticism might be wisdom, not resistance. For engineering leaders: Resist the temptation to mandate AI tool adoption without addressing the underlying factors driving resistance. Take a page from the *Rewired* playbook: 1. Invest in systematic skills development: Create learning paths, communities of practice, and time for experimentation 2. Evolve your operating model: Adapt code review processes, quality standards, and workflow patterns to account for AI-assisted development 3. Measure actual value, not vanity metrics: Track developer satisfaction, code quality, and business outcomes 4. Listen deeply to your teams: [As Atlassian's 2025 State of DevEx Survey found, 63% of developers now say leaders don't understand their pain points, up sharply from 44% last year](https://www.atlassian.com/blog/developer/developer-experience-report-2025) 5. Create space for heterogeneous adoption: Not every team or developer will benefit equally; that's okay For organizations: Recognize that AI tools work best when integrated into a broader transformation of the software development lifecycle, not as a standalone silver bullet. [Companies that pair generative AI with end-to-end process transformation report 25% to 30% productivity boosts](https://www.bain.com/insights/from-pilots-to-payoff-generative-ai-in-software-development-technology-report-2025/), but that requires systemic change, not just tool adoption. And critically: be honest about the enterprise context. What works for a solo developer building a side project or a startup with three engineers doesn't automatically translate to a regulated financial services company with legacy systems, compliance requirements, and thousands of developers. The bar for code quality, the complexity of the systems, and the consequences of errors are all fundamentally different. The resistance to GenAI tools isn't simply about developers being stubborn or afraid of change. It's a rational response to tools that haven't yet proven their value universally, in an environment where people are already managing substantial change fatigue, and where the quality bar for production code remains high. As someone who has genuinely benefited from these tools, I remain optimistic about their potential. But I also recognize that the path to widespread, effective adoption is longer and more complex than the hype suggested. And that's okay. The best technology adoption stories have never been about instant revolution: they've been about thoughtful evolution, learning what works, and adapting both the tools and our practices to get the best results. The conversation shouldn't be "why aren't more developers using AI tools?" It should be "how do we create the conditions where AI tools deliver genuine value for diverse teams in diverse contexts?" That's a conversation worth having, and one that requires the kind of fundamental organizational rewiring that successful transformations have always demanded. --- What's your experience been with AI-assisted development tools? Are you seeing the productivity gains promised, or are you finding the reality more nuanced? --- ## Coaching Your LLM with Software Craftsmanship Principles - **Published:** 2025-09-27 - **Tags:** software-engineering - **URL:** https://vinny.dev/blog/2025-09-27-coaching-your-llm-with-software-craftmanship-principles/ One of the best lessons I've learned using LLMs for code generation is this: the quality of the output depends heavily on the quality of the guardrails you provide. Left on autopilot, even the most advanced models can generate over-engineered, inconsistent, or unmaintainable code. But if you coach the model with proven principles (the same way you would mentor a junior developer), you get results that are consistently clean, solid, and production-ready. I lean on timeless practices like SOLID, DRY (Don't Repeat Yourself), YAGNI (You Aren't Gonna Need It), separation of concerns, convention over configuration, loose coupling, and high cohesion. These aren't just buzzwords, they're a set of guardrails that keep both humans and LLMs aligned on writing scalable and maintainable code. Here's the guideline set I use when prompting my favorite LLM for code generation: ``` # Code Development Guidelines ## Core Philosophy - **Favor simplicity over cleverness** - Write code that's easy to understand first, optimize later if needed - **Start minimal and iterate** - Build the smallest working solution, then enhance based on actual requirements - **Optimize for the next developer** - Write code as if the person maintaining it is a violent psychopath who knows where you live ## Readability & Maintainability - **Use descriptive names** - Variables, functions, and classes should clearly express their purpose - **Keep functions small and focused** - Each function should do one thing well (single responsibility principle) - **Minimize nesting** - Use early returns, guard clauses, and clear conditional logic - **Add comments for "why," not "what"** - The code should be self-documenting for what it does - **Follow consistent formatting** - Use team-agreed linting rules and code formatting standards ## DRY (Don't Repeat Yourself) - Applied Thoughtfully - **Extract common patterns** but avoid premature abstraction - **Create reusable functions/modules** when you see the same logic 3+ times - **Use configuration over duplication** for environment-specific values - **Balance DRY with readability** - sometimes a little duplication is clearer than complex abstraction ## Anti-Over-Engineering Principles - **YAGNI (You Aren't Gonna Need It)** - Don't build features for hypothetical future requirements - **Choose boring technology** - Use well-established patterns and libraries unless there's a compelling reason not to - **Avoid premature optimization** - Make it work correctly first, then measure and optimize bottlenecks - **Question every layer of abstraction** - Each abstraction should solve a real, current problem - **Prefer composition over inheritance** - Build functionality by combining simple pieces ## Code Generation Instructions When working with an LLM such as Claude Code, Codex, Gemini or others, include these guidelines in your prompts: ### Essential Prompt Elements - "Keep it simple and readable" - "Use standard patterns and avoid clever tricks" - "Include clear variable names and brief comments explaining complex logic" - "Don't abstract until you see repeated patterns" - "Focus on solving the immediate problem efficiently" ### Example Prompt Template Generate [specific functionality] that: - Uses clear, descriptive variable and function names - Follows [language/framework] best practices - Includes error handling where appropriate - Has minimal complexity and nesting - Includes brief comments for any non-obvious logic - Avoids premature optimization - Uses well-established libraries and patterns ## Quality Checklist Before considering code complete, verify: - [ ] Can a new team member understand this code in 5 minutes? - [ ] Are variable and function names self-explanatory? - [ ] Is the happy path clear and the error handling robust? - [ ] Could this be simpler without losing functionality? - [ ] Are there any "clever" parts that could be made more straightforward? - [ ] Does it solve the actual problem without extra features? ## Red Flags to Watch For - Functions longer than 20-30 lines - More than 3 levels of nesting - Variable names like `data`, `item`, `temp`, or single letters (except loop counters) - Complex inheritance hierarchies - Abstractions that are only used once - Code that requires extensive comments to explain what it does (vs. why) Remember: The goal is code that your team can quickly understand, modify, and extend without archaeological excavation of the original author's intent. ``` ## Why this works An LLM is like an eager apprentice. It will happily generate code at lightning speed, but without direction it may invent abstractions you don't need, introduce inconsistencies, or optimize the wrong thing. By feeding it a clear playbook like the one above, you give it a shared language for what "good code" means in your context. This turns your interactions from "please generate code for X" into "please generate code for X that adheres to the same standards I'd expect from any engineer on my team." The result? Code you can trust, reuse, and maintain, not just code that compiles. --- ## From AI to Agents: Building Smarter Systems that think, decide and act - **Published:** 2025-09-14 - **Tags:** software-engineering, genai, agentic-sdlc, finops - **URL:** https://vinny.dev/blog/2025-09-14-From-AI-to-AI-Agents/ We're witnessing a fundamental shift in how we interact with artificial intelligence. While traditional AI systems excel at answering questions and generating content, they operate in isolation: responding to prompts but unable to take action in the real world. Enter AI agents: the next evolution that bridges this gap between intelligence and action. AI agents are autonomous software systems that use artificial intelligence, such as the frontier large language models (LLMs), to perceive their environment, make decisions, and take actions to achieve user-defined goals with minimal human intervention. Unlike static AI models that respond to queries, agents actively monitor, reason, and act upon their surroundings, creating a dynamic feedback loop that enables truly intelligent automation. This evolution represents a shift from reactive to proactive AI. Instead of waiting for human input, AI agents continuously observe their environment, identify opportunities or issues, and autonomously execute appropriate responses. They combine the reasoning capabilities of modern LLMs with the ability to interact with external systems, APIs, and services, creating intelligent systems that can manage complex workflows end-to-end. ## What I'm building In my quest to learn by doing, I decided to work on a personal project that yielded tangible results, helping me understand the value of AI agents. My day job is all about maximizing the value of our cloud investments. As part of my learning journey, I am building a simple, real-world agent that watches my personal cloud spend and notifies me when I'm trending over budget. The agent sends alerts via email, text, and iOS push notifications, so I see them. The point is not novelty, it is leverage. If an autonomous system can handle routine FinOps hygiene, humans can spend more time on architecture, savings plans, and strategy. This example uses the Strands Agents framework from AWS to perform the heavy lifting and simplify the development of AI agents. Here is a simple flowchart that demonstrates how this simple AI agent works. ![Application flow chart](/images/blog/2025/09/agentic-ai-flowchart.png "Flowchart of the application flow") ## Introducing the AWS Strands framework Strands takes a model-driven approach to building and running AI agents, enabling them to be created and deployed in just a few lines of code. This approach scales from simple to complex agent use cases, as well as from local development to production deployment. What makes Strands unique is its philosophy of letting the LLM serve as the orchestrator. Rather than requiring developers to define complex workflows for their agents, Strands simplifies agent development by embracing the capabilities of state-of-the-art models to plan, chain thoughts, call tools, and reflect. This approach allows developers to focus on defining the agent's purpose and available tools, while the framework handles the complex orchestration logic. The simplified code snippet in the image below shows the elegance of the Strands framework. ![Strand Framework](/images/blog/2025/09/strands-framework.png "The implementation showcases the elegance of the Strands framework") ## Try it yourself The project I've created is open source. Please download and try it out yourself. You can read the overview and setup notes here: - [GitHub Project](https://github.com/vscarpenter/FinOps-AIAgent) where this project lives - [Project README](https://github.com/vscarpenter/FinOps-AIAgent/blob/main/README.md) with goals and usage instructions - [FinOps-AIAgent details](https://github.com/vscarpenter/FinOps-AIAgent/blob/main/FinOps-AIAgent.md) with behavior and alert notes - [Strands Agents documentation](https://strandsagents.com/) for concepts, quickstart, and deployment options ## See the agent in action One of the most satisfying moments in building this AI agent was seeing it spring into action. Instead of quietly running in the background, it actively watched my AWS account and sent me an alert the moment my spend crossed the budget threshold. It felt like having a diligent teammate who never sleeps, always on the lookout. Here's the actual email it generated, proof that the agent is not just an idea, but working in practice.

AWS Spend Alert Email Screenshot

## The future: from toil to judgment The real promise of AI agents isn't in saving a few keystrokes or sending one more alert. It's in transforming how we work. Much of the energy in today's enterprises is still consumed by toil: manual checks, repetitive approvals, constant monitoring. That work is essential, but it rarely calls on our best selves. It doesn't demand deep judgment, creativity, or empathy. It just has to get done. Agents are a lever against that gravity. They will automate the baseline work that keeps systems running and budgets under control. In doing so, they create space for people to focus on what only people can do: making complex tradeoffs, exercising judgment in ambiguous situations, and shaping a strategy that balances innovation with responsibility. In the same way cloud freed us from racking servers and patching disks, AI agents will free us from babysitting dashboards and chasing cost anomalies. My thesis is simple: the future of work will be defined by how effectively we use agents to reduce toil and reclaim human judgment. As agents become more capable, our value won't be measured by how fast we can click through tasks, but by how thoughtfully we apply insight, creativity, and leadership to the decisions that matter. In a sense, AI isn't replacing us; it's reminding us what we're here for. --- ## My AI Subscription Problem (or is it obsession) - **Published:** 2025-09-07 - **Tags:** genai, software-engineering, platform-engineering - **URL:** https://vinny.dev/blog/2025-09-07-My-AI-Subscription-Problem/ At this point, I think I officially qualify for an AI Tools Support Group. After reviewing my Gmail invoices, it turns out I'm paying for… well… a lot of AI tools. And yes, I definitely use all of them… for at least five minutes each. Here's the current lineup in my "AI All-You-Can-Eat Buffet": - Claude Code → *My absolute favorite for code generation and refactoring.* It's like having a brilliant pair-programmer who never judges my bad variable names. - OpenAI Codex → *Another CLI, because apparently one isn't enough.* - Kiro AWS IDE → *My current obsession.* Spec-driven development done right. - Cursor IDE → *Makes me think I'm a 10x developer.* Spoiler: I'm not. - VS Code + AI Extensions → *Where half of my tabs go to die.* - Warp Terminal → *Feels like coding inside a sci-fi movie.* - Trae's Solo → *Because why not have another AI IDE?* - Google Gemini CLI → *For those "just one more LLM" moments.* - Amazon Q Developer → *Like Alexa, but way nerdier.* ![Gemeni AI search my Gmail to AI tools](/images/blog/2025/09/too-many-ai-tools.png) *Figure 1: Using AI to find AI tools I'm paying for. Inception?* Switching between all of them also has a side benefit: I get around usage limits on their built-in LLMs. (Yes, I'm basically the Netflix password sharer of AI.) But the real star here is Kiro. I'm genuinely excited about the way it approaches spec-driven development. If more tools adopt this model, building software could feel less like debugging spaghetti code at 2AM and more like… actual engineering. Yes, I used AI to audit my AI spending. The irony is not lost on me. In the meantime, if you need me, I'll be over here explaining to my finance team (a.k.a. my wife) why I "need" nine different AI subscriptions to write the same "TODO task mgmt" app. --- ## What worked in 2010 is our blueprint for the AI-infused future - **Published:** 2025-09-01 - **Tags:** cloud, genai, software-engineering, engineering-leadership - **URL:** https://vinny.dev/blog/2025-09-01-Blueprint-for-AI-infused-future/ Adrian's reflection on Netflix's early AWS journey really resonates. At the time, cloud wasn't just a technology shift. It forced companies to rethink operating models, developer experience, and leadership structures. The organizations that succeeded didn't just *bolt cloud onto legacy workflows*; they redesigned how work actually got done. Today, we are experiencing the same transformation with AI agent swarms. Only this time, the timelines are compressed. What took years during the cloud era is happening in months with AI. This is not a plug-and-play moment. As *McKinsey's Rewired* argues, getting value from AI requires rebuilding the enterprise's DNA, not just adopting a new toolset. Winning organizations are: - Redesigning operating models to support cross-functional, outcome-driven teams - Letting product managers think like developers and developers act with product-level ownership - Investing in talent and skills instead of outsourcing core capabilities - Rearchitecting data and platform strategies to enable seamless integration of AI agents - Driving cultural change by rewarding adaptability, learning, and experimentation The core idea: the companies that thrive will rethink their operating models, developer experience, and leadership structures instead of layering AI on top of outdated workflows. Just as Netflix had to dismantle the data center playbook to tap the power of cloud, leaders today must dismantle retrofit-AI thinking. It is becoming faster to teach product managers how to orchestrate AI agents than to retrain developers to think like product managers. Those who learn to define outcomes, orchestrate agent swarms, and lead with clarity will be the ones rewriting the next chapter of software delivery. The playbook is changing. Again. --- ## The Future of Interfaces - **Published:** 2025-08-28 - **Tags:** genai, platform-engineering, software-engineering - **URL:** https://vinny.dev/blog/2025-08-28-The-Future-of-Interfaces/ I just finished reading this thought-provoking piece on "The Death of the User Interface" by @0xs34n (on GitHub) and it got me thinking about how we interact with technology. The core idea is simple: graphical UIs are starting to feel like yesterday's solution. Instead of clicking through menus and dashboards, AI agents let you state intent and get results. Picture this: Instead of navigating through AWS console tabs to check your EC2 instances, you say "Show me all instances running costs above $50/day" and get instant results. It happens without the window-hunting and context switching. It's a compelling evolution from Steve Jobs' "bicycle for the mind" analogy to what feels like a teleporter: instant, effortless intent-to-execution. The historical timeline from the mouse's invention in the 1960s to today's AI-driven abstractions hits home, showing how each leap in computing simplifies interaction and reduces cognitive load. As someone who's dabbled in UX design and development, I love how it names the "mental tax" of traditional interfaces, all those buttons and hierarchies we take for granted but that sap our focus. This also connects with Santiago Valdarrama's post asking why so many AI providers are shipping CLIs if IDEs "won." My take is that it's not CLI vs IDE. It's using the right tool for the moment. ## Why CLIs are gaining traction in AI-powered workflows Speed → refactor and test quickly without heavy UI overhead Automation → integrates cleanly with pipelines, scripts, and Git hooks Focus → conversational, stepwise work with less visual noise Fit → matches terminal-first habits many devs already have IDEs still matter for deep debugging, complex builds, and visual insight. But CLIs improved by AI open up a new mode: coding by intent instead of coding by clicking. Looking at this through the developer experience lens, imagine spinning up environments, fixing configs, or deploying apps by describing the outcome you want. Fewer dashboards. Fewer clicks. More time solving problems. I'm curious: In your daily work, where do you see AI-powered interfaces replacing traditional clicks and menus first? --- ## September Read List - **Published:** 2025-08-28 - **Tags:** engineering-leadership, productivity, learning, software-engineering - **URL:** https://vinny.dev/blog/2025-08-28-September-readinglist/ I've been spending September diving into a few new reads and re-reading a couple of old favorites that keep teaching me something new every time. ![September 2025 Reading List](/images/blog/2025/09/september-reading-list.jpg) *My carefully curated reading list for September 2025* - **The Leader's Guide** by Eric Ries (re-read): Practical ways to scale innovation and keep focus when everything is moving fast. - **The Power of Less** by Leo Babauta: Simplicity that creates more impact. - **Stillness Is the Key** by Ryan Holiday (re-read): A return to Stoicism; calm and clarity as leadership superpowers. - **Essentialism** by Greg McKeown: Say no to the trivial many so you can say yes to the vital few. There's a common thread here that I can't ignore. In a world that rewards being busy, these authors are making the case for being intentional. Whether it's Holiday's Stoic principles helping us find calm in chaos, or McKeown's framework for ruthless prioritization, the message is clear: less noise, more signal. As engineering leaders, we're constantly pulled in different directions. The real skill isn't managing more; it's choosing better. Sometimes the most innovative thing you can do is eliminate everything that isn't essential. What's landing on your October reading list? I'm always hunting for books that challenge conventional thinking or offer fresh perspectives on leadership and life. --- ## We are standing at the edge of another tech revolution - **Published:** 2025-08-19 - **Tags:** engineering-leadership, genai, software-engineering - **URL:** https://vinny.dev/blog/2025-08-19-Another-Tech-Revolution/ I've seen this story before: the internet, mobile, and now AI. Each wave has reshaped how we live and work, creating opportunities we never saw coming. But this time, the speed is different. AI is moving at a breathtaking pace. What took the internet and mobile years to reach maturity is happening in months. That acceleration changes the rules for how individuals, companies, and entire industries adapt. ## AI is creative destruction, and that's a good thing Every major technological shift brings creative destruction: - Some roles disappear. - Some skills lose value. - Entire workflows are rewritten. But history shows that each wave creates more than it destroys. New industries emerge. Entirely new careers take shape. Opportunities we could not have imagined become the new normal. I've lived through two of these revolutions: ## The internet revolution The web didn't just digitize existing industries; it invented new ones. Search engines, e-commerce, digital marketing, and online marketplaces appeared almost overnight. Careers like SEO specialist, web developer, and UX designer didn't exist before the mid-90s. ## The mobile revolution The App Store democratized software. A single developer could build an app and reach millions without a sales team. Entire industries were reshaped as mobile-first companies upended entrenched players. New careers emerged (product design, app monetization, push notifications, mobile analytics), none of which existed before 2008. Content creation also transformed: - Self-publishing removed gatekeepers. - YouTube and TikTok made global broadcasters out of anyone. - Streaming gave independent musicians worldwide reach. ## Now, it's AI's turn AI is moving even faster than those waves. It will: - Automate repetitive work - Augment high-skill roles - Create careers we can't yet define Some job titles may sound strange today, just like *"social media manager"* did a decade ago. Soon, they'll be obvious. ## A personal perspective My daughter is in college studying computer programming. She's smart, driven, and passionate about building things. I often think about what her career will look like in 5, 10, or 20 years. Will some of the skills she's learning be automated? Almost certainly. Will AI also give her superpowers to create, innovate, and solve problems beyond today's limits? Absolutely. And here's my advice to her, and anyone starting out in tech today: > **Learn how to learn.** > Don't anchor yourself to today's tools, frameworks, or languages. > Build the muscle of adaptability, creativity, and problem-solving. Because in a world where roles will keep changing, the ability to reinvent yourself again and again will matter more than any single skill you learn today. ## The future of work is about readiness AI is lowering the barrier to innovation, putting powerful tools in the hands of individuals who can now build and compete at scales once reserved for the largest companies. The winners will be those who: - Adapt as tools evolve - Spot opportunities before they're obvious - Blend technical fluency with creativity and problem-solving This is where grit comes in: the passion and perseverance to keep learning, keep experimenting, and keep moving forward, even when the ground shifts beneath you. ## The big question The question isn't if your role will change; it will. The real question is: > **Will you be ready to step into the roles that don't exist yet?** --- ## 10 Years Later: A Journey of Continuous Learning Through Side Projects - **Published:** 2025-08-10 - **Tags:** engineering-leadership, learning, side-projects, software-engineering - **URL:** https://vinny.dev/blog/2025-08-10-Reflecting-journey-continous-learning/ Leadership roles come with a tricky trade-off, one that's always quietly gnawed at me. The more time you spend nurturing people, building teams, shaping culture, and refining strategy, the less time you get to roll up your sleeves and *write code*. And for someone who came up through engineering and still loves the feel of a keyboard under his fingers, that was something I wasn't willing to give up completely. So I made a promise to myself: never stop learning. ## It started with Swift In 2014, Apple introduced a brand-new programming language: Swift. While most people were still getting their heads around Objective-C, I decided to dive into the deep end. What began as a simple weekend experiment to tinker with Apple's new language turned into a full-on project. That app? It made it all the way to the App Store. This month marks 10 years since that first app launched. What started as a side project turned into a decade-long journey of hands-on learning, one build, one bug fix, one release at a time. ## Why I still code That iOS app was just the beginning. Over the years, I've created dozens of side projects (apps, tools, experiments, cloud-based services), all with one goal in mind: stay technical. Some were fun. Some were painful. All were worth it. Here's what I've learned along the way: - User feedback makes your product better, full stop. - Iteration is the secret sauce to everything. - Technologies change fast, and the half-life of knowledge keeps shrinking. - Shipping something real (and having it used!) is immensely satisfying. These lessons didn't come from books or meetings; they came from doing. ## Leading with both hands While my day job focuses on leading amazing teams and driving strategy, these personal projects help me stay grounded in the craft. There's a unique kind of empathy that comes from debugging your own code at 11 PM. It's humbling. And it keeps you connected to the work your teams are doing every day. To any engineering leaders reading this: find your way to stay close to the craft. Maybe it's through open source. Maybe it's tinkering with AI models. Maybe it's just reading through PRs or contributing feedback. Whatever it is, don't let go of it. ## Explore the app that started it all Curious about that very first app I built with Swift? [Check it out here](https://traveltimesapp.com/) ## What about you? What personal projects have fueled *your* learning journey? Whether it's code, writing, design, or building things in the garage, I'd love to hear what keeps you sharp. Let's keep learning. --- ## From Vibe Mode to Spec Mode: Why I’m All In on Kiro - **Published:** 2025-08-10 - **Tags:** ai-coding, genai, platform-engineering, software-engineering - **URL:** https://vinny.dev/blog/2025-08-10-From-Vibe-Mode-to-Spec-Mode/ ![Specs vs Vibes](/images/blog/2025/08/spec-vs-vibes.png) ## The evolution of a developer mindset There was a time when I leaned heavily into what I call "vibe coding." You throw out a few prompts, cross your fingers, and hope the AI kicks back something usable. It was fast, fun, and sometimes chaotic. But after 25 years of writing code, I've learned that structure, clarity, and repeatability are what really stand the test of time. That's why I've become such a huge fan of Kiro, the new agentic IDE from AWS. Kiro isn't just a fancier autocomplete tool. It's a development partner that understands your entire codebase, translates natural-language prompts into structured specs, and eliminates the grind through intelligent automation. ## Specs vs vibes: two ways to build You can build software in one of two ways: - Vibe mode: toss code at the wall and hope it sticks. It's fast and loose, but easy to lose control and context. - Spec-driven mode: plan your work, break it into well-defined steps, and give your AI the guidance it needs to produce consistent, high-quality results. Kiro supports spec-driven development in the best possible way. You write your high-level intent, and Kiro turns that into specs, design files, tasks, tests, and even production-ready code. You can even go in reverse: make changes to the code and Kiro updates the corresponding specs. As someone who has spent decades building software, I feel right at home here. ## Kiro in action
Kiro Tasks Kiro Requirements

Kiro auto-generates tasks from requirements, and vice versa.

## What makes Kiro so different - Specs give your development efforts structure - Hooks automate repetitive tasks behind the scenes - Agentic Chat lets you collaborate with your project like you're talking to a senior dev - Steering gives Kiro context from your documentation and product direction, so it behaves consistently across the whole stack Kiro makes it feel like you've got a quiet but brilliant team of senior engineers backing you up. It anticipates what you need, documents as it goes, and keeps your work clean and consistent with the big picture. ## Why I switched I was a happy Cursor user until I tried Kiro. Now? I've canceled my Cursor subscription. Kiro plus Claude Code has become my daily driver for AI-assisted development. It's a setup that supports deep work, thoughtful engineering, and reliable delivery. If you've been stuck in vibe mode and want to bring some structure and strategy into your workflow, try Kiro. You'll get more than working code. You'll get working systems that make sense, evolve well, and keep you proud of what you're shipping. Your future self and your next production deploy will thank you. --- ## Back to Blogging: Two Decades in the Making - **Published:** 2025-05-17 - **Tags:** engineering-leadership, side-projects, software-engineering - **URL:** https://vinny.dev/blog/2025-05-17-back-to-blogging/ In the early 2000s, I stumbled into blogging almost by accident. I was attending the JavaOne conference when I sat in on a small demo for this new tool called Blogger. It felt magical. Suddenly, anyone could write, publish, and share their thoughts on their own little corner of the web. Back then, Blogger even let you publish directly to your own hosting server. Not long after, Google acquired them, and the internet as we knew it started shifting. That first blog started something for me. I moved on to running WordPress on my own Linux server, tweaking themes late into the night, and eventually spinning up my very first Amazon EC2 instance in 2008. That was my first real leap into the cloud, leaving behind the dedicated ISP-hosted servers I'd used for years. Blogging became more than just publishing posts. It was my way of sharing what I'd learned, capturing experiments, and connecting with people who were just as curious as I was. For a while, it worked. I met incredible folks. I learned from others. I had fun. Then life shifted. I joined a company that… let's just say… wasn't exactly thrilled about employees having a public voice online. I stopped writing. And honestly, I've missed it ever since. Fast forward to today, and I've decided to come back. Blogging again feels like reclaiming an old creative outlet, a chance to write, share, and connect without overthinking it. No perfect cadence, no grand plan. Just ideas, reflections, and things I'm excited about. Will I keep this up for a week, a month, or another decade? I have no idea. But here's to finding out. *Welcome back, old friend.* --- ## I just ran a 20-billion-parameter LLM entirely offline, from my Mac at home - **Published:** 2025-05-17 - **Tags:** genai, open-source, software-engineering - **URL:** https://vinny.dev/blog/2025-05-17-Twenty-Billion-Parameter-LLM-at-home/ ![Local LLM setup demonstration](/images/blog/2025/08/local-llm.jpg) *Figure 1: Local LLM configuration and setup* I've been experimenting with OpenAI's new open-weight model, gpt-oss-20b, on my Apple M4 Pro using LM Studio, and I'm genuinely impressed. This thing runs fast, respects your privacy (no data leaves your machine), and doesn't cost a cent beyond the initial download. It holds its own against cloud-based giants like ChatGPT 5, especially for reasoning tasks, code generation, and even creative writing, all without an internet connection. In a world where AI often means "connect to someone else's infrastructure," this flips the script. You can build and test locally, no API calls or billing meters in sight. There are tradeoffs: no live web data and some hardware requirements, but the benefits of local-first AI are growing fast. It feels like a glimpse into the future of decentralized intelligence. Are you running any open-weight models locally? I'd love to hear what's working for you and what you're building. ---