know.2nth.ai Software Packages & dependencies
software · Packages · Skill Leaf

You write a little. You ship a lot.

Almost no modern software is written from scratch. You write a thin layer of your own code on top of hundreds of packages other people wrote — pulled from a registry, pinned by a lockfile, and shipped as part of your product. That dependency graph is enormous leverage and a real risk surface at the same time, and it's one an AI agent now reaches into every time it runs install.

Registries SemVer & lockfiles Supply chain Reproducible installs

The dependency graph.

A package is a reusable chunk of code someone published so others don't have to rewrite it — a date library, an HTTP client, a UI framework. A registry is the public warehouse those packages live in. A package manager (npm, pip, cargo) is the tool that downloads the ones you ask for, plus everything they depend on, and so on down the tree.

That last part is the whole story. You add one dependency; it pulls in five; each of those pulls in more. The result is a dependency graph that can run to hundreds or thousands of packages from people you've never heard of — and all of it ships inside your product and runs with your product's permissions. You wrote maybe 5% of the code your users run. The other 95% is the graph.

The manifest and the lockfile

Two files describe your dependencies. The manifest (package.json, pyproject.toml, Cargo.toml) lists what you asked for, usually as version ranges. The lockfile (package-lock.json, poetry.lock, Cargo.lock) records the exact version of every package — direct and transitive — that was actually installed. Commit both. The manifest is intent; the lockfile is the reproducible reality.

One per ecosystem.

Each language has its dominant registry and manager. They differ in size and culture, but the model is the same everywhere.

EcosystemRegistry · managerNotes
JavaScript / TSnpm · npm / pnpm / bunThe largest registry on earth (millions of packages). Huge leverage, huge surface — tiny packages and deep trees are the norm.
PythonPyPI · pip / uv / poetryThe default for data, ML, and scripting. uv is the fast modern installer; lockfiles via poetry/uv.
Rustcrates.io · cargoBest-in-class tooling — cargo handles build, test, and deps as one. Strong culture of small, well-audited crates.
Java / JVMMaven Central · Maven / GradleEnterprise mainstay. Heavier, but mature security and provenance tooling.

The pattern repeats for every language (Go modules, RubyGems, NuGet, Packagist). The skill isn't memorising commands — it's understanding that every ecosystem gives you the same deal: enormous reuse in exchange for trusting a lot of strangers' code, mediated by versioning and lockfiles.

SemVer is the contract; the lockfile is the proof.

Semantic versioning (SemVer) is the convention that makes the whole system tractable. A version is MAJOR.MINOR.PATCH — bump patch for a bug fix, minor for a backwards-compatible feature, major for a breaking change. It's a promise from the author to you: "upgrading within the same major version won't break you." Your manifest leans on that promise by allowing ranges (e.g. "any 4.x").

Promises get broken, which is why the lockfile exists. It pins the exact resolved versions so that install produces an identical dependency tree on your machine, your colleague's, CI, and production — today and in six months. Without a committed lockfile, "it worked yesterday" and "it works on my machine" become genuine, unanswerable mysteries. With one, an install is reproducible, and reproducibility is the foundation everything else (debugging, audit, rollback) stands on.

Pin, then update deliberately

The healthy rhythm: commit the lockfile so installs are reproducible, then update dependencies on purpose — on a branch, through CI, reviewed in a PR — rather than letting them drift. Tools like Dependabot/Renovate open those update PRs automatically, so upgrades become small, tested, reviewable changes instead of a scary big-bang. Same discipline as everything else in this branch: change deliberately, gate it, keep it reversible.

You own code you didn't write.

The flip side of all that reuse: every package in your graph is code running with your product's trust. If one is malicious or compromised, so is your product. This is the software supply chain, and it's a live attack surface.

Typosquatting

A name one letter off

A malicious package named to look like a popular one (reqests for requests). Install the wrong name and you've run someone's payload.

Account takeover

A maintainer compromised

A legitimate, widely-used package gets a malicious release after its maintainer's account is hijacked. Your auto-update pulls it in.

Transitive risk

Deep in the tree

The dangerous package is rarely the one you chose — it's five levels down, a dependency of a dependency you never evaluated.

Abandonment

Unmaintained & unpatched

A package that's no longer maintained accumulates known vulnerabilities with no fixes coming. Stale is its own risk.

The defences are practical and mostly free: commit lockfiles (so a surprise version can't sneak in); run automated vulnerability scanning (npm audit, GitHub Dependabot alerts, pip-audit); prefer fewer, well-maintained dependencies over many obscure ones; review what an update actually changes before merging it; and for regulated work, generate an SBOM (software bill of materials) so you can answer "what's actually in our product?" when — not if — the next big vulnerability lands.

Agents install dependencies too.

A coding agent building a feature does what a developer does: it reaches for packages and runs install. That's a real expansion of the supply-chain surface — an agent can pull in a dependency no human explicitly chose, and it can be fooled by a plausible-but-wrong package name just as a human can (arguably more so, since it's optimising for "something that works" at speed).

The mitigations are the ones this whole branch keeps returning to. The agent's work lands as a pull request, so a human sees exactly which dependencies it added before anything ships. CI runs the audit on every change, flagging known-vulnerable packages automatically. The lockfile diff in the PR makes new dependencies visible and reviewable. And for untrusted execution, the agent runs in a sandbox with restricted network and filesystem access, so a malicious install can't reach your secrets or your network. Agent autonomy over dependencies is safe for exactly the same reason agent autonomy over code is: the gate, not the trust.

Review the lockfile diff — every time

The single highest-value habit when an agent (or anyone) adds a dependency: actually look at the lockfile diff in the PR. It shows every package — direct and transitive — that the change brings in. A feature that should need one small library but adds forty packages is a signal worth pausing on, whether a human or an agent wrote it.

Reproducibility beats bandwidth anxiety.

Lockfiles, caching, and a known-good build

On bandwidth that's expensive or intermittent, reproducible installs matter twice over: a committed lockfile plus a CI cache means builds don't re-download the world on every run, and a clean checkout produces an identical, known-good dependency tree even months later. For regulated SA work, the lockfile and an SBOM are also the evidence base for "what third-party code is in the system touching this data?" — the question POPIA and security reviews eventually ask. Pinned, scanned dependencies turn that from a scramble into a lookup.

Where this links in the tree.

Primary sources only.