Skip to content
Back to skills

Dependency Hygiene

ASecurity

Use when adding, upgrading, or resolving Python/Node dependencies — declare every import, cap majors to stop silent drift, and keep the resolver consistent. Prevents undeclared-import and silent-major-bump defects.

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 11, 2026
developmentpythonrustgonoderailsapibackend

Works with

  • cli
  • api

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 11, 2026

npx -y skills add SkyyRoseLLC/DevSkyy --skill dependency-hygiene --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dependency Hygiene?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dependency Hygiene
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/skyyrosellc-dependency-hygiene/badge)](https://www.skillsdirectory.com/skills/skyyrosellc-dependency-hygiene)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dependency-hygiene
description: Use when adding, upgrading, or resolving Python/Node dependencies — declare every import, cap majors to stop silent drift, and keep the resolver consistent. Prevents undeclared-import and silent-major-bump defects.
origin: SkyyRose
---

# Dependency Hygiene

An honest dependency graph is not "the install works" — it is **declare-what-you-import**
plus **cap-majors-that-matter**, so the resolver's output is deterministic instead of
whatever the last `pip install` happened to land on. This is **bug-254**: a shared venv
silently drifted from openai 1.x to openai 2.45.0 because nothing capped it, and the graph
had a load-bearing import (`litellm`) that was never declared at all.

> **Boot first:** read `pyproject.toml` (the dependency groups and their inline rationale
> comments) → `.wolf/buglog.json` (grep `bug-254` — the reference case is already logged)
> → `CLAUDE.md`. Do not pin from memory of what a library "usually" needs.

## When to Use

- Adding a new `import`/`require` that isn't already in `pyproject.toml` / `package.json`.
- Upgrading any dependency, especially a transitive one pulled in by another package.
- `pip check` / `npm ls` reports a conflict, or `pip install -e ".[all]"` takes 20+ minutes
  backtracking.
- Before trusting a green install after adding an optional extras group.

## Method

1. **Every top-level import is declared.** If a file does `import litellm` or
   `require("boto3")`, that package name is in `pyproject.toml` (or `package.json`) in a
   group that actually gets installed for that code path — not assumed present because a
   sibling dependency happens to pull it in transitively. `litellm/providers/
   litellm_provider.py` imported `litellm` while it was undeclared in every group; the
   only reason `pip check` ever saw it was because something else's transitive graph
   happened to install it.
2. **Cap majors on load-bearing libraries.** A library your codebase has a specific client
   contract with (the openai 1.x SDK surface, in this repo's case) gets an explicit
   `<major+1` ceiling — `"openai>=1.6,<2"` — not just a floor. Without the ceiling, a
   transitive pin from an unrelated package (litellm's own `openai==2.30.0` requirement)
   can silently bump the whole shared venv to a major your code was never verified against.
   Document *why* the cap sits where it does, inline, next to the pin — see
   `pyproject.toml:93-97` (`litellm>=1.80,<1.81` — 1.80.x is the last line admitting
   openai 1.x; 1.81+ requires openai>=2.8) as the pattern to follow.
3. **Prefer `uv pip install` when pip's resolver backtracks.** Plain `pip install -e
   ".[all]"` spent 20+ minutes backtracking through the openai/litellm conflict; `uv pip
   install` resolved the same graph in seconds. Reach for `uv` first on any group with
   more than a few pinned ranges.
4. **Never hardcode secrets while touching dependency config.** API keys some new
   integration needs go in `.env` / `.env.secrets` via env vars, never inline in
   `pyproject.toml`, a lockfile, or a test fixture — see `CLAUDE.md` Critical Rules.

## Loop until pip check is clean

Bounded, like [[drive-to-green]] — never more than 5 turns, stop if the same conflict
repeats twice (that's guessing, not resolving):

```
1. Change one dependency (declare / bump / cap).
2. Run `pip check` (or `npm ls` for Node).
3. Run the test suite for the affected module.
4. On conflict: cap the offending major or declare the missing import — never delete
   the constraint that's complaining just to make the tool quiet.
5. Repeat from step 2. Stop when `pip check` prints clean AND the affected suite passes.
```

## Verify from an authoritative source

- **`pip check` must print "No broken requirements found."** Not "fewer errors than
  before" — clean, full stop. Same bar for `npm ls` (no `UNMET DEPENDENCY` / `invalid`
  lines).
- **Grep every top-level import against `pyproject.toml`** to prove each is declared in a
  group that's actually installed for that code path — don't trust that an editable
  install "just has it." This is how bug-254's undeclared `litellm` import and the
  installed-but-undeclared `boto3` fallback (`integrations/cloudflare_r2_manager.py:6`)
  were both found.
- **Re-run the affected test suite after any dependency change** — a clean resolver
  doesn't prove the code still behaves against the newly-resolved version.
- **Use Context7 for version facts** (`resolve-library-id` → `query-docs`) before pinning
  a range — never trust training data on what a library's current major requires; that's
  exactly how the openai/litellm version boundary got missed the first time.

## Adversarial pass

Link [[adversarial-verification]] before calling the graph settled — have an independent
pass try to refute "the dependency graph is consistent": pick one declared pin and ask
whether its stated reason (the inline comment next to it) is still true today, and whether
any *other* installed package's transitive requirement could silently violate it on the
next `pip install`.

## Guardrails · Handoff · Log

- An undeclared import is a **fail-open in the dependency graph** — the install "works"
  today only by accident of some other package's transitive pull. Cross-ref
  [[fail-closed-audit]]: the same "absent input silently passes" pattern, just at the
  resolver layer instead of a runtime gate.
- Backend dependency changes stay in `skyyrose-core`; if a fix requires touching imagery
  or theme build tooling, hand off per `CROSS-PLUGIN.md`, then **re-verify `pip check`
  here** after the handoff lands.
- Log every undeclared-import or silent-major-bump find to `.wolf/buglog.json` under the
  `bug-254` lineage (bump `occurrences`, never duplicate), run
  `scripts/wolf_recurring_sync.py`, and record the lesson via [[continuous-learning]].

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.