<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matthew</title>
    <description>The latest articles on DEV Community by Matthew (@mattbaconz).</description>
    <link>https://dev.to/mattbaconz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3886323%2Fcb6c4fb0-db9d-443c-a295-53c12d2c855a.png</url>
      <title>DEV Community: Matthew</title>
      <link>https://dev.to/mattbaconz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mattbaconz"/>
    <language>en</language>
    <item>
      <title>Your CI is green. Your billing logic is broken.</title>
      <dc:creator>Matthew</dc:creator>
      <pubDate>Thu, 25 Jun 2026 01:04:42 +0000</pubDate>
      <link>https://dev.to/mattbaconz/your-ci-is-green-your-billing-logic-is-broken-4j6j</link>
      <guid>https://dev.to/mattbaconz/your-ci-is-green-your-billing-logic-is-broken-4j6j</guid>
      <description>&lt;p&gt;User paid. Stripe looked fine. The app still gated them.&lt;/p&gt;

&lt;p&gt;They had an active subscription. The checkout page worked. Tests passed. But &lt;code&gt;has_paid_access&lt;/code&gt; in Postgres stayed &lt;code&gt;false&lt;/code&gt;, so the user hit the paywall anyway.&lt;/p&gt;

&lt;p&gt;This is not a rare edge case. It is the default failure mode when you ship billing logic with AI tools and mock Stripe in tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the bug actually happens
&lt;/h2&gt;

&lt;p&gt;The sequence is usually boring:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Agent writes checkout and a webhook handler for &lt;code&gt;customer.subscription.created&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Tests mock Stripe. CI goes green.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;invoice.payment_failed&lt;/code&gt; or &lt;code&gt;customer.subscription.deleted&lt;/code&gt; never updates the DB flag.&lt;/li&gt;
&lt;li&gt;Stripe says active. Your app says free.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nothing in a unit test suite checks both systems at once. You are testing each side in isolation. The bug lives in the gap between them.&lt;/p&gt;

&lt;p&gt;Stack Overflow's 2025 survey put AI coding tool adoption around 84%. Veracode found roughly 45% of AI-generated code samples contained OWASP Top 10 issues. Only about 33% of developers say they trust AI accuracy. Speed went up. The intersection of billing and database state did not get safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What v0.10.0 changed
&lt;/h2&gt;

&lt;p&gt;Before v0.10, showing someone this bug took four steps: clone the SDK, cd into it, pass config flags, point at a fixtures directory. Fine for docs. Too much friction for a Reddit comment or a tweet.&lt;/p&gt;

&lt;p&gt;v0.10.0 bundles the revenue-leak fixture inside the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prodverdict@0.10.0 demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. No git clone. No Stripe keys. You get a FAIL on purpose: active subscription, &lt;code&gt;has_paid_access&lt;/code&gt; false.&lt;/p&gt;

&lt;p&gt;Two other commands round out discovery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prodverdict scan    &lt;span class="c"&gt;# static repo analysis, no credentials&lt;/span&gt;
npx prodverdict init &lt;span class="nt"&gt;--mcp&lt;/span&gt; &lt;span class="nt"&gt;--cursor-rule&lt;/span&gt;   &lt;span class="c"&gt;# auto-detects stack from package.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Architecturally, v0.10 adds a discovery layer on top of the existing engine. &lt;code&gt;runContracts()&lt;/code&gt; still powers everything. The new commands just remove the setup tax before someone sees value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffp720c08diq9jhv39xf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffp720c08diq9jhv39xf2.png" alt="Billing state gap — before and after ProdVerdict" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: check the intersection in CI
&lt;/h2&gt;

&lt;p&gt;ProdVerdict compares billing state (Stripe or Paddle) against who your database thinks has paid access. Rules only. No LLM in the evaluation path. Missing credentials = fail, not a silent pass.&lt;/p&gt;

&lt;p&gt;After the demo, wire it into your repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prodverdict init &lt;span class="nt"&gt;--mcp&lt;/span&gt; &lt;span class="nt"&gt;--cursor-rule&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rk_test_...
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql://readonly:...@host/db
npx prodverdict check access
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Block merges in GitHub Actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prodv-dev/prodverdict-action@v0.10.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./prodverdict.yml&lt;/span&gt;
    &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;access&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.STRIPE_SECRET_KEY }}&lt;/span&gt;
    &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DATABASE_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secrets stay on your runner. ProdVerdict cloud never sees subscription rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other contracts (after access is wired)
