skills/code-analysis/dependency-resolver/SKILL.md
Diagnoses and resolves package dependency conflicts — version mismatches, diamond dependencies, cycles — across npm, pip, Maven, Cargo, and similar ecosystems. Use when install fails with a resolution error, when two packages require incompatible versions of a third, or when upgrading one dependency breaks another.
npx skillsauth add santosomar/general-secure-coding-agent-skills dependency-resolverInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Dependency conflicts are a constraint satisfaction problem. The manifest is a set of version constraints; the resolver tries to pick one version per package that satisfies all of them. When it can't, you have to change a constraint.
| Conflict | Symptom | Root cause | | ----------------------- | ---------------------------------------------------- | ------------------------------------------- | | Diamond | A needs X@2, B needs X@1, you need A and B | Transitive deps disagree on a shared dep | | Upper-bound collision | A needs X<3, you need X>=3 | A pinned too tightly, hasn't updated | | Peer dep mismatch | npm: "X@2 requires peer Y@^1 but Y@2 is installed" | Peer deps — caller must provide, and did wrong | | Cycle | A depends on B depends on A | Bad package design (rare in published pkgs, common in monorepos) | | Yanked / missing | Version in lockfile no longer on registry | Upstream pulled it (security or mistake) |
Before fixing, understand. Every ecosystem has a tree command:
| Ecosystem | Tree command |
| --------- | ------------------------------------------------- |
| npm | npm ls <pkg> or npm ls --all |
| pip | pipdeptree or pip show <pkg> for one level |
| Maven | mvn dependency:tree -Dincludes=<group>:<artifact> |
| Gradle | gradle dependencies --configuration runtimeClasspath |
| Cargo | cargo tree -i <pkg> (inverted — who depends on this) |
| Go | go mod graph | grep <module> |
Find every path to the conflicting package. The conflict is at the merge point.
your-app
├── [email protected] ── requests@^2.28
└── [email protected] ── requests@>=2.20,<2.26
requests@^2.28 means >=2.28, <3.0. Intersection with >=2.20,<2.26 is empty. No version satisfies both.
Who's wrong? Usually the upper-bounded one (legacy-sdk). Upper bounds on deps are almost always too pessimistic — legacy-sdk probably works fine with [email protected] but the author pinned defensively.
| Strategy | When | Risk |
| ----------------------------- | -------------------------------------------------- | -------------------------------------- |
| Update the stale dep | [email protected] might have relaxed the bound | None if it exists — check changelog |
| Override / force resolution | Tell the resolver "use [email protected] anyway" | legacy-sdk might actually break |
| Fork and patch | Fork legacy-sdk, bump its requests bound, publish privately | Maintenance burden |
| Vendor / inline | Copy legacy-sdk into your repo, drop its requests dep | Loses upstream updates |
| Remove one side | Do you actually need legacy-sdk? | Feature loss |
Ecosystem-specific overrides:
| Ecosystem | Override mechanism |
| --------- | --------------------------------------------------------------- |
| npm | overrides in package.json (npm 8+), or resolutions (yarn) |
| pip | No first-class override — use constraints file, or fork |
| Maven | <dependencyManagement> forces a version for all transitives |
| Gradle | resolutionStrategy.force 'group:artifact:version' |
| Cargo | [patch.crates-io] section — replace a dep with a fork |
| Go | replace directive in go.mod |
Error:
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! Found: [email protected]
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.0" from [email protected]
Tree:
$ npm ls react
├── [email protected] ← your direct dep
└── [email protected]
└── react@^17.0.0 (peer) ← wants 17.x
Diagnosis: old-chart-lib declares react@^17 as a peer dep — it was written for React 17, never updated.
Resolution ladder:
npm view old-chart-lib versions → 2.1.0 is latest. No fix upstream.old-chart-lib actually break on React 18? Read its React usage — if it uses no removed APIs, the peer bound is overly tight."overrides": { "old-chart-lib": { "react": "$react" } }
$react means "use whatever version I have at the top level." Forces old-chart-lib to accept React 18.old-chart-lib, fix the actual incompatibility (likely a removed lifecycle method), use npm:@yourorg/old-chart-lib.In monorepos: pkg-a depends on pkg-b depends on pkg-a. Most resolvers handle this (npm, Cargo). Some don't (pip, without -e). Either way it's a smell.
Break the cycle by extracting the shared piece:
pkg-a ─────► pkg-b pkg-a ──► pkg-shared ◄── pkg-b
▲ │ →
└───────────┘
Whatever pkg-a needs from pkg-b and vice versa — that's pkg-shared.
--force / --legacy-peer-deps as a permanent fix. It silences the resolver; it doesn't resolve anything. The conflict is still there at runtime.requests<3 in your package is how you become someone else's diamond problem.## Conflict
<resolver error, verbatim>
## Tree
<paths to the conflicting package — npm ls / cargo tree / etc output>
## Diagnosis
Conflicting constraints: <X requires Y@A> vs <Z requires Y@B>
Intersection: <empty | range>
Suspected over-constrainer: <which one's bound is probably wrong>
## Resolution
Strategy: <update | override | fork | vendor | remove>
Change:
<diff to manifest/lockfile>
Risk: <what might break — and how you verified it doesn't>
## Verification
<install succeeds, tests pass, feature using the overridden dep works>
development
Extracts human-readable pseudocode from a verified formal artifact (Dafny, Lean, TLA+) while preserving the verified properties as annotations, so the proof-carrying logic can be reimplemented in a production language. Use when porting verified code to an unverified target, when documenting what a formal spec actually does, or when handing a verified algorithm to an implementer.
development
Translates natural-language or pseudocode descriptions of concurrent and distributed systems into TLA+ specifications ready for the TLC model checker. Identifies state variables, actions, type invariants, safety properties, and liveness properties from the description. Use when formalizing a protocol, when the user describes a distributed algorithm to verify, when designing a consensus or locking scheme, or when starting formal verification of a concurrent system.
testing
Reduces a TLA+ model so TLC can actually check it — shrinks constants, adds state constraints, abstracts data, or applies symmetry — when the state space is too large to enumerate. Use when TLC runs out of memory, when checking takes hours, or when a spec works at N=2 and you need confidence at larger scale.
development
TLA+-specific instance of model-guided repair — reads a TLC error trace, identifies the enabling condition that should have been false, strengthens the corresponding action, and maps the fix to source code. Use when TLC reports an invariant violation or deadlock and you have the code-to-TLA+ mapping from extraction.