AI coding

Teaching an Agent to Read a Lockfile Before Touching Dependencies

Antonio Evans10 min read

A split scene: on the left, a coding agent's terminal window showing a lockfile opened in a text editor with a highlighted section of resolved dependencies and a count of transitive entries; on the right.
Key points

Key points

  1. 1A lockfile-reading instruction in both the system prompt and a repo context file makes the agent report the resolved dependency tree before it edits any manifest.
  2. 2The report should state top-level count, transitive count, and the added, removed and version-changed entries, so the reviewer can check it against the lockfile diff.
  3. 3Lockfiles record resolved versions but do not by themselves prove a package is safe or real, so the same report must name each new package and where it was published.
  4. 4Making the report a precondition turns dependency edits into small, reviewable proposals rather than surprises that surface late in review.

Why the lockfile is the right place to put the brake

A coding agent asked to "add caching" or "fix the date parsing" will often reach for a package. It reads the manifest, sees a name that looks right, and runs an install. What it usually does not do is open the resolved tree that the lockfile records and check what the install will actually pull in. That gap is where review gets expensive: the reviewer ends up reconstructing the dependency change from a diff of hundreds of lines.

The lockfile is the artifact that answers the question "what will actually be installed." npm ls lists the dependencies installed in node_modules and returns a non-zero exit code when the resolved tree does not match what package.json should produce, which is a ready-made consistency check for the agent to run the npm ls walkthrough. npm ls --all prints the full tree including transitive dependencies, and --depth caps how far it descends the Stack Overflow answer on npm ls. Those are the commands a prompt can name explicitly.

The second reason is supply chain. A model can generate an import for a package that does not exist, and an attacker can register that name; the defense is to look up every added name in its registry before anything installs it and to check that changes to the lockfile match the added packages the SpecStory review checklist. Dependency provenance is called out as a pre-screening standard for generated code: confirm the package exists on the canonical registry, matches the intended library, is needed at all, and is pinned through the lockfile, with watch for slopsquatting where attackers register names an assistant might hallucinate the Metacto checklist. Reading the lockfile first is how an agent can satisfy that standard on its own.

There is a live threat model here. One campaign deliberately engineered npm packages to be selected and installed by AI coding agents rather than by people, tracking more than 60 packages and over 300 versions across a seven-month operation, with a parallel effort distributing more than 1,700 malicious packages across npm, PyPI, Go and Rust the CSA research note. Agents that install with minimal vetting are the target. A prompt that forces the tree into the open before the install is a cheap control.

Decision rule: when the report is mandatory

Use the report as a hard precondition when any of these is true, and skip it when none are.

ConditionReport requiredWhy
Manifest edit adds, removes or widens a dependencyYesThe resolved tree changes
Only application code changes, no manifest editNoThe tree is untouched
Lockfile diff touches a transitive entry the agent did not nameYesSomeone else's dependency moved
Lockfile diff appears after a plain npm install with no manifest editYesInstalls can rewrite the lockfile
Overrides or resolutions block is addedYesEvery match of that name is forced

That last row matters more than it looks. npm install can rewrite package-lock.json even when the request did not ask for it, a behavior developers have documented repeatedly the Stack Overflow thread on lockfile rewrites. If the agent ran an install as a side effect, the report is the only place a reviewer will see it.

The prompt pattern that makes the agent read the tree

The instruction has three parts and they must all be present: open the lockfile, count entries at two levels, and print a fixed-shape report before editing. Vague instructions like "be careful with dependencies" are ignored under task pressure. A numbered precondition with an output format is not.

Here is a system prompt block that works with any terminal agent harness. The harness, not the model, supplies the tools and the execution loop, and it is the harness that decides which actions are permitted the AI Engineer overview of coding agents.

DEPENDENCY PRECONDITION (applies to any task that adds, removes,
or changes a dependency, or that runs an install):

1. Before editing any manifest, open the lockfile and read the
   resolved tree. Do not guess package names.
2. Count and report:
   - top-level entries the manifest declares
   - total resolved entries in the lockfile, which includes
     transitive packages
3. For each dependency you intend to change, name it and give the
   current resolved version and the proposed version.
4. Print the report in this exact shape and stop:

   DEPENDENCY REPORT
   lockfile: <path>
   top-level: <n>
   resolved total: <n>
   added: [<name@version> | none]
   removed: [<name@version> | none]
   changed: [<name old -> new> | none]
   new packages not previously in the tree: [<name> published at <registry URL> | none]

5. Do not run an install or edit the manifest until the report has
   been shown and the next instruction is given.
6. After the manifest edit, run the read-only diff command and print
   the same report again from the diff. If the two reports differ,
   stop and explain the difference before doing anything else.

Two details carry most of the weight. First, the counting step forces a real read: an agent that has not parsed the lockfile cannot produce a number that survives a spot check. Second, the "print twice" rule catches the most common failure, where the agent's stated intent and the actual resolved tree diverge.

Notice that the prompt asks for the lockfile path. A repository may contain more than one, and Python projects frequently carry a requirements.txt alongside a poetry lock. Naming the file removes ambiguity.