&lt;/h2&gt;

&lt;p&gt;Once the billing check is trusted, add more: config (env drift), migration (unsafe Postgres DDL), boundary (mass-assignment), webhook (signature + idempotency lint), restore (backup smoke tests). Run all six with &lt;code&gt;npx prodverdict check all&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Start with access. It ties directly to revenue. The rest is expansion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prodverdict@0.10.0 demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Docs: &lt;a href="https://prodverdict.com/docs/quickstart" rel="noopener noreferrer"&gt;https://prodverdict.com/docs/quickstart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Agents + MCP: &lt;a href="https://prodverdict.com/agents" rel="noopener noreferrer"&gt;https://prodverdict.com/agents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SDK: &lt;a href="https://github.com/prodv-dev/prodverdict-sdk" rel="noopener noreferrer"&gt;https://github.com/prodv-dev/prodverdict-sdk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub Action: &lt;a href="https://github.com/marketplace/actions/prodverdict" rel="noopener noreferrer"&gt;https://github.com/marketplace/actions/prodverdict&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free CLI, Action, and local MCP on private repos. I built this after catching the same bug one too many times. Curious if you have shipped this class of mismatch before.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>devops</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Stripe says active. Postgres says false. Nobody alerts you.</title>
      <dc:creator>Matthew</dc:creator>
      <pubDate>Thu, 18 Jun 2026 07:05:02 +0000</pubDate>
      <link>https://dev.to/mattbaconz/stripe-says-active-postgres-says-false-nobody-alerts-you-32d4</link>
      <guid>https://dev.to/mattbaconz/stripe-says-active-postgres-says-false-nobody-alerts-you-32d4</guid>
      <description>&lt;p&gt;Your Stripe dashboard looks fine. MRR is up. Tests pass. CI is green.&lt;/p&gt;

&lt;p&gt;Then a customer emails you: "I paid, but I'm still on the free plan."&lt;/p&gt;

&lt;p&gt;That is usually not a Stripe bug. Stripe charged them. Your app never updated the row that gates access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two systems, one gap
&lt;/h2&gt;

&lt;p&gt;Most subscription SaaS runs on two truths:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stripe — who paid, which plan, subscription status&lt;/li&gt;
&lt;li&gt;Your database — &lt;code&gt;has_paid_access&lt;/code&gt;, &lt;code&gt;plan&lt;/code&gt;, &lt;code&gt;stripe_customer_id&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The webhook handler is supposed to keep them aligned. When it drifts, neither side raises an alarm. Stripe thinks everything delivered. Your app serves the wrong access level. You only find out when someone complains.&lt;/p&gt;

&lt;p&gt;Stripe's docs say this plainly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Events are not guaranteed to arrive in order (&lt;a href="https://docs.stripe.com/webhooks" rel="noopener noreferrer"&gt;docs.stripe.com/webhooks&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Failed deliveries retry for up to three days in live mode&lt;/li&gt;
&lt;li&gt;Your endpoint must return 2xx before slow work, or you hit timeouts and retries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This shows up in production, not just in tutorials. On the &lt;a href="https://forum.ghost.org/t/subscriber-charged-by-stripe-for-premium-subscription-but-still-shows-up-as-free-member/46722" rel="noopener noreferrer"&gt;Ghost forum&lt;/a&gt;, a founder paid through Stripe successfully, then landed back on the site as a free user. Ghost staff explained: if the webhook never lands, Ghost never learns about the subscription. Another user confirmed multiple paid subscribers stuck as free until they watched the webhook log constantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI makes the happy path faster and the failure path easier to skip
&lt;/h2&gt;

