You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
In a package's authoring repository — i.e., the repo whose .apm/ tree IS the package source — apm install always deploys that local content into the same project's runtime target directories (.agents/skills/, .claude/skills/, etc.). There is no way to keep the publish-side behavior (apm pack bundles .apm/ content for external consumers) while suppressing the install-side self-deployment.
For an authoring repo this produces three concrete pain points:
Working-tree noise. Every apm install writes N copies of each local primitive into .agents/<type>/<name>/ and per-client mirrors (.claude/skills/<name>/, etc.). Authors of a 20+ skill package see 40+ deployed paths show up next to the source they just edited. The lockfile's local_deployed_files: block grows proportionally.
Source vs. deployed-copy drift during iteration. While editing .apm/skills/foo/SKILL.md, the file Claude Code (or Cursor, Copilot, etc.) actually loads from .claude/skills/foo/SKILL.md is a snapshot from the last apm install. The author either has to re-run apm install after every edit, or symlink manually, or accept that their own client is running stale skills. None of these are good answers for a tight authoring loop.
No clean way to say "ship this, don't run it here." Sometimes the author specifically does not want their in-progress skills loaded into their own client — early prototypes, breaking changes mid-refactor, skills with side effects (network calls, file writes) that shouldn't fire in the authoring session. Today the only escape hatch is includes: [], which also prevents apm pack from including the content, defeating the purpose.
Per the docs (https://microsoft.github.io/apm/reference/cli/install/): "After dependencies are integrated, primitives in the project's own .apm/ directory are deployed to the same targets." This behavior is documented as unconditional.
Describe the solution you'd like
Add a knob that splits "publish in apm pack" from "deploy on local apm install." Three shapes worth considering:
Manifest field (preferred for declarative repos):
# apm.ymlself_install: false # default true; when false, apm install skips local .apm/ deploymentincludes: auto # publish path unaffected — apm pack still bundles .apm/
The field is checked only by apm install (and apm compile) when walking root .apm/. apm pack ignores it. External consumers installing this package as a dependency are unaffected because their copy lives under apm_modules/<this-package>/.apm/, not at their project root.
CLI flag for ad-hoc use:
apm install --no-self-install
Useful in CI (apm install --no-self-install to validate external deps resolve without polluting the workspace) and as an opt-out when the manifest field defaults to true.
Per-includes-entry granularity if the team wants finer control:
includes:
- path: skills/deploy_local: false # ship in apm pack; do not deploy on install
- templates/ # publish + deploy as today
For audit honesty, when self-install is skipped, apm.lock.yaml's local_deployed_files: should be empty (not stale entries from a prior install) and apm audit --ci should still hash-verify the source.apm/ paths the way it would the deployed ones — closing the same gap that #887 closed for the deploy-on path.
Describe alternatives you've considered
includes: [] — kills publishing too, so apm pack produces an empty bundle. Not viable.
Move skills outside .apm/ (e.g., src/skills/) — apm pack's file scanner walks .apm/, so out-of-tree content isn't picked up. Could declare each as a path: devDep, but that flips the problem: dev-installed but not shipped.
Post-install cleanup script — works (Remove-Item .agents/skills/foo-*, .claude/skills/foo-* after apm install) but every consumer of the authoring repo has to remember it, and apm audit --ci will then complain about missing deployed files relative to local_deployed_files: in the lockfile.
Narrow targets: in apm.yml — also affects what external consumers receive; the targets list is part of the package contract, not a local-only switch.
Symlinks from .claude/skills/foo → .apm/skills/foo — would solve the drift problem (pain point 2), but APM owns those paths and overwrites symlinks on next install; also not portable to Windows authors without dev-mode.
Additional context
Concrete repro of pain point (1), redacted:
# apm.yml in an authoring repo with 21 local skillsname: example-skills-packversion: 1.0.0targets: [agent-skills, claude]dependencies:
apm: []includes: autodevDependencies:
apm:
- some-external/skill-bundle#main
[FEATURE] add --deploy-only one-shot artifact deployment #1347 (declined) added --deploy-only for the opposite direction (deploy without project state). The decline rationale doesn't apply here because this proposal preserves all APM project state; it only suppresses the redundant copy of content the project already authors.
Naming bikeshed welcome — self_install, self_deploy, local_deploy, author_mode are all in the ballpark.
Is your feature request related to a problem? Please describe.
In a package's authoring repository — i.e., the repo whose
.apm/tree IS the package source —apm installalways deploys that local content into the same project's runtime target directories (.agents/skills/,.claude/skills/, etc.). There is no way to keep the publish-side behavior (apm packbundles.apm/content for external consumers) while suppressing the install-side self-deployment.For an authoring repo this produces three concrete pain points:
Working-tree noise. Every
apm installwrites N copies of each local primitive into.agents/<type>/<name>/and per-client mirrors (.claude/skills/<name>/, etc.). Authors of a 20+ skill package see 40+ deployed paths show up next to the source they just edited. The lockfile'slocal_deployed_files:block grows proportionally.Source vs. deployed-copy drift during iteration. While editing
.apm/skills/foo/SKILL.md, the file Claude Code (or Cursor, Copilot, etc.) actually loads from.claude/skills/foo/SKILL.mdis a snapshot from the lastapm install. The author either has to re-runapm installafter every edit, or symlink manually, or accept that their own client is running stale skills. None of these are good answers for a tight authoring loop.No clean way to say "ship this, don't run it here." Sometimes the author specifically does not want their in-progress skills loaded into their own client — early prototypes, breaking changes mid-refactor, skills with side effects (network calls, file writes) that shouldn't fire in the authoring session. Today the only escape hatch is
includes: [], which also preventsapm packfrom including the content, defeating the purpose.Per the docs (https://microsoft.github.io/apm/reference/cli/install/): "After dependencies are integrated, primitives in the project's own
.apm/directory are deployed to the same targets." This behavior is documented as unconditional.Describe the solution you'd like
Add a knob that splits "publish in
apm pack" from "deploy on localapm install." Three shapes worth considering:Manifest field (preferred for declarative repos):
The field is checked only by
apm install(andapm compile) when walking root.apm/.apm packignores it. External consumers installing this package as a dependency are unaffected because their copy lives underapm_modules/<this-package>/.apm/, not at their project root.CLI flag for ad-hoc use:
Useful in CI (
apm install --no-self-installto validate external deps resolve without polluting the workspace) and as an opt-out when the manifest field defaults totrue.Per-includes-entry granularity if the team wants finer control:
For audit honesty, when self-install is skipped,
apm.lock.yaml'slocal_deployed_files:should be empty (not stale entries from a prior install) andapm audit --cishould still hash-verify the source.apm/paths the way it would the deployed ones — closing the same gap that #887 closed for the deploy-on path.Describe alternatives you've considered
includes: []— kills publishing too, soapm packproduces an empty bundle. Not viable..apm/(e.g.,src/skills/) —apm pack's file scanner walks.apm/, so out-of-tree content isn't picked up. Could declare each as apath:devDep, but that flips the problem: dev-installed but not shipped.Remove-Item .agents/skills/foo-*, .claude/skills/foo-*afterapm install) but every consumer of the authoring repo has to remember it, andapm audit --ciwill then complain about missing deployed files relative tolocal_deployed_files:in the lockfile..gitignorethe deployed paths (adjacent to [FEATURE] Extend .gitignore coverage from apm_modules/ to deployed files #1342) — files still get written on every install and still get loaded by the local AI client; this only hides them from git, which addresses pain point (1) partially and doesn't help (2) or (3).targets:in apm.yml — also affects what external consumers receive; the targets list is part of the package contract, not a local-only switch..claude/skills/foo→.apm/skills/foo— would solve the drift problem (pain point 2), but APM owns those paths and overwrites symlinks on next install; also not portable to Windows authors without dev-mode.Additional context
Concrete repro of pain point (1), redacted:
Related prior art in this repo:
includes:field to give explicit consent to local-.apm/publishing; this proposal builds on it by separating consent-to-publish from consent-to-self-deploy.--deploy-onlyfor the opposite direction (deploy without project state). The decline rationale doesn't apply here because this proposal preserves all APM project state; it only suppresses the redundant copy of content the project already authors.Naming bikeshed welcome —
self_install,self_deploy,local_deploy,author_modeare all in the ballpark.