Repository navigation
[BUG] apm install keeps transitive dependencies of a local package after the package's manifest stops declaring them #3401
Description
Summary
When a local-path dependency removes one of its own dependencies from its apm.yml, a plain apm install in the
consuming project still installs the removed package and records it in apm.lock.yaml as resolved_by the local
package. The installed copy of the local package in apm_modules/ shows the new manifest without the dependency, so the
lock file and the dependency graph disagree with the manifests actually installed. Only apm install --refresh or
apm install --update prunes it. Running apm uninstall and then installing again also clears it.
The same happens when the consuming project changes the path of a local dependency to a new build of the same package
(same name, so the same _local/<name> key) whose manifest no longer declares the dependency.
Environment
- APM CLI 0.35.0 (latest release, v0.35.0)
- macOS (Darwin arm64), Python 3.15.2
Steps to reproduce
R=$(mktemp -d); cd "$R"
mk() {
mkdir -p "$1/.apm/skills/$1"
printf -- '---\nname: %s\ndescription: test skill %s\n---\n# %s\n' "$1" "$1" "$1" > "$1/.apm/skills/$1/SKILL.md"
}
mk pkg-b; printf 'name: pkg-b\nversion: 1.0.0\n' > pkg-b/apm.yml
mk pkg-a; printf 'name: pkg-a\nversion: 1.0.0\ndependencies:\n apm:\n - ../pkg-b\n' > pkg-a/apm.yml
mkdir proj && cd proj && git init -q && mkdir .github
printf 'name: proj\nversion: 1.0.0\ndependencies:\n apm:\n - ../pkg-a\n mcp: []\n' > apm.yml
apm install --target copilot
apm deps tree # pkg-a -> pkg-b (correct)
# pkg-a no longer depends on pkg-b
printf 'name: pkg-a\nversion: 1.0.0\n' > ../pkg-a/apm.yml
apm install --target copilot # "Installed 2 APM dependencies"
apm deps tree # still pkg-a -> pkg-b
ls .agents/skills # pkg-a pkg-b
find apm_modules -path '*pkg-a*' -name apm.yml -exec cat {} \;
# installed pkg-a manifest has no dependencies
apm install --target copilot --refresh # "Installed 1 APM dependency (2 stale files cleaned)"Expected behavior
After the manifest change, apm install re-reads the local package's manifest (it already copies the new manifest into
apm_modules/), resolves pkg-a with no dependencies, removes pkg-b from apm.lock.yaml, and cleans up the files it
deployed (.agents/skills/pkg-b). A local-path dependency has no ref to pin, so reusing its locked transitive set seems
unintended. At minimum, apm install should warn that the locked graph no longer matches the installed manifests.
Actual behavior
apm installreports 2 installed dependencies and leavespkg-bdeployed.apm deps treestill showspkg-a -> pkg-b.apm.lock.yamlkeeps thepkg-bentry withresolved_byset to the local package.- No warning is printed.
Real-world impact
A local package moved its coding-standards-python and pr-review-loop dependencies to devDependencies, and its
build output omits them. Consumers that switched to the new build kept getting both packages, and their skills, after
every apm install, attributed to the local package. That looks as though the package still requires them, which makes
the cause hard to find.
Workarounds
apm install --refresh(or--update)apm uninstall <path>followed byapm install <path>
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
adityaanikam commentedon Oct 28, 2026
I would like to work on this. Following CONTRIBUTING, I am waiting for a maintainer to confirm the scope before I start.
My reading of the issue: when the manifest of a local package no longer lists a transitive dependency,
apm installshould drop it from what is installed and fromapm.lock.yaml, instead of leaving it recorded asresolved_bythat package. Is that the scope you want, or only the lock file entry? I have not read the code path yet.