Context-file rules that back it up

A system prompt can be lost in long sessions; a repository context file is read on every run. Put the same rule there, in shorter form, and mark it as a precondition rather than advice. A checklist saved as a pull request template only fills the body of a pull request opened through the browser, not one opened through the API, which is a useful reminder that file-based rules only cover the paths that actually read the file the SpecStory review checklist. Keep the prompt copy as the enforcement and the file copy as the reminder.

# Dependency rules

- Never add, remove or bump a dependency without first printing a
  DEPENDENCY REPORT (see system prompt) built from the lockfile.
- Read the lockfile as the source of truth for resolved versions.
  The manifest shows intent; the lockfile shows what installs.
- For every new package name, state where it is published and why
  an existing dependency cannot do the job.
- Prefer an edit to application code over a new dependency when the
  task can be done with the standard library or something already
  in the tree.
- After any manifest edit, run the read-only lockfile diff and
  repeat the report. Differences must be explained, not smoothed.

The "prefer existing" rule is what keeps dependency growth honest. A single package can pull in hundreds of transitive entries: installing a full React toolchain historically added over 1,200 packages, while a small state library adds one, and the gap is supply chain surface, install time and version conflict probability the pkgpulse analysis of dependency trees. An agent that has counted the tree is far less casual about adding to it.

Worked example: package-lock.json

Suppose the agent is asked to add retry logic to an HTTP client that already uses a package in the tree. The naive move is npm install p-retry. The prompt forces a different sequence.

Step one, read the tree. npm ls --all prints the full resolved tree, and npm ls --depth=0 prints the top level only the Stack Overflow answer on npm ls. The lockfile itself is JSON, so the agent can also count entries directly: top-level entries are the keys the manifest declares, and the resolved total is the number of package entries in the lockfile's package map.

Step two, print the report before touching anything:

DEPENDENCY REPORT
lockfile: package-lock.json
top-level: 14
resolved total: 212
added: [[email protected]]
removed: [none]
changed: [none]
new packages not previously in the tree:
  p-retry published at registry.npmjs.org
  retry published at registry.npmjs.org

Step three, make the edit and run the read-only diff. Note the wording: read-only. Running npm install to see what changes is exactly the behavior that rewrites the lockfile by surprise.

npm install p-retry --package-lock-only
git diff --stat package-lock.json package.json
git diff package-lock.json | grep -E '^\+ +"node_modules/' | wc -l

The first command updates the lockfile without touching node_modules, so the diff reflects resolution only. The count from the third command is the number of new resolved entries, and it should equal the number of new packages in the report. If the report said two new packages and the diff shows eleven, the agent has to explain the other nine before proceeding.

Step four, check the second report against the first. Anything the agent did not predict, especially a version bump on a transitive package it never named, is a finding. npm audit and the registry lookups come next, but only after the counts reconcile.

A useful check on override blocks: when a manifest adds an overrides entry, npm forces every instance of that package name in the tree to the declared version, whether a direct or transitive dependency the HeroDevs guide to npm overrides. That is a single line in the manifest that can move dozens of resolved entries, so the report must count the diff, not the manifest line.

Worked example: poetry.lock

The same pattern transfers to Python, with different commands. Poetry writes its lock hash into poetry.lock and a stale hash means the lockfile does not match pyproject.toml, so poetry check --lock is the first thing to run. If it fails, the agent must say so before proposing anything.

Reading the resolved tree is a two-step: poetry show --tree prints the dependency graph, and poetry show --no-dev excludes development groups so the agent reports the production tree separately. Counting resolved entries is a matter of counting [[package]] blocks in the lockfile, which is a fixed string, so it can be done with grep -c.

poetry check --lock
grep -c '^\[\[package\]\]' poetry.lock
poetry show --no-dev | wc -l
poetry add httpx --lock
git diff --stat poetry.lock pyproject.toml
grep -E '^\+name = ' poetry.lock

The last command lists names added to the lockfile, which is the diff-side equivalent of the "added" line in the report. The two should match entry for entry.

The report shape stays identical, which matters for review: a reviewer reading a mixed-language monorepo sees the same six fields regardless of the package manager.

Fieldpackage-lock.jsonpoetry.lock
Resolved totalpackage entries in the JSON mapcount of [[package]] blocks
Top-levelkeys the manifest declaresdirect dependencies in pyproject.toml
Consistency checknpm ls exit codepoetry check --lock
Tree viewnpm ls --allpoetry show --tree
Lockfile-only updatenpm install --package-lock-onlypoetry add --lock
Diff-side added listnew node_modules/ keysadded name = lines

Checking the agent's report against the diff

The report is only worth requiring if someone checks it. Treat it like any other claim in a change: technical facts and data overrule opinions, which is the first principle in Google's review guidance the Google standard of code review. A dependency report is data, so it can be verified mechanically.

Four checks, in order:

  1. Recount the resolved total from the lockfile on the branch and compare it with the number in the report. The difference should equal added minus removed.
  2. List added and removed names from the lockfile diff and compare them with the report's two lists. Every name in the diff must appear in the report.
  3. For each new name, confirm it exists in the canonical registry and state why an existing dependency could not do the job.
  4. For each changed version, ask whether the change was requested. A transitive bump that no one asked for is a scope question.

The fourth check is where the intent-and-scope discipline from the review literature pays off. Each changed file should serve the task or carry a stated reason, and the task should be compared against the change rather than against the agent's own description of it the SpecStory review checklist. The report is the agent's description; the diff is the change. When they agree, the reviewer can spend attention on design and behavior, which is where review adds the most value what to look for in a code review.

Teams that have adopted a standard for AI-generated changes usually place dependency provenance early, with a named owner for that check the Metacto checklist. The report makes that ownership cheap: the owner checks counts and names, not a rolling diff.

There is a second-order benefit. Research on generated code keeps finding that a large share of samples carry security flaws or design weaknesses, which is one more reason reviewers should not be the first people to reason about a change the CSET report on cybersecurity risks of AI-generated code and the CSA analysis of security risks in AI-generated code. Moving one class of first-order reasoning, the dependency tree, to the agent's own preconditions frees reviewer attention for logic and access control.

What the report cannot prove

Be clear about the limits. A lockfile proves which resolved versions will install; it does not prove a package is benign, maintained, or correctly licensed. It also does not prove that the target version still contains the function the code calls, and a real API check belongs in review, where every imported module and method should be confirmed against the version in use the Metacto checklist. Treat the report as a scope and surface tool, then run the audit and license checks as usual.

One more limit: agents can be steered by the documentation of the packages they consider. Because an assistant evaluates candidate packages by reading their docs and metadata rather than running them, a carefully crafted README can bias a choice the CSA research note. A report that names the registry location for each new package at least gives the reviewer a place to look.

Rolling it out on a team

Start with the two files and one reviewer. Add the prompt block to the agent's system instructions, add the rules file to the repository root, and ask one reviewer to check reports against diffs for a week. You will learn within a few changes whether the agent is reading the lockfile or paraphrasing it.

Expect some tuning. Agents that treat the report as a formality will produce identical numbers for different trees; the recount check catches that. Agents that over-report will pad the report with the full transitive list; cap it at the three lists and a total. If your team reviews with a shared template, put the four checks in the dependency section so they travel with the change object rather than living in someone's head the SpecStory review checklist.

For teams that want the agent side handled for them, an expert that reads your repository context and returns finished deliverables fits the loop described here, and Quanta experts can run the dependency prerequisite as part of its normal work. The prompt and context-file patterns above remain the portable part; they work with any harness that lets you set instructions and read tool output.

One last habit: keep the report in the pull request body. A reviewer who can read the agent's stated intent next to the diff spends less time reconstructing what happened, and a future reader who wants to know why a package entered the tree has an answer in the history rather than in a lost chat.

FAQ

FAQ

How do I stop an agent from running installs while it explores?

Remove install commands from the tools the agent can call during planning, or require an explicit confirmation step. The prompt pattern here asks for the report before any manifest edit and permits only lockfile-only commands such as npm install --package-lock-only, which update resolution without touching the installed tree.

What if the repository has both a lockfile and a pinned requirements file?

Report on the file the build actually reads, and say which one that is in the report's first line. If two files both influence installation, the precondition applies to both and the two reports must agree; a mismatch is a finding for the reviewer, not something the agent should average.

Should the report include development dependencies?

Yes, but separately. Count and list development entries apart from production entries, the same way poetry show --no-dev separates them. A dependency added for tests still lands on every developer machine and in CI images, so it deserves the same provenance check.

How large a lockfile diff should a reviewer accept?

The report makes size less important than shape: a diff whose added names match the report, with a resolved total that reconciles, is reviewable at any size. A large diff whose added names exceed the report is a stop, regardless of how plausible the change looks.

Does this replace dependency scanning tools?

No. Scanning tools check known vulnerabilities and licenses across the tree; the report establishes scope and provenance before the tree changes. Run the scan after the report reconciles, and treat a scanner finding as a reason to reopen the proposal rather than a reason to skip the report.

Sources

Sources

  1. Using npm's ls command for Fun and Insight
  2. How to view the dependency tree of a given npm module?
  3. Code review checklist for AI-generated code - SpecStory
  4. AI-Generated Code Review Checklist: 2026 Standards for Teams - Metacto
  5. Nation-State npm Malware Targets AI Coding Agents
  6. Why does "npm install" rewrite package-lock.json?
  7. Coding agents - AI Engineer
  8. npm Dependency Trees: Most Nested Packages 2026
  9. A Guide to NPM Overrides: Take Control of Your ...
  10. The Standard of Code Review | eng-practices - Google
  11. What to look for in a code review | eng-practices - Google
  12. Cybersecurity Risks of AI-Generated Code | Center for Security ... - CSET
  13. Understanding Security Risks in AI-Generated Code | CSA
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles