<?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: Shachar Solomon</title>
    <description>The latest articles on DEV Community by Shachar Solomon (@shacharsol).</description>
    <link>https://dev.to/shacharsol</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3865787%2Fa5eb9ac7-e950-4fa2-a2ba-2df8545e72e3.jpeg</url>
      <title>DEV Community: Shachar Solomon</title>
      <link>https://dev.to/shacharsol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shacharsol"/>
    <language>en</language>
    <item>
      <title>I forgot I installed my own CI tool. It caught me shipping 4 bugs.</title>
      <dc:creator>Shachar Solomon</dc:creator>
      <pubDate>Sat, 11 Apr 2026 18:01:02 +0000</pubDate>
      <link>https://dev.to/shacharsol/i-forgot-i-installed-my-own-ci-tool-it-caught-me-shipping-4-bugs-295l</link>
      <guid>https://dev.to/shacharsol/i-forgot-i-installed-my-own-ci-tool-it-caught-me-shipping-4-bugs-295l</guid>
      <description>&lt;p&gt;Four type errors didn't ship to main last week.&lt;/p&gt;

&lt;p&gt;Not because I caught them. I'd already done the ritual — &lt;code&gt;pnpm lint&lt;/code&gt;, &lt;code&gt;npx tsc --noEmit -p apps/api/tsconfig.json&lt;/code&gt;, &lt;code&gt;pnpm test&lt;/code&gt;. Three greens. I was one &lt;code&gt;git push&lt;/code&gt; away from landing all four on main.&lt;/p&gt;

&lt;p&gt;A pre-push hook I'd forgotten I'd installed stopped the push and said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;typecheck&lt;/code&gt; failed — 4 errors&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I sat there for a second. &lt;em&gt;I just checked. With my own eyes. Three times.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It was right. I was wrong. Here's exactly what it found, in the order it found them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 1: coverage enforcement had been silently off for weeks
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vitest.config.ts(19,7): error TS2769: No overload matches this call.
  Object literal may only specify known properties,
  and 'lines' does not exist in type 'CoverageOptions'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vitest v4 moved coverage thresholds from the top level into a nested &lt;code&gt;thresholds: {}&lt;/code&gt; key. My config had &lt;code&gt;lines/functions/branches/statements&lt;/code&gt; at the old level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before — silently ignored&lt;/span&gt;
&lt;span class="nx"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="nl"&gt;coverage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;thresholds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vitest reads the old key, shrugs, ignores it, enforces nothing. My tests had been "passing coverage" for an indeterminate number of weeks with zero coverage actually checked.&lt;/p&gt;

&lt;p&gt;No lint rule catches this. No test catches this. It requires &lt;code&gt;tsc&lt;/code&gt; pointed at &lt;code&gt;vitest.config.ts&lt;/code&gt; — which nothing in my dev loop ever did, because root-level config files don't live inside any workspace package's &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 2: a string that forgot to be a union
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tests/services/tenant.test.ts(37,41): error TS2345:
  Type 'string' is not assignable to type
  '"us-east-1" | "us-west-2" | "eu-west-1" | "ap-southeast-1"'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Classic TypeScript widening. &lt;code&gt;config: { region: 'us-east-1' }&lt;/code&gt; — TypeScript widens the literal &lt;code&gt;'us-east-1'&lt;/code&gt; to &lt;code&gt;string&lt;/code&gt;, which isn't assignable to the &lt;code&gt;Region&lt;/code&gt; union my function actually requires. Fix is one &lt;code&gt;as const&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tenantData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;orgId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;org-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Acme Corp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;acme.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;          &lt;span class="c1"&gt;// widened to string&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tenantData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;orgId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;org-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Acme Corp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;acme.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// preserves the literal&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same structural problem as Bug 1: &lt;code&gt;tests/services/&lt;/code&gt; is a root-level test directory that lives outside any project's &lt;code&gt;tsconfig.json&lt;/code&gt; include. My &lt;code&gt;pnpm lint&lt;/code&gt; fans out to per-project &lt;code&gt;tsc&lt;/code&gt; runs. None of them ever looked at this file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 3: &lt;code&gt;.avg&lt;/code&gt; on a &lt;code&gt;number&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tests/services/metrics.test.ts(167,32): error TS2339: Property 'avg' does not exist on type 'number'.
tests/services/metrics.test.ts(168,32): error TS2339: Property 'min' does not exist on type 'number'.
tests/services/metrics.test.ts(169,32): error TS2339: Property 'max' does not exist on type 'number'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one embarrassed me most. I'd refactored &lt;code&gt;aggregateMetrics&lt;/code&gt; to return &lt;code&gt;number[]&lt;/code&gt; at some point and forgotten to update the test. The test was still asserting &lt;code&gt;aggregated[0].cpu.avg&lt;/code&gt;, &lt;code&gt;.min&lt;/code&gt;, &lt;code&gt;.max&lt;/code&gt; — properties that don't exist on a primitive number.&lt;/p&gt;

&lt;p&gt;In TypeScript: three explicit errors. In JavaScript: &lt;code&gt;.avg&lt;/code&gt; on a number silently returns &lt;code&gt;undefined&lt;/code&gt;, then &lt;code&gt;.cpu&lt;/code&gt; on &lt;code&gt;undefined&lt;/code&gt; throws at runtime, but only for the specific shape of the test data I happened to pass. On slightly different inputs it might silently return nonsense. On the inputs my test used, it happened to look fine.&lt;/p&gt;

&lt;p&gt;Same structural problem as Bugs 1 and 2. Same dev-loop blind spot. Same fix: point &lt;code&gt;tsc&lt;/code&gt; at the file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 4: the meta-bug that hid the other three
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apps/api/src/app/types.ts(2,6): error TS2304: Cannot find name 'KVNamespace'.
apps/api/src/app/types.ts(3,6): error TS2304: Cannot find name 'R2Bucket'.
apps/api/src/app/types.ts(4,14): error TS2304: Cannot find name 'Queue'.
apps/api/src/app/types.ts(7,17): error TS2304: Cannot find name 'DurableObjectNamespace'.
apps/api/src/app/types.ts(8,6): error TS2552: Cannot find name 'D1Database'.
... 200+ more errors across 50+ files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My root &lt;code&gt;tsconfig.json&lt;/code&gt; was the template every monorepo template ships with. No &lt;code&gt;include&lt;/code&gt;, no &lt;code&gt;exclude&lt;/code&gt;, no &lt;code&gt;types&lt;/code&gt;, no &lt;code&gt;baseUrl&lt;/code&gt;, no &lt;code&gt;paths&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES2022"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES2022"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"forceConsistentCasingInFileNames"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resolveJsonModule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isolatedModules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"declaration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"declarationMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sourceMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because it had no &lt;code&gt;include&lt;/code&gt;, running &lt;code&gt;tsc --noEmit&lt;/code&gt; from the repo root pulled in every &lt;code&gt;.ts&lt;/code&gt; file in the project, tried to compile them under the root's type set, and exploded with 200+ errors from Cloudflare Worker code that depends on &lt;code&gt;@cloudflare/workers-types&lt;/code&gt; — which the root tsconfig doesn't load.&lt;/p&gt;

&lt;p&gt;Total noise. Unrunnable. &lt;strong&gt;My response, months ago, was to pin my dev-loop &lt;code&gt;tsc&lt;/code&gt; command to &lt;code&gt;-p apps/api/tsconfig.json&lt;/code&gt; — the one project that worked cleanly.&lt;/strong&gt; That gave me fast, clean typechecks for &lt;code&gt;apps/api&lt;/code&gt;, and a silent blind spot everywhere else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bug 4 didn't cause Bugs 1–3. Bug 4 was the condition in which Bugs 1–3 could live forever.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fixing Bug 4 was the last step. After adding &lt;code&gt;include&lt;/code&gt;, &lt;code&gt;exclude&lt;/code&gt;, &lt;code&gt;types: []&lt;/code&gt;, and workspace &lt;code&gt;paths&lt;/code&gt;, bare &lt;code&gt;tsc&lt;/code&gt; from the repo root now exits 0. It took four minutes. It could have taken four minutes any time in the last six months. I just never had a reason to do it, because I'd already built a workaround I didn't have to think about.&lt;/p&gt;

&lt;h2&gt;
  
  
  The line I want you to remember
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It's not that my CI catches things my local environment doesn't. It's that my CI runs the commands I stopped running.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the whole thesis. Every one of those four bugs was catchable by &lt;code&gt;tsc&lt;/code&gt;. The same &lt;code&gt;tsc&lt;/code&gt; that ships with TypeScript. The same binary I already have installed. I just couldn't — or wouldn't — type the command that would have caught them, because I'd spent months engineering my dev loop around a broken root config I didn't want to fix.&lt;/p&gt;

&lt;p&gt;A pre-push hook that runs your pipeline automatically eliminates that drift by removing the human who "just skips this one this time." That's it. That's the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the tool did, exactly
&lt;/h2&gt;

&lt;p&gt;Here's the part I want to be specific about, because the specifics are the value:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pushci init&lt;/code&gt; walked my repo and detected two Node workspace projects&lt;/strong&gt; — &lt;code&gt;apps/api&lt;/code&gt; and &lt;code&gt;apps/web&lt;/code&gt;. It read each project's &lt;code&gt;tsconfig.json&lt;/code&gt; independently instead of trying to compile the whole tree under one root config. No &lt;code&gt;KVNamespace&lt;/code&gt; noise, no avoidance pattern required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It read my &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; and chose &lt;code&gt;pnpm run build&lt;/code&gt; over bare &lt;code&gt;npx vite build&lt;/code&gt;&lt;/strong&gt;, so the auto-detected commands actually run in a pnpm workspace. (That one was a recent fix. I was dogfooding the fix when it caught me. Recursion everywhere.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It generated a &lt;code&gt;pushci.yml&lt;/code&gt; pipeline I didn't have to write&lt;/strong&gt;, with &lt;code&gt;install&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;lint&lt;/code&gt;, &lt;code&gt;typecheck&lt;/code&gt; stages. I edited it later. I didn't need to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It installed a git pre-push hook I forgot about in about ten minutes&lt;/strong&gt;, because the best developer tools are the ones you stop noticing. The next push I did — the one with the four bugs in it — the hook fired, ran my pipeline, caught them, blocked the push. None of the four reached main. The commit that &lt;em&gt;did&lt;/em&gt; reach main had all four already fixed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Scoreboard
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bugs about to ship&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bugs that shipped&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install time&lt;/td&gt;
&lt;td&gt;90 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SaaS accounts created&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YAML files written by hand&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub webhooks installed&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pieces of local state I had to maintain&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What this is, in one breath
&lt;/h2&gt;

&lt;p&gt;One binary. &lt;code&gt;npm install -g pushci&lt;/code&gt;. Auto-detects your stack across 33 languages. Generates &lt;code&gt;pushci.yml&lt;/code&gt; from your repo structure. Installs a git pre-push hook that runs the pipeline locally before every push. No SaaS, no dashboard, no account, no credit card, no GitHub App, no &lt;code&gt;.github/workflows/&lt;/code&gt; to maintain. Runs inside Claude Code, Cursor, and Windsurf sandboxes where GitHub Actions can't reach — which is, for what it's worth, what I was originally dogfooding when it caught me.&lt;/p&gt;

&lt;p&gt;I wrote it. I forgot I installed it. It caught me anyway.&lt;/p&gt;

&lt;p&gt;Ninety seconds to install it and find your own seam:&lt;br&gt;
&lt;/p&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; pushci
pushci init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other ways that work today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;finsavvyai/tap/pushci                &lt;span class="c"&gt;# macOS + Linux&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://pushci.dev/install.sh | sh     &lt;span class="c"&gt;# any POSIX shell&lt;/span&gt;
npx pushci init                                    &lt;span class="c"&gt;# no install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tomorrow you'll either find zero bugs and forget about it, or you'll find one bug and keep it forever. Those are the only two outcomes.&lt;/p&gt;

&lt;p&gt;— Shahar&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pushci.dev" rel="noopener noreferrer"&gt;pushci.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ci</category>
      <category>devtools</category>
      <category>monorepo</category>
      <category>typescript</category>
    </item>
    <item>
      <title>PushCI v1.3.0: Your CI Tool Supports Three Languages and You Are Fine With That?</title>
      <dc:creator>Shachar Solomon</dc:creator>
      <pubDate>Thu, 09 Apr 2026 21:39:59 +0000</pubDate>
      <link>https://dev.to/shacharsol/pushci-v130-your-ci-tool-supports-three-languages-and-you-are-fine-with-that-541i</link>
      <guid>https://dev.to/shacharsol/pushci-v130-your-ci-tool-supports-three-languages-and-you-are-fine-with-that-541i</guid>
      <description>&lt;p&gt;&lt;em&gt;33 language stacks. Performance tracing. Flaky test detection. Still $0.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Let Me Get This Straight
&lt;/h2&gt;

&lt;p&gt;Your CI platform — the one you're paying for — supports Go, Node, and Python. That's it. That's the list. Meanwhile your actual team has a Terraform module, a Rust CLI, a Kotlin microservice, and an intern who insists on writing everything in Elixir.&lt;/p&gt;

&lt;p&gt;So what happens when someone pushes the Terraform module? Nothing. It goes through. Unvalidated. Like a passport control agent who only speaks three languages working at an international airport.&lt;/p&gt;

&lt;p&gt;I got tired of pretending this was acceptable.&lt;/p&gt;

&lt;p&gt;PushCI v1.3.0 supports &lt;strong&gt;33 language stacks&lt;/strong&gt;. Because that's how many languages people actually use.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;33 stacks&lt;/strong&gt;: Go, Node/TS, Python, Rust, Java, C#, Ruby, PHP, Swift, Dart, Elixir, Zig, Kotlin, Lua, Perl, R, Julia, OCaml, Nim, Crystal, Erlang, V, Terraform, Helm, Solidity/Foundry, Bun, Fortran — plus framework pipelines for Expo, Electron, Angular, Vue, CRA, and T3&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;22 CLI commands&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;69 marketplace skills&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;57 integration tests + 11 E2E tests&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every stack tested. Every pipeline validated. Not "community maintained." Not "beta support." Tested.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's New
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Performance Tracing with Perfetto
&lt;/h3&gt;

&lt;p&gt;I asked my DevOps guy where the bottleneck was. He said "somewhere in the build." Somewhere. In the build. That's like a doctor saying the problem is "somewhere in your body."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pushci run &lt;span class="nt"&gt;--trace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generates Chrome Trace Event JSON. Drag it into &lt;a href="https://ui.perfetto.dev" rel="noopener noreferrer"&gt;ui.perfetto.dev&lt;/a&gt; and see exactly which step took 47 seconds while the rest finished in 3. No other CI tool does this. Zero. I checked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flaky Test Detection
&lt;/h3&gt;

&lt;p&gt;The test passed on your machine. It passed in CI. It passed 9 out of 10 times. But on that tenth time, the whole team stops what they're doing for a meeting about "test reliability."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pushci run &lt;span class="nt"&gt;--stress&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runs each check 10 times. Color-coded flake rate report. Now you have proof that &lt;code&gt;test_payment_webhook&lt;/code&gt; fails 30% of the time instead of everyone pretending it doesn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallel Agents with Git Worktree Isolation
&lt;/h3&gt;

&lt;p&gt;Build, test, security scan, and deploy — all running simultaneously on isolated git worktrees. Race strategy (first agent wins) or consensus (all must agree).&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="na"&gt;agents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;race&lt;/span&gt;
  &lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;security&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your CI pipeline just became a parallel processing system instead of a sad, sequential queue.&lt;/p&gt;

&lt;h3&gt;
  
  
  5 Notification Channels
&lt;/h3&gt;

&lt;p&gt;Slack, Discord, Email, Telegram, Webhook. All of them. On every run.&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="na"&gt;notifications&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;slack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;webhook&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$SLACK_WEBHOOK&lt;/span&gt;
  &lt;span class="na"&gt;discord&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;webhook&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$DISCORD_WEBHOOK&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;team@company.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No marketplace plugin. No third-party integration. Just add it to &lt;code&gt;pushci.yml&lt;/code&gt; and it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive Dashboard Charts
&lt;/h3&gt;

&lt;p&gt;Victory.js charts replacing the hand-rolled SVG situation we had before. Build time trends, flaky test rates, cost savings over time. Looks like a real product now because it is one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tailscale Fleet Discovery
&lt;/h3&gt;

&lt;p&gt;Got a fleet of runners across machines? PushCI discovers peers via Tailscale MagicDNS with tag-based filtering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pushci fleet discover &lt;span class="nt"&gt;--tag&lt;/span&gt; ci-runner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Distributed CI across your actual infrastructure. Not rented infrastructure. Yours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Llamafile Lifecycle
&lt;/h3&gt;

&lt;p&gt;Run AI diagnosis without sending your code to anyone's cloud:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pushci llamafile download mistral-7b
pushci llamafile start
pushci diagnose &lt;span class="nt"&gt;--local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Download, start, stop LLM models locally. AI-powered pipeline diagnosis at $0 with zero data leaving your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Free Tier Promise
&lt;/h2&gt;

&lt;p&gt;Let me be very clear about what "free" means here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unlimited repos&lt;/li&gt;
&lt;li&gt;Unlimited local runs&lt;/li&gt;
&lt;li&gt;All 33 language stacks&lt;/li&gt;
&lt;li&gt;Performance tracing&lt;/li&gt;
&lt;li&gt;Flaky test detection&lt;/li&gt;
&lt;li&gt;All install methods&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$0. Forever. Not a trial.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your machine runs the tests. Your machine pays the electricity bill. We don't get involved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pro&lt;/strong&gt; ($9/mo) adds AI diagnosis, cloud runners, and priority support for when you want someone else's computer involved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team&lt;/strong&gt; ($29/seat) adds SSO, audit logs, 25 members, and an SLA for when your company requires a piece of paper that says someone is responsible.&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;&lt;span class="c"&gt;# Install&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; pushci

&lt;span class="c"&gt;# Or Homebrew&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;finsavvyai/tap/pushci

&lt;span class="c"&gt;# Or just run it&lt;/span&gt;
npx pushci init

&lt;span class="c"&gt;# Set up CI in 30 seconds&lt;/span&gt;
pushci init

&lt;span class="c"&gt;# Run with performance tracing&lt;/span&gt;
pushci run &lt;span class="nt"&gt;--trace&lt;/span&gt;

&lt;span class="c"&gt;# Stress test for flaky tests&lt;/span&gt;
pushci run &lt;span class="nt"&gt;--stress&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Website&lt;/strong&gt;: &lt;a href="https://pushci.dev" rel="noopener noreferrer"&gt;pushci.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/finsavvyai/push-ci.dev" rel="noopener noreferrer"&gt;github.com/finsavvyai/push-ci.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Homebrew&lt;/strong&gt;: &lt;code&gt;brew install finsavvyai/tap/pushci&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm&lt;/strong&gt;: &lt;code&gt;npm install -g pushci&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard&lt;/strong&gt;: &lt;a href="https://app.pushci.dev" rel="noopener noreferrer"&gt;app.pushci.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;So you're paying per minute for a CI tool that supports three languages, can't tell you where the bottleneck is, has no idea which tests are flaky, and runs everything sequentially. And when you asked about it, someone said "that's just how CI works." No. That's just how bad CI works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;pushci.dev&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>opensource</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Told My CI/CD to Configure Itself. It Did. In 30 Seconds.</title>
      <dc:creator>Shachar Solomon</dc:creator>
      <pubDate>Tue, 07 Apr 2026 11:59:30 +0000</pubDate>
      <link>https://dev.to/shacharsol/pushci-i-built-a-free-cicd-tool-that-replaces-github-actions-in-30-seconds-2a02</link>
      <guid>https://dev.to/shacharsol/pushci-i-built-a-free-cicd-tool-that-replaces-github-actions-in-30-seconds-2a02</guid>
      <description>&lt;p&gt;Let me get this straight.&lt;/p&gt;

&lt;p&gt;You WROTE a config file. To TELL a computer. To run a TEST. That YOUR computer could run. For FREE.&lt;/p&gt;

&lt;p&gt;And you're paying $0.008 per minute for that privilege.&lt;/p&gt;

&lt;p&gt;I'm looking at my GitHub Actions bill right now. We're paying... to LINT. We're paying someone to run eslint. I could run eslint. My toaster could run eslint.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Vibe-Coding Era Has a CI/CD Problem
&lt;/h2&gt;

&lt;p&gt;We're in 2026. Nobody writes code anymore. You tell Claude to build your app, Cursor autocompletes your dreams, and Copilot finishes your sentences before you think them.&lt;/p&gt;

&lt;p&gt;But CI/CD? Still stuck in 2019.&lt;/p&gt;

&lt;p&gt;Still writing 50-line YAML files by hand. Still Googling "github actions cache node_modules" for the 47th time. Still debugging indentation errors in a config file that runs &lt;code&gt;npm test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The AI writes your code. But YOU have to write the YAML that tests the code the AI wrote.&lt;/p&gt;

&lt;p&gt;Let that sink in.&lt;/p&gt;

&lt;h2&gt;
  
  
  So I Fixed It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx pushci init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole setup. 30 seconds. AI scans your repo, detects your stack, generates the pipeline. You push code, it runs. Done.&lt;/p&gt;

&lt;p&gt;No YAML. No config file. No 45-minute detour into GitHub Actions documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Just Happened
&lt;/h2&gt;

&lt;p&gt;PushCI used AI to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look at your repo and figure out you're running Next.js with TypeScript&lt;/li&gt;
&lt;li&gt;Generate build, test, lint, and deploy steps&lt;/li&gt;
&lt;li&gt;Install a git hook so it runs before every push&lt;/li&gt;
&lt;li&gt;Run everything on YOUR machine. For $0. Forever.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Supports &lt;strong&gt;19 languages&lt;/strong&gt;, &lt;strong&gt;40+ frameworks&lt;/strong&gt;, &lt;strong&gt;16 deploy targets&lt;/strong&gt;. Works with GitHub, GitLab, AND Bitbucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers That Make DevOps Guys Go Quiet
&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;PushCI&lt;/th&gt;
&lt;th&gt;GitHub Actions&lt;/th&gt;
&lt;th&gt;GitLab CI&lt;/th&gt;
&lt;th&gt;Jenkins&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup&lt;/td&gt;
&lt;td&gt;30 sec&lt;/td&gt;
&lt;td&gt;30+ min&lt;/td&gt;
&lt;td&gt;30+ min&lt;/td&gt;
&lt;td&gt;Hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Config&lt;/td&gt;
&lt;td&gt;AI auto&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;Groovy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;$0.008/min&lt;/td&gt;
&lt;td&gt;$0.008/min&lt;/td&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local runs&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with&lt;/td&gt;
&lt;td&gt;GH+GL+BB&lt;/td&gt;
&lt;td&gt;GitHub only&lt;/td&gt;
&lt;td&gt;GitLab only&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;1,000 builds/month at 8 minutes each?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Actions: &lt;strong&gt;$768/year&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;PushCI: &lt;strong&gt;$0/year&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Also Fixes Itself
&lt;/h2&gt;

&lt;p&gt;Your pipeline breaks at 2am? PushCI auto-diagnoses it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pushci heal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;26+ failure patterns. Missing dependencies, flaky tests, format errors, timeouts. It figures out the root cause and patches it. While you sleep.&lt;/p&gt;

&lt;p&gt;No other CI tool does this. Not GitHub Actions. Not GitLab. Not Jenkins. Not the $15/user one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your AI Agent Can Set It Up
&lt;/h2&gt;

&lt;p&gt;Claude Code, Cursor, Windsurf — they can all use PushCI directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pushci"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pushci"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tell your AI: "set up CI for this project." It does the rest. The AI writes the code AND the CI. Full circle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Awkward Part
&lt;/h2&gt;

&lt;p&gt;I showed PushCI to our DevOps engineer. Ran &lt;code&gt;npx pushci init&lt;/code&gt;. Pipeline generated. Tests passing. 30 seconds.&lt;/p&gt;

&lt;p&gt;Long silence.&lt;/p&gt;

&lt;p&gt;"Well... this is embarrassing."&lt;/p&gt;

&lt;p&gt;"What is?"&lt;/p&gt;

&lt;p&gt;"I spent three days on our GitHub Actions workflow."&lt;/p&gt;

&lt;p&gt;"Three DAYS?"&lt;/p&gt;

&lt;p&gt;"There were caching issues."&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 pushci init               &lt;span class="c"&gt;# AI detects your stack&lt;/span&gt;
pushci run                     &lt;span class="c"&gt;# Run CI locally, $0&lt;/span&gt;
pushci heal                    &lt;span class="c"&gt;# Auto-fix broken pipelines&lt;/span&gt;
pushci ask &lt;span class="s2"&gt;"deploy to staging"&lt;/span&gt; &lt;span class="c"&gt;# Natural language CI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://pushci.dev" rel="noopener noreferrer"&gt;pushci.dev&lt;/a&gt; | &lt;a href="https://pushci.dev/vs/github-actions" rel="noopener noreferrer"&gt;vs GitHub Actions&lt;/a&gt; | &lt;a href="https://pushci.dev/tools/cost-calculator" rel="noopener noreferrer"&gt;Cost Calculator&lt;/a&gt; | &lt;a href="https://github.com/finsavvyai/push-ci.dev" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stop writing YAML. It's 2026.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>github</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