&lt;p&gt;Developers are using AI tools everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;84% use or plan to use AI tools (&lt;a href="https://stackoverflow.co/company/press/archive/stack-overflow-2025-developer-survey/" rel="noopener noreferrer"&gt;Stack Overflow 2025 survey&lt;/a&gt;, 49k+ responses)&lt;/li&gt;
&lt;li&gt;90% of software professionals use AI daily (&lt;a href="https://blog.google/innovation-and-ai/technology/developers-tools/dora-report-2025/" rel="noopener noreferrer"&gt;Google DORA 2025&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Trust did not keep up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;29% trust AI accuracy, down 11 points from 2024 (&lt;a href="https://stackoverflow.blog/2026/02/18/closing-the-developer-ai-trust-gap/" rel="noopener noreferrer"&gt;Stack Overflow blog, Feb 2026&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;46% distrust AI output accuracy (SO 2025 press release)&lt;/li&gt;
&lt;li&gt;66% say their top frustration is output that is "almost right, but not quite" (&lt;a href="https://www.infoworld.com/article/4031673/ai-use-among-software-developers-grows-but-trust-remains-an-issue-stack-overflow-survey.html" rel="noopener noreferrer"&gt;InfoWorld on the survey&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI is good at checkout → stub webhook → set &lt;code&gt;has_paid_access = true&lt;/code&gt;. It is weaker on the paths that actually cause drift:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;invoice.payment_failed&lt;/code&gt; without revoking access&lt;/li&gt;
&lt;li&gt;Out-of-order &lt;code&gt;customer.subscription.updated&lt;/code&gt; events&lt;/li&gt;
&lt;li&gt;Duplicate &lt;code&gt;evt_...&lt;/code&gt; IDs without idempotency&lt;/li&gt;
&lt;li&gt;Writing to the wrong user row for a &lt;code&gt;stripe_customer_id&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An &lt;a href="https://www.indiehackers.com/post/i-checked-3-saas-products-built-with-cursor-this-week-all-3-had-the-same-silent-billing-bug-ae30e3cc67" rel="noopener noreferrer"&gt;Indie Hackers thread from April 2026&lt;/a&gt; describes three Cursor-built SaaS products with the same handler: return 200, log the event, never touch the database. Cancelled users keep Pro. MRR looks fine. You only see the leak when you manually compare Stripe to Postgres.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/sravan27/i-keep-finding-the-same-stripe-webhook-bugs-in-saas-launches-4222"&gt;This dev.to post from sravan27&lt;/a&gt; lists the same bugs in the wild: trusting the success redirect, skipping idempotency, letting Pro access drift from the payment source of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduce a revenue leak in 60 seconds (no API keys)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 https://github.com/prodv-dev/prodverdict-sdk.git
&lt;span class="nb"&gt;cd &lt;/span&gt;prodverdict-sdk

npx prodverdict check access &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; examples/nextjs-stripe/prodverdict.yml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fixtures&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fixtures-dir&lt;/span&gt; examples/nextjs-stripe/scenarios/fail-revenue-leak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HIGH] user:usr_alice — Active subscription but has_paid_access is false
fix: Set has_paid_access=true in your webhook handler
VERDICT: FAIL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a production contract: compare live billing state to live database state. Not a lint rule. Not an LLM guess. PASS / WARN / FAIL.&lt;/p&gt;

&lt;h2&gt;
  
  
  What fixes this (with or without a tool)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Stripe owns subscription status. Your DB is a cache.&lt;/li&gt;
&lt;li&gt;Store processed &lt;code&gt;evt_...&lt;/code&gt; IDs with a unique constraint.&lt;/li&gt;
&lt;li&gt;Refetch the subscription from Stripe on critical events. Do not assume event order.&lt;/li&gt;
&lt;li&gt;Run a nightly reconciliation: active Stripe subs vs DB rows, alert on mismatch.&lt;/li&gt;
&lt;li&gt;Block merges when drift exists, not just when mocked unit tests pass.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;jest.mock('stripe')&lt;/code&gt; will never catch "Stripe says active, Postgres says false."&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm building
&lt;/h2&gt;

&lt;p&gt;I run &lt;a href="https://prodverdict.com" rel="noopener noreferrer"&gt;ProdVerdict&lt;/a&gt;, a deterministic contract checker for AI-assisted SaaS. The access contract compares Stripe or Paddle to your Postgres &lt;code&gt;users&lt;/code&gt; table. Config, migration, boundary, webhook, and restore contracts ship in v0.9.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLI + &lt;a href="https://github.com/marketplace/actions/prodverdict" rel="noopener noreferrer"&gt;GitHub Action&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MCP for Cursor agents (billing secrets stay local)&lt;/li&gt;
&lt;li&gt;Free for public repos; fixtures above work without credentials
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prodverdict init &lt;span class="nt"&gt;--stack&lt;/span&gt; nextjs-stripe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm looking for three design partners on real Stripe + Postgres repos to run nightly access checks and publish anonymized drift findings. Comment if you want a free audit with a read-only Stripe key.&lt;/p&gt;

&lt;p&gt;Have you ever found someone paying in Stripe but locked out in your app, or cancelled but still on Pro? How did you catch it?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://prodverdict.com" rel="noopener noreferrer"&gt;prodverdict.com&lt;/a&gt; · &lt;a href="https://github.com/prodv-dev/prodverdict-sdk" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://discord.gg/Mp6mMnmqB6" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>stripe</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>ProdVerdict v0.6: verify billing before your Cursor agent opens a PR</title>
      <dc:creator>Matthew</dc:creator>
      <pubDate>Thu, 11 Jun 2026 07:10:21 +0000</pubDate>
      <link>https://dev.to/mattbaconz/prodverdict-v06-verify-billing-before-your-cursor-agent-opens-a-pr-2bb</link>
      <guid>https://dev.to/mattbaconz/prodverdict-v06-verify-billing-before-your-cursor-agent-opens-a-pr-2bb</guid>
      <description>&lt;p&gt;AI agents ship fast. Tests pass. The PR looks fine. Then Stripe says &lt;strong&gt;active&lt;/strong&gt; and Postgres says &lt;code&gt;has_paid_access = false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProdVerdict v0.6&lt;/strong&gt; adds an agent-first workflow: diagnose credentials, run all contracts, get stable JSON back — for Cursor MCP or CLI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20va214fkm7dt48my0fp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20va214fkm7dt48my0fp.png" alt="ProdVerdict — merge-blocking CI for billing drift, env vars, and migrations" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent loop (new in v0.6)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prodverdict init &lt;span class="nt"&gt;--stack&lt;/span&gt; nextjs-stripe &lt;span class="nt"&gt;--mcp&lt;/span&gt; &lt;span class="nt"&gt;--cursor-rule&lt;/span&gt;
npx prodverdict doctor &lt;span class="nt"&gt;--format&lt;/span&gt; agent
npx prodverdict check all &lt;span class="nt"&gt;--format&lt;/span&gt; agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--format agent&lt;/code&gt; returns &lt;code&gt;schemaVersion: "1"&lt;/code&gt; JSON with &lt;code&gt;summary&lt;/code&gt; and &lt;code&gt;nextSteps&lt;/code&gt; — no LLM in evaluation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor MCP
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;@prodverdict/mcp&lt;/code&gt; to &lt;code&gt;.cursor/mcp.json&lt;/code&gt;. Tools: &lt;code&gt;doctor&lt;/code&gt;, &lt;code&gt;check_all_contracts&lt;/code&gt;, &lt;code&gt;check_access_contract&lt;/code&gt;, &lt;code&gt;check_config_contract&lt;/code&gt;, &lt;code&gt;check_migration_contract&lt;/code&gt;, &lt;code&gt;validate_config&lt;/code&gt;, &lt;code&gt;suggest_fix&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Prompts: &lt;code&gt;setup_prodverdict&lt;/code&gt;, &lt;code&gt;verify_before_pr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Full guide: &lt;a href="https://prodverdict.com/agents" rel="noopener noreferrer"&gt;prodverdict.com/agents&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Three contracts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5y7qxhmostxvm9e2oud1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5y7qxhmostxvm9e2oud1.png" alt="Access, Config, and Migration contracts" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Access&lt;/strong&gt; — Stripe/Paddle vs Postgres billing drift&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Config&lt;/strong&gt; — env var references vs &lt;code&gt;.env.example&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migration&lt;/strong&gt; — unsafe Postgres DDL in agent-generated SQL&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Try without API keys
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 https://github.com/prodv-dev/prodverdict-sdk.git
&lt;span class="nb"&gt;cd &lt;/span&gt;prodverdict-sdk
npx prodverdict check access &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; examples/nextjs-stripe/prodverdict.yml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fixtures&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fixtures-dir&lt;/span&gt; examples/nextjs-stripe/scenarios/fail-revenue-leak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CI enforcement
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prodv-dev/prodverdict-action@v0.6.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./prodverdict.yml&lt;/span&gt;
    &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;access&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.STRIPE_SECRET_KEY }}&lt;/span&gt;
    &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DATABASE_URL }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Billing secrets stay on &lt;strong&gt;your&lt;/strong&gt; runner. The dashboard stores verdict metadata only.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/prodverdict" rel="noopener noreferrer"&gt;GitHub Marketplace&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/prodverdict" rel="noopener noreferrer"&gt;npm&lt;/a&gt; · &lt;a href="https://prodverdict.com/agents" rel="noopener noreferrer"&gt;Agents&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>saas</category>
      <category>github</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Your AI agent shipped a billing bug. ProdVerdict blocks it in CI.</title>
      <dc:creator>Matthew</dc:creator>
      <pubDate>Tue, 09 Jun 2026 12:37:53 +0000</pubDate>
      <link>https://dev.to/mattbaconz/your-ai-agent-shipped-a-billing-bug-prodverdict-blocks-it-in-ci-2gpc</link>
      <guid>https://dev.to/mattbaconz/your-ai-agent-shipped-a-billing-bug-prodverdict-blocks-it-in-ci-2gpc</guid>
      <description>&lt;p&gt;AI coding tools are fast. Tests pass. The PR looks fine. Then production quietly leaks revenue.&lt;/p&gt;

&lt;p&gt;The pattern I kept seeing in vibecoded SaaS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Billing logic lands in a PR&lt;/li&gt;
&lt;li&gt;Webhooks get skipped or half-wired&lt;/li&gt;
&lt;li&gt;Stripe says &lt;strong&gt;active&lt;/strong&gt; while Postgres says &lt;code&gt;has_paid_access = false&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's not a lint issue. That's money walking out the door.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProdVerdict&lt;/strong&gt; is deterministic CI for production contracts — not another AI code reviewer. Zero LLM in the evaluation path. Read-only observations (Stripe/Paddle + your DB) and fixed rules. Same input, same output every time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o7yzkcgzw91h0hnma19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o7yzkcgzw91h0hnma19.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Three contracts in v0.5
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf8zys86qbrijwy4ayjw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf8zys86qbrijwy4ayjw.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Access — billing vs database
&lt;/h3&gt;

&lt;p&gt;Compares live subscription state (Stripe or Paddle) against your Postgres &lt;code&gt;users&lt;/code&gt; table. Catches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Revenue leak&lt;/strong&gt; — active subscription, &lt;code&gt;has_paid_access = false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrongful access&lt;/strong&gt; — cancelled user still has paid features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan drift&lt;/strong&gt; — price ID maps to &lt;code&gt;pro&lt;/code&gt;, row says &lt;code&gt;starter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplicate customer&lt;/strong&gt; — same billing ID on multiple app users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ea4li0gpupay5kfx4b2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ea4li0gpupay5kfx4b2.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Config — env var drift
&lt;/h3&gt;

&lt;p&gt;Scans &lt;code&gt;process.env&lt;/code&gt; references in your code vs &lt;code&gt;.env.example&lt;/code&gt; and CI secrets. The classic "it worked locally" killer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fappfkutmrf1exwq7z2z4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fappfkutmrf1exwq7z2z4.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Migration — unsafe Postgres DDL
&lt;/h3&gt;

&lt;p&gt;Static SQL rules for agent-generated migrations: blocking &lt;code&gt;CREATE INDEX&lt;/code&gt; without &lt;code&gt;CONCURRENTLY&lt;/code&gt;, dangerous &lt;code&gt;NOT NULL&lt;/code&gt; on hot tables, and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgy7a7c346oia9y1kxpi3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgy7a7c346oia9y1kxpi3.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in 10 seconds — no API keys
&lt;/h2&gt;

&lt;p&gt;Clone the SDK once for fixture paths, then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 https://github.com/prodv-dev/prodverdict-sdk.git
&lt;span class="nb"&gt;cd &lt;/span&gt;prodverdict-sdk

npx prodverdict check access &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; examples/paddle-stripe/prodverdict.yml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fixtures&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fixtures-dir&lt;/span&gt; examples/paddle-stripe/scenarios/fail-revenue-leak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see a &lt;strong&gt;FAIL&lt;/strong&gt; with a concrete fix hint:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ql9hwwoldiz5a0d0cmf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ql9hwwoldiz5a0d0cmf.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HIGH] user:usr_alice — Active subscription but has_paid_access is false
fix: Set has_paid_access=true in your webhook handler
VERDICT: FAIL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prodverdict check access &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--config&lt;/span&gt; examples/nextjs-stripe/prodverdict.yml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fixtures&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--fixtures-dir&lt;/span&gt; examples/nextjs-stripe/scenarios/pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add to your repo
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prodverdict init &lt;span class="nt"&gt;--stack&lt;/span&gt; nextjs-stripe
&lt;span class="c"&gt;# or: npx prodverdict init --stack paddle-stripe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit &lt;code&gt;prodverdict.yml&lt;/code&gt;, add secrets, and wire the GitHub Action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prodv-dev/prodverdict-action@v0.5.0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./prodverdict.yml&lt;/span&gt;
    &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;access&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;STRIPE_SECRET_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.STRIPE_SECRET_KEY }}&lt;/span&gt;
    &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DATABASE_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runs on every PR. Secrets never leave your runner. Optional dashboard stores verdict metadata only — not subscription rows or PII.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzbgwttgwwin97y0ygl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwzbgwttgwwin97y0ygl7.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install from &lt;a href="https://github.com/marketplace/actions/prodverdict" rel="noopener noreferrer"&gt;GitHub Marketplace&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/prodverdict" rel="noopener noreferrer"&gt;npm&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/@prodverdict/mcp" rel="noopener noreferrer"&gt;MCP for Cursor/Claude&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How this differs from AI code review
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;AI code review&lt;/th&gt;
&lt;th&gt;ProdVerdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation&lt;/td&gt;
&lt;td&gt;LLM suggestions&lt;/td&gt;
&lt;td&gt;Deterministic rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;Source code diff&lt;/td&gt;
&lt;td&gt;Live billing + DB state (or fixtures)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;"Consider checking…"&lt;/td&gt;
&lt;td&gt;PASS / WARN / FAIL with fix hints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI behavior&lt;/td&gt;
&lt;td&gt;Optional, noisy&lt;/td&gt;
&lt;td&gt;Merge-blocking on HIGH&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Agents can call ProdVerdict via MCP &lt;em&gt;before&lt;/em&gt; opening a PR. Enforcement still happens in CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt; — public repos, CLI, GitHub Action, MCP, Access + Config contracts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro ($39/project/mo)&lt;/strong&gt; — private repos, scheduled checks, dashboard history&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're on &lt;a href="https://www.producthunt.com/products/prodverdict" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt; — use code &lt;strong&gt;PRODUCTHUNT&lt;/strong&gt; at checkout for 3 months free Pro.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Webhook contract, API boundary checks (mass-assignment / forbidden fields), and more stack templates. Open an issue on &lt;a href="https://github.com/prodv-dev/prodverdict-sdk" rel="noopener noreferrer"&gt;prodverdict-sdk&lt;/a&gt; if you want a rule prioritized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the scariest prod bug an agent ever shipped for you?&lt;/strong&gt; Drop it in the comments — I'm collecting patterns for the next contracts.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ProdVerdict is MIT-licensed (SDK + Action). &lt;a href="https://prodverdict.com" rel="noopener noreferrer"&gt;prodverdict.com&lt;/a&gt; · &lt;a href="https://discord.gg/Mp6mMnmqB6" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>github</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>Building Phonton: a local-first AI coding CLI that verifies diffs before review</title>
      <dc:creator>Matthew</dc:creator>
      <pubDate>Sun, 03 May 2026 04:33:25 +0000</pubDate>
      <link>https://dev.to/mattbaconz/building-phonton-a-local-first-ai-coding-cli-that-verifies-diffs-before-review-1hbn</link>
      <guid>https://dev.to/mattbaconz/building-phonton-a-local-first-ai-coding-cli-that-verifies-diffs-before-review-1hbn</guid>
      <description>&lt;p&gt;I have been building &lt;strong&gt;Phonton CLI&lt;/strong&gt;, an open-source local-first AI coding agent.&lt;/p&gt;

&lt;p&gt;The idea is simple: instead of treating an AI coding tool like a chat box, Phonton treats it like an engineering workflow.&lt;/p&gt;

&lt;p&gt;It tries to follow this loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You give it a goal.&lt;/li&gt;
&lt;li&gt;It creates a plan.&lt;/li&gt;
&lt;li&gt;It works against your local repo context.&lt;/li&gt;
&lt;li&gt;It verifies the generated diff.&lt;/li&gt;
&lt;li&gt;You review the result before accepting it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most AI coding tools are optimized for speed and convenience. Phonton is more focused on making AI-generated changes easier to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I wanted a CLI agent that was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local-first&lt;/li&gt;
&lt;li&gt;BYOK, so you use your own provider keys&lt;/li&gt;
&lt;li&gt;review-oriented&lt;/li&gt;
&lt;li&gt;built around verification&lt;/li&gt;
&lt;li&gt;able to remember repo decisions locally&lt;/li&gt;
&lt;li&gt;useful from the terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to replace every tool like Claude Code, Codex, Cursor, or OpenCode. The goal is to explore a stricter workflow for AI-assisted coding: &lt;strong&gt;plan, verify, review, then ship&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current status
&lt;/h2&gt;

&lt;p&gt;Phonton is still early alpha.&lt;/p&gt;

&lt;p&gt;It currently has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Rust CLI/TUI&lt;/li&gt;
&lt;li&gt;provider adapters&lt;/li&gt;
&lt;li&gt;planning&lt;/li&gt;
&lt;li&gt;local memory&lt;/li&gt;
&lt;li&gt;repo indexing&lt;/li&gt;
&lt;li&gt;verification flow&lt;/li&gt;
&lt;li&gt;review commands&lt;/li&gt;
&lt;li&gt;checkpoint/rollback work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are still rough edges, and I am not claiming it is production-ready yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; phonton-cli
phonton doctor
phonton plan &lt;span class="s2"&gt;"add input validation to config loading"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/phonton-dev/phonton-cli" rel="noopener noreferrer"&gt;https://github.com/phonton-dev/phonton-cli&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would appreciate feedback from developers who already use AI coding agents and care about local-first workflows, reviewable diffs, and verification.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>opensource</category>
      <category>rust</category>
    </item>
    <item>
      <title>SIGNAL; shrinking agent skills so context stays for code</title>
      <dc:creator>Matthew</dc:creator>
      <pubDate>Sat, 18 Apr 2026 16:49:12 +0000</pubDate>
      <link>https://dev.to/mattbaconz/signal-shrinking-agent-skills-so-context-stays-for-code-40p1</link>
      <guid>https://dev.to/mattbaconz/signal-shrinking-agent-skills-so-context-stays-for-code-40p1</guid>
      <description>&lt;p&gt;&lt;strong&gt;SIGNAL&lt;/strong&gt; is a small open-source &lt;strong&gt;agent skill bundle&lt;/strong&gt; for people who hit &lt;strong&gt;context limits&lt;/strong&gt;: tiered modes, symbolic shorthand, checkpoints, a disk-backed &lt;code&gt;.signal_state.md&lt;/code&gt;, and separate skills for &lt;strong&gt;diff/search summaries&lt;/strong&gt; and &lt;strong&gt;git&lt;/strong&gt; (commit / push / PR) plus &lt;strong&gt;structured review&lt;/strong&gt;. Each skill ships as readable &lt;code&gt;*.md&lt;/code&gt; and a tight &lt;code&gt;*.min.md&lt;/code&gt; so you can load less instruction surface when you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add mattbaconz/signal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Repo: github.com/mattbaconz/signal
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Benchmarks (honest caveat)&lt;/strong&gt;&lt;br&gt;
The repo includes scripted fixtures and heuristic token estimates (ceil(chars/4)). That’s useful for comparing shapes, not for quoting exact billed tokens from a provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I’d like from readers&lt;/strong&gt;&lt;br&gt;
If you’ve tried skills packs or fat AGENTS.md files: does the canonical + minified split match how you’d maintain this, or is it too much friction? I’m open to blunt feedback.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
