Linear rewrote its CI to keep up with AI-generated code
The company behind Linear explains how it cut CI wait time and runner cost after code agents started multiplying the volume of pull requests. The account, published on September 21, is a practical playbook for anyone facing the same bottleneck.
On September 21, 2026, Linear published an internal account describing a problem that any team using copilots and code agents is probably already feeling: the development bottleneck is no longer writing code, it's validating it. According to the post signed by Mufeez Amjad, the company's CTO opened a simple ticket, "CI costs are high," after noticing that agents had made code production exponentially faster, while CI kept running at the same old pace. Every pull request still has to go through the test pipeline, so as the volume of changes grows, the CI queue grows with it, and infrastructure cost rises along with it.
The number that sums up the problem: Linear's test suite has nearly quadrupled since January 2026, but the company managed to cut a PR's CI wait time from more than 6 minutes to just over 5, cutting runner time per test by almost half. This isn't an isolated case of one-off optimization, it's a rework of the entire pipeline, spread across four fronts that are worth reading about for any team running TypeScript, a pnpm monorepo, or GitHub Actions.
Swapping out base infrastructure and tooling
The first gain came without optimizing a single line of the pipeline: migrating GitHub Actions workloads to third-party runners with faster CPUs, better-performing storage, and more efficient caching. In a direct comparison of the two days around the switch, jobs ran 34% faster on average, with some workloads (like tsc) dropping 52%.
The second move was swapping the compiler. Linear migrated to tsgo, the native TypeScript compiler, and that cut the weekly median for the tsc check by 73%, enough to take typechecking off the critical path.
Linting also changed architecture. Some of the custom rules depended on TypeScript type information, which forced ESLint to build the full type graph before evaluating any rule, one of the most memory-heavy jobs in CI. The team rewrote those rules to operate only on the syntax tree (AST), without type information. Result: a 68% reduction in API lint time and 55% in lint time for the whole repository, plus much lower memory use. That change also opened the door to migrating to Oxlint, since purely syntactic rules are far easier to port.
Trimming the jobs that block the rest of the queue
With a faster base, the team looked at the system as a whole and noticed that small gate jobs (checking which paths a PR touched, whether tests had already passed for the same input) sat on the critical path: none of the API's eight test shards could start until those checks finished.
A change-detection job, for example, did a full checkout of the working tree even though it only needed a small fraction of it. Limiting fetch depth brought the slowest gate down from 94 to 20 seconds, and removing checkout from jobs that never needed a working tree cut that time from 27 to 7 seconds. For push and merge queue events, a sparse, blobless checkout with limited history was enough to save another 11 seconds. In total, the median for the change-detection job dropped from 26 to 8 seconds.
The team also identified network instability after switching runners: since they sit outside GitHub's network, they depended on a direct IP link that showed intermittent degradation. The fix was replacing actions/checkout with their own composite action, with retry and backoff, configuring GIT_HTTP_LOW_SPEED_LIMIT and GIT_HTTP_LOW_SPEED_TIME to abort a stuck connection after about 30 seconds instead of hanging indefinitely.
Another simple tweak: writing cache markers, which used to run as part of the final check before merge, was moved to a job that runs after the test shards finish but blocks nothing. That took 42 seconds off the merge path for every PR and merge queue entry.
Cutting the repeated setup in every job
Every CI job pays a fixed cost for runner boot, package installation, and dependency provisioning, a cost that multiplies by the number of shards. Linear attacked this from several angles: pre-installing shared dependencies (like the Postgres client) into its own base CI image, instead of installing them via apt on every shard, which saved 7 to 8 seconds per run.
Since the codebase is a pnpm monorepo, the API test workflow installed the entire workspace even though it only needed the API package and its dependencies. Restricting the install to the needed package cut pnpm install from 44-73 seconds to 16-18 seconds.
A counterintuitive detail: caching node_modules ended up being slower than reinstalling from scratch, because the cache key depended on a lockfile that changes frequently, and even a cache hit took about 28 seconds to restore, versus 7.5 seconds for a filtered install. Together, these three changes cut setup per shard by roughly 44%, from 110-140 seconds down to 67-73 seconds.
Seven independent checks, each of which spun up a runner, did a checkout, and installed dependencies for just seconds of actual useful work, were consolidated into two jobs, running the seven tasks in parallel inside them. Based on June usage, this change alone saved around 87,000 runner minutes a month, equivalent to 11.8% of the company's total CI usage.
Making test execution more efficient
With the fixed cost per shard down, Linear could parallelize the API suite, the largest and most frequently run part of the workflow, more aggressively. Vitest, the test runner used for the TypeScript suites, distributes work by file rather than by each test's duration, so a handful of large files could dominate an entire shard. The fix was breaking those large files into smaller ones while preserving the test structure, and reconfiguring sharding: from three shards at the start of the year to four, and then to eight, which made the critical job about 19% faster and 19% cheaper.
The single biggest optimization came from sharing module state under strict isolation rules. By default, Vitest isolates every test file, which at Linear meant rebuilding the entity graph, GraphQL, and decorators on every shard. The team created an opt-in vitest project with isolate: false, letting safe files share the module registry within each worker. That was worth about 17% in monthly savings, bringing the slowest shard down from 300-379 seconds to around 195 seconds.
This was also the change with the highest correctness risk: it required explicitly marking eligibility with an opt-in comment in each file, adding the necessary teardown for shared state, and leaving out files that used fake timers or unsafely shared state. Since agents already write most of the tests at Linear, the team updated the "agent skills" (the instructions that guide the code agents) so that automatically generated tests already follow these same constraints by default.
What remains open
Linear estimates that, without this effort, today's test suite would take about 11 minutes, nearly double what developers expect now. And the company makes clear that the work isn't over: the codebase keeps growing, with about 2,000 new tests a week, a good share of them generated by agents. For Brazilian teams already feeling the same symptom (PRs piling up, runner minutes climbing on the cloud provider's bill), Linear's playbook serves as a replicable checklist: measure where the critical time actually is before optimizing, separate fixed setup from test execution, and treat sharding as a cost decision, not just a speed one. The point that may deserve the most attention from anyone already using code agents day to day is the last one: if AI generates the tests, the performance and isolation conventions also need to be in the instructions it follows, or the problem simply recreates itself every sprint.
Translated from the Brazilian Portuguese original · Read the original
China-linked hackers use AI pentesting tool to breach ConnectWise, Microsoft says
Microsoft attributed to a group tracked as Storm-0940 the use of the ARTEX AI pentesting framework to compromise ConnectWise and target hundreds of organizations worldwide. ConnectWise is a platform used by MSPs that serve companies in Brazil.





