diff --git a/docs/src/content/docs/guides/dependencies.md b/docs/src/content/docs/guides/dependencies.md index 2810bb47c..461844bbe 100644 --- a/docs/src/content/docs/guides/dependencies.md +++ b/docs/src/content/docs/guides/dependencies.md @@ -269,6 +269,8 @@ devDependencies: Dev dependencies install to `apm_modules/` like production deps but are excluded from `apm pack --format plugin` output. See [Pack & Distribute](../pack-distribute/) for details. +**Important:** plain `apm install` (no flag) deploys both `dependencies` and `devDependencies` -- there is currently no `--omit=dev` flag. The dev/prod separation kicks in at `apm pack --format plugin`. Maintainer-only primitives that you author yourself MUST live outside `.apm/` to be excluded from plugin bundles, because the local-content scanner operates on `.apm/` regardless of the devDep marker. See [Dev-only Primitives](../dev-only-primitives/) for the canonical pattern. + ## Local Path Dependencies Install packages from the local filesystem for fast iteration during development. diff --git a/docs/src/content/docs/guides/dev-only-primitives.md b/docs/src/content/docs/guides/dev-only-primitives.md new file mode 100644 index 000000000..3145f7e38 --- /dev/null +++ b/docs/src/content/docs/guides/dev-only-primitives.md @@ -0,0 +1,82 @@ +--- +title: "Dev-only Primitives" +description: "Author maintainer-only skills, agents, and instructions that stay out of shipped artifacts." +sidebar: + order: 7 +--- + +Some primitives are useful while you author an APM package but should never reach consumers: a release-checklist skill for maintainers, a debugging agent that only makes sense in your repo, instructions that reference internal infrastructure. APM has one canonical pattern for this. Once you know it, three otherwise surprising behaviors stop being surprising. + +## The pattern + +``` +your-package/ ++-- apm.yml ++-- .apm/ # shipped source root +| +-- skills/ +| | +-- public-skill/SKILL.md +| +-- agents/ ++-- dev/ # maintainer-only, outside .apm/ + +-- skills/ + +-- release-checklist/SKILL.md +``` + +```yaml +# apm.yml +name: your-package +version: 1.0.0 + +dependencies: + apm: + - microsoft/apm-sample-package#v1.0.0 + +devDependencies: + apm: + - path: ./dev/skills/release-checklist +``` + +`apm install --dev` deploys the release-checklist skill to `.github/skills/release-checklist/` with `is_dev: true` in the lockfile. `apm pack --format plugin` excludes it. Consumers running `apm install your-org/your-package` never see it. + +## Why outside `.apm/`? + +APM treats `.apm/` as the publishable source root. The local-content scanner that builds plugin bundles operates on `.apm/` only, and it does NOT consult the devDependency marker when deciding what to include. If a dev-only skill sits under `.apm/skills/`, it ships -- even if the only reference to it in `apm.yml` is under `devDependencies`. + +Authoring dev-only primitives anywhere outside `.apm/` (`dev/`, `internal/`, `.maintainer/` -- your choice) keeps them invisible to the scanner. Referencing them via local-path `devDependencies` keeps them installable on `apm install --dev` and tracked in the lockfile. + +## Three behaviors this pattern works around + +1. **The scanner does not honor the devDep marker.** It scans `.apm/` wholesale at pack time. The cure is to live outside `.apm/`. + +2. **`includes:` is allow-list only.** There is no `exclude:` form. You cannot write `includes: [.apm/]` and expect a sibling `.apm/dev/` subtree to be stripped -- `includes` does not gate `.apm/` against itself, and the manifest schema has no exclude verb. See [Manifest section 3.9](../../reference/manifest-schema/#39-includes). + +3. **Plain `apm install` deploys devDeps.** `apm install` (no flag) resolves and deploys both `dependencies` and `devDependencies`. `apm install --dev ` adds a new dev dependency to the manifest -- it is not a filter that excludes prod deps. There is currently no `--omit=dev` flag; the dev/prod separation kicks in at `apm pack --format plugin` time, not at install time. + +## When to use this pattern + +- Maintainer-only release tooling (changelog drafters, version-bump helpers). +- Internal debugging agents you do not want consumers to load. +- Test-fixture skills referenced by your own CI but not by consumers. +- Anything that would embarrass you if it shipped. + +## When NOT to use this pattern + +- Shared dev tooling that another package consumes -- that is a regular remote `devDependencies` entry (`owner/test-helpers`), not a local path. +- A primitive a consumer might legitimately want -- keep it under `.apm/`. + +## Verifying + +```bash +apm install --dev # deploys with is_dev: true +grep is_dev apm.lock.yaml # confirm marker +apm pack --format plugin --dry-run # confirm absence from bundle +ls build/your-package-1.0.0/skills/ # release-checklist must NOT appear +``` + +If the dev-only skill appears in the dry-run output, it is sitting under `.apm/`. Move it to `dev/` (or any non-`.apm/` path) and re-reference it via `path:` in `devDependencies`. + +## See also + +- [Anatomy of an APM Package](../../introduction/anatomy-of-an-apm-package/) -- why `.apm/` is the publishable source root. +- [Manifest Schema 3.9 -- `includes`](../../reference/manifest-schema/#39-includes) -- allow-list semantics, no exclude form. +- [Manifest Schema 5 -- `devDependencies`](../../reference/manifest-schema/#5-devdependencies) -- the field reference. +- [Pack & Distribute -- Plugin format](./pack-distribute/#plugin-format) -- what the scanner emits. diff --git a/docs/src/content/docs/guides/pack-distribute.md b/docs/src/content/docs/guides/pack-distribute.md index 900c03bab..abea5b406 100644 --- a/docs/src/content/docs/guides/pack-distribute.md +++ b/docs/src/content/docs/guides/pack-distribute.md @@ -221,7 +221,9 @@ Dependencies listed under [`devDependencies`](../../reference/manifest-schema/#5 apm install --dev owner/test-helpers ``` -This keeps development-only packages (test helpers, lint rules) out of distributed plugins. +This keeps third-party development-only packages (test helpers, lint rules) out of distributed plugins. + +**Caveat for primitives you author yourself:** the dev/prod split is enforced via the lockfile's `is_dev` marker for resolved dependencies. The local-content scanner that ships your own `.apm/` content does NOT consult that marker -- it bundles everything under `.apm/`. To keep maintainer-only primitives (release-checklist skills, internal debugging agents) out of plugin bundles, author them OUTSIDE `.apm/` (e.g. under `dev/`) and reference them via a local-path devDependency. See [Dev-only Primitives](./dev-only-primitives/). ### Example output diff --git a/docs/src/content/docs/guides/skills.md b/docs/src/content/docs/guides/skills.md index b92b6c41c..c7d14d9bb 100644 --- a/docs/src/content/docs/guides/skills.md +++ b/docs/src/content/docs/guides/skills.md @@ -253,6 +253,25 @@ my-package/ On install, APM promotes each sub-skill to a top-level `.github/skills/` entry alongside the parent — see [Sub-skill Promotion](#sub-skill-promotion) below. +### Option 5: Maintainer-only Skill (Dev-only) + +For skills you want during authoring but not shipped to consumers (release-checklist skills, internal debugging skills), author them OUTSIDE `.apm/` and reference them via a local-path devDependency: + +``` +your-package/ ++-- apm.yml ++-- .apm/skills/... # public skills ++-- dev/skills/release-checklist/SKILL.md # maintainer-only +``` + +```yaml +devDependencies: + apm: + - path: ./dev/skills/release-checklist +``` + +`apm install --dev` deploys the skill locally; `apm pack --format plugin` excludes it. See [Dev-only Primitives](../dev-only-primitives/) for the full pattern. + ### Sub-skill Promotion When a package contains sub-skills in `.apm/skills/*/` subdirectories, APM promotes each to a top-level entry under `.github/skills/`. This ensures Copilot can discover them independently, since it only scans direct children of `.github/skills/`. diff --git a/docs/src/content/docs/introduction/anatomy-of-an-apm-package.md b/docs/src/content/docs/introduction/anatomy-of-an-apm-package.md index c25876a7e..279ef86a4 100644 --- a/docs/src/content/docs/introduction/anatomy-of-an-apm-package.md +++ b/docs/src/content/docs/introduction/anatomy-of-an-apm-package.md @@ -280,6 +280,13 @@ next `apm install`?** Your edit gets overwritten. Edit the source under **I ran `ls` and don't see `.apm/`.** It's a dotfile directory, hidden by default. Use `ls -a`. +**I have a skill I want for development but not shipped to consumers. +Where does it go?** Outside `.apm/`. The local-content scanner that builds +plugin bundles operates on `.apm/` only and does not consult the +devDependency marker. Author dev-only primitives under `dev/` (or any +non-`.apm/` path) and reference them via a local-path devDependency. See +[Dev-only Primitives](../../guides/dev-only-primitives/). + **Do I need `.apm/` to install packages?** No. `.apm/` is for authoring. If you only consume packages, `apm install` creates the runtime targets (`.github/`, `.claude/`, etc.) directly under `apm_modules/` and you never diff --git a/docs/src/content/docs/reference/manifest-schema.md b/docs/src/content/docs/reference/manifest-schema.md index 573925e9b..1c0a38ceb 100644 --- a/docs/src/content/docs/reference/manifest-schema.md +++ b/docs/src/content/docs/reference/manifest-schema.md @@ -193,6 +193,8 @@ includes: auto # - .apm/skills/my-skill/ ``` +**`includes:` is allow-list only.** There is no `exclude:` form. The field controls which `.apm/` content the project consents to publish; it cannot be used to fence off subdirectories of `.apm/` from the scanner. To keep maintainer-only primitives out of shipped artifacts, author them OUTSIDE `.apm/` and reference them via a local-path devDependency -- see [Dev-only Primitives](../../guides/dev-only-primitives/). + When `policy.manifest.require_explicit_includes` is `true` (see [Governance guide](../../enterprise/governance-guide/)), only form 3 passes the policy check; `auto` and undeclared are rejected at install/audit time by the `explicit-includes` policy check (not at YAML parse time). ### 3.10. `policy` @@ -445,6 +447,16 @@ Created automatically by `apm init --plugin`. Use [`apm install --dev`](../cli-c apm install --dev owner/test-helpers ``` +Plain `apm install` (no flag) deploys both `dependencies` and `devDependencies`. There is currently no `--omit=dev` flag -- the dev/prod separation kicks in at `apm pack --format plugin` time. The local-content scanner that builds plugin bundles also operates on `.apm/` only and does not consult the devDep marker. To keep maintainer-only primitives out of shipped artifacts, author them outside `.apm/` and reference them via a local-path devDependency. See [Dev-only Primitives](../../guides/dev-only-primitives/). + +Local-path devDependency example: + +```yaml +devDependencies: + apm: + - path: ./dev/skills/release-checklist +``` + --- ## 6. Compilation