ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-07-15Advanced

Quarantining the Dependencies Your Agent Adds, Before They Install

When an agent adds a dependency overnight, nobody reviews the lifecycle scripts that run at install time. Here is how I turned the default off and built a quarantine score to let the safe ones through.

Antigravity332npm5supply chainpostinstallunattended runs2

Premium Article

The tasks I had queued for the agent overnight were done by morning. Tests passing. Scrolling through the diff, I noticed one new line in package.json: a small library for parsing CLI arguments. Four-digit weekly downloads. Published eleven days ago.

Nothing was wrong with it functionally. But the moment that dependency unpacked into node_modules, a postinstall script had run once on my machine. The agent had done exactly the job it was given — make the tests pass. Reading that script was a job nobody had been assigned.

As an indie developer running several apps alongside a set of Stripe-billed sites, the only thing that quietly grows is the number of times a dependency decision gets made. The same machine also builds what I ship to the App Store. That is why one added line bothered me.

npm install is not a download. It is an execution. Back when I added dependencies by hand, there was a beat before I typed that line — enough to glance at the name, maybe search it. Hand the work to an agent and that beat disappears.

What npm install Actually Runs

Of npm's lifecycle scripts, three can fire from a dependency: preinstall, install, and postinstall. The part that matters is that this is not limited to your direct dependencies. Scripts belonging to a transitive dependency six levels down run with the same permissions, as the same user.

So the boundary you are defending is not "the packages I chose." It is "the entire tree the packages I chose dragged along." When an agent is adding dependencies, that boundary can widen overnight.

HookWhen it firesTypical legitimate use
preinstallBefore the package unpacksEnvironment checks (rarely needed)
installRight after unpackingBuilding native addons
postinstallAfter installFetching binaries, applying patches

The legitimate uses are real. Native addons and tools that fetch platform-specific binaries do not work without them. Which means "ban everything" is not a policy anyone sticks to. The policy that survives is: off by default, allowed by name.

Flipping the Default

Defaults and config locations differ by package manager. Here is what I actually set across four repositories.

ToolDependency scripts by defaultHow to block or allow
npmRunignore-scripts=true in .npmrc; run allowed ones manually
pnpm (v10+)Do not runOnly packages listed in pnpm.onlyBuiltDependencies run
Yarn (Berry)Do not runenableScripts / dependenciesMeta in .yarnrc.yml

If you are on pnpm, the safe default is already yours. You only need to be explicit about the allowlist.

{
  "pnpm": {
    "onlyBuiltDependencies": ["esbuild", "sharp", "@swc/core"]
  }
}

On npm, you invert the default yourself.

# .npmrc (repo root, committed)
ignore-scripts=true

The honest problem: some packages break under ignore-scripts=true. Anything that fetches a binary — sharp, esbuild — will fail. And it fails in an unhelpful way. The install succeeds. Then the app starts and tells you a binary is missing.

So reverse the order. Instead of hunting for breakage after the fact, count what will stop first. Across four repositories, the steps that worked for me were these three:

  1. Inventory every dependency in the tree that carries a script (Implementation 1)
  2. Sort that list into an allowlist and a drop-candidate list
  3. Flip the default and let only the allowlist through

Done in this order, you know the blast radius before you start. The first time I did it backwards, isolating the cause alone cost me half a day.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
The .npmrc and pnpm settings that stop install-time scripts by default, and how to find what breaks when you do
A working script that scores new dependencies on age, weekly downloads, name edit distance, and install scripts
A gate for unattended runs, plus one month of real numbers (87% auto-passed, 13% held, and where the false positives landed)
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-07-14
Protecting Screenshot Tests for AdMob Screens from Ad Nondeterminism
Screens with ads turn red on every screenshot run, and eventually nobody reviews the diffs. Here is a design that seals off AdMob banner nondeterminism and leaves only real layout breaks in your checks, with Compose code and Antigravity-driven diff triage.
App Dev2026-07-14
When the Deploy Was Green but Users Still Saw the Old Build: Field Notes on a Gate That Verifies Your Shipped Commit Reached the Edge
When a deploy reports success but production keeps serving the old build, a post-deploy gate that verifies your shipped commit actually reached the edge via a build stamp closes the gap. Field notes with real operational numbers.
App Dev2026-07-10
An Agent's ORM Code Made p95 Five Times Slower — Measuring Query Counts and Blocking Them in CI
N+1 queries slip past code review because the code looks correct. Here is a CI gate that measures query counts and judges them by their slope against input size, with working code and real numbers.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →