| name | dependency-management |
| description | Python dependency and environment management for multi-service or monorepo python backends. Use when: (1) adding, upgrading, or removing a Python package, (2) responding to Dependabot or security vulnerability alerts (GHSA/CVE), (3) creating a new service that needs its own requirements files, (4) debugging pip install failures or Docker build issues related to dependencies, (5) reviewing or auditing the dependency tree, (6) running pip-compile. Enforces the pip-compile locked-file workflow and tiered dependency hierarchy.
|
| allowed-tools | Bash, Read, Write |
Dependencies
This skill requires Python 3.8+ and standard library only. No external packages needed.
To install this skill's dependencies:
pip-compile ./requirements.in
pip install -r ./requirements.txt
See ./requirements.txt for the dependency lockfile (currently empty — standard library only).
Dependency Management
- One runtime per service. Each isolated service owns its own
./requirements.txt lockfile.
Plugin & Skill Script Architecture (Hub-and-Spoke)
- DRY in source - Hub-and-Spoke. One canonical script file lives at
plugins/<plugin-name>/scripts/. Skills that need it use a file-level symlink in their own scripts/ directory pointing back to the root (ln -s ../../../scripts/foo.py).
- File-level symlinks only. Never symlink entire directories. The Bridge Installer (
bridge_installer.py) only resolves individual file-level symlinks. Directory-level symlinks are silently dropped by binary packaging tools.
- Self-contained at install. The installer (
bridge_installer.py) resolves all symlinks to physical copies when deploying to .agents/. This ensures every skill is independently runnable regardless of the source mono-repo's presence.
- Windows Compatibility. The
plugin_installer.py uses a 3-tier strategy for Windows:
- Symlink (if Developer Mode is on)
- Junction (fallback for directory-level logic, though file-level is preferred)
- Full Copy (ultimate fallback)
This resolution ensures the Hub-and-Spoke pattern works cross-platform.
- No Cross-Plugin Script Execution. A skill should never execute
python ../../other-plugin/scripts/foo.py. If a cross-plugin capability is needed, use Agent Skill Delegation: instruct the Agent to invoke the target skill via the conversation layer. In the mono-repo source, cross-plugin file-level symlinks are acceptable for shared logic that the installer will then resolve.
Repository Layout (Example)
src/
├── requirements-core.in # Tier 1: shared baseline (fastapi, pydantic…)
├── requirements-core.txt # Lockfile for core
├── services/
│ ├── auth_service/
│ │ ├── requirements.in # Tier 2: inherits core + auth deps
│ │ └── ./requirements.txt
│ ├── payments_service/
│ │ ├── requirements.in
│ │ └── ./requirements.txt
│ └── database_service/
│ ├── requirements.in
│ └── ./requirements.txt
Tiered Hierarchy
| Tier | Scope | File | Examples |
|---|
| 1 – Core | Shared by >80% of services | requirements-core.in | fastapi, pydantic, httpx |
| 2 – Specialized | Service-specific heavyweights | <service>/requirements.in | stripe, redis, asyncpg |
| 3 – Dev tools | Never in production containers | requirements-dev.in | pytest, black, ruff |
Each service .in file usually begins with -r ../../requirements-core.in to inherit the core dependencies.
Workflow: Adding or Upgrading a Package
-
Declare — Add or update the version constraint in the correct .in file.
- If the package is needed by most services →
requirements-core.in
- If only one service → that service's
.in
- Security floor pins use
>= syntax: cryptography>=46.0.5
-
Lock — Compile the lockfile:
pip-compile src/requirements-core.in \
--output-file src/requirements-core.txt
pip-compile src/services/auth_service/requirements.in \
--output-file src/services/auth_service/./requirements.txt
Because services inherit core via -r, recompiling a service also picks up core changes.
-
Sync — Install locally to verify:
pip install -r src/services/<service>/./requirements.txt
-
Verify — Rebuild the affected Docker/Podman container to confirm stable builds.
-
Commit — Stage and commit both .in and .txt files together.
Workflow: Responding to Dependabot / Security Alerts
-
Identify the affected package and fixed version from the advisory (GHSA/CVE).
-
Determine tier placement:
- Check if the package is a direct dependency (appears in an
.in file).
- If it only appears in
.txt files, it's transitive — pinned by something upstream.
-
For direct dependencies: Bump the version floor in the relevant .in file.
# SECURITY PATCHES (Mon YYYY)
package-name>=X.Y.Z
-
For transitive dependencies: Add a version floor pin in the appropriate .in file
to force the resolver to pull the patched version, even though it's not a direct dependency.
-
Recompile all affected lockfiles. Since services inherit core, a core change means
recompiling every service lockfile. Use this compilation order:
pip-compile src/requirements-core.in \
--output-file src/requirements-core.txt
for svc in auth_service payments_service database_service; do
pip-compile "src/services/${svc}/requirements.in" \
--output-file "src/services/${svc}/./requirements.txt"
done
-
Verify the patched version appears in all affected .txt files:
grep -i "package-name" src/requirements-core.txt \
src/services/*/./requirements.txt
-
If no newer version exists (e.g., inherent design risk like pickle deserialization),
document the advisory acknowledgement as a comment in the .in file and note mitigations.
Container / Dockerfile Constraints
- Dockerfiles only use
COPY ./requirements.txt + RUN pip install -r ./requirements.txt.
- No
RUN pip install <pkg> commands. No manual installs.
- Copy
./requirements.txt before source code to preserve Docker layer caching.
Common Pitfalls
- Forgetting to recompile downstream services after a core
.in change.
- Pinning
== instead of >= for security floors — use >= so pip-compile can resolve freely.
- Adding dev tools to production
.in files — keep pytest, ruff, etc. in requirements-dev.in.
- Committing
.txt without .in — always commit them as a pair.