Skip to content

feat(packages): honor .apmignore on install, pack, and compile - #2677

Open
Sergio Sisternes (sergio-sisternes-epam) wants to merge 11 commits into
mainfrom
sergio-sisternes-epam-apmignore-file-exclusion
Open

feat(packages): honor .apmignore on install, pack, and compile#2677
Sergio Sisternes (sergio-sisternes-epam) wants to merge 11 commits into
mainfrom
sergio-sisternes-epam-apmignore-file-exclusion

Conversation

@sergio-sisternes-epam

@sergio-sisternes-epam Sergio Sisternes (sergio-sisternes-epam) commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

apm-spec-waiver: CLI-only .apmignore membership; not an OpenAPM v0.1 normative change

TL;DR

Authors can now put a .apmignore next to a package (gitignore semantics, including nested files and !) so maintainer-only trees such as evals/ stay out of skill deploy, pack, and compile. One owner (src/apm_cli/utils/apmignore.py) answers membership; SKILL.md and apm.yml cannot be ignored. The git checkout in apm_modules/ stays a faithful clone.

No built-in evals/ default. Authors write the file. Live /tmp e2e on Copilot and Claude confirmed deploy/pack/compile omit ignored paths.

Problem (WHY)

  • A root SKILL.md package is installed by copying the whole tree into <target>/skills/<name>/, so evals/ and other maintainer files ship to consumers.
  • compilation.exclude only skips compile discovery; includes: is a pack allow-list; ignore_non_content only drops symlinks and .apm-pin. None of those is a package-local deny list.
  • Adding a third ad-hoc glob matcher in install, pack, and compile would split the membership decision.

Approach (WHAT)

  • New ApmIgnoreSpec owner on pathspec (GitIgnoreSpec): nested files, last-match-wins, directory-only /, and !.
  • Install copytree goes through build_copy_ignore(package_root=...).
  • Pack collectors and primitive discovery call the same spec.
  • Fail closed if SKILL.md or apm.yml would be ignored.
  • Do not filter the apm_modules/ checkout so the ignore file stays present.

Implementation (HOW)

  • src/apm_cli/utils/apmignore.py: sole parser/matcher. Loads root + nested .apmignore, applies git parent-dir rules, exposes is_ignored and copytree_ignore.
  • src/apm_cli/integration/skill_support.py and skill_integrator.py: deploy copytree composes ignore_non_content with the spec.
  • src/apm_cli/bundle/plugin_exporter.py: _collect_flat / _collect_recursive / bare-skill / explicit includes skip ignored files.
  • src/apm_cli/primitives/discovery.py: compile/discovery prunes ignored dirs and files.
  • Architecture table + AC35 lint: only the owner may parse ignore files or import pathspec.
  • Docs, package-authoring.md, and CHANGELOG updated in place. README unchanged.

Trade-offs

  • Full gitignore, not a glob deny-list. Chose pathspec so ! and nested files match git; rejected a second home-grown matcher next to utils/exclude.py.
  • No built-in evals/ default. Authors opt in.
  • Cache stays unfiltered. Filtering at clone time would hide .apmignore and break updates.
  • Git parent-dir rule kept: evals/ then !evals/README.md does not re-include the file (un-ignore the directory first with evals/*).
  • Bare-skill pack still only lifts top-level files. Pre-existing collector shape; expanding recursion is a separate PR.
  • OpenAPM v0.1 is unchanged. .apmignore is a working-draft CLI filter, waived from Mode B spec citation.

Validation

CI-mirror lint is green (ruff check, ruff format --check, pylint R0801, auth-signal lint). Targeted pytest: 345 passed. Live /tmp e2e on --target copilot,claude:

  • Root SKILL.md deploy to .agents and .claude kept SKILL.md + references/keep.md only.
  • Three .apm/skills/{alpha,beta,gamma} deploy omitted every evals/.
  • Pack of three-skills: 8 files, no evals/.
  • Compile with .apmignore kept KEEP-COMPILE-THREE only; removing the file compiled MUST-NOT-COMPILE-THREE.
  • Follow-up commit regenerates NOTICE for pathspec and resyncs the architecture-instruction lockfile hash so apm audit --ci is clean.

How to test

  1. In a root SKILL.md package, add .apmignore with evals/ and a dummy evals/secret.md. Run apm install ./that-pkg --target copilot,claude. Expect .agents/skills/<name>/ and .claude/skills/<name>/ to lack evals/.
  2. In a package with .apm/skills/{a,b,c}/evals/, run apm pack. Expect the bundle skill dirs to contain SKILL.md and references only.
  3. Run apm compile --target copilot,claude with an ignored evals/*.instructions.md. Expect AGENTS.md / CLAUDE.md not to include that body. Remove .apmignore and recompile: the body appears.
  4. Put SKILL.md in .apmignore and run install or pack. Expect a hard error naming the required file.
  5. Confirm apm_modules/_local/<pkg>/evals/ still exists after install (cache is unfiltered).

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Add a gitignore-compatible .apmignore so authors can keep maintainer-only
files such as evals/ out of skill deploy, pack, and compile. One owner
parses the file; SKILL.md and apm.yml cannot be ignored.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add pathspec to NOTICE metadata and regenerate NOTICE. Copy the
canonical-owner row into the .apm source so apm audit --ci matches
the deployed .github copy.

apm-spec-waiver: CLI-only .apmignore membership; not an OpenAPM v0.1 normative change

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@sergio-sisternes-epam Sergio Sisternes (sergio-sisternes-epam) added the panel-review Trigger the apm-review-panel gh-aw workflow label Aug 24, 2026
_integrate_skill_bundle passed package_root=package_path without
binding the name, so SKILL_BUNDLE installs crashed. Bind
package_info.install_path and update the copytree source guard to
require build_copy_ignore.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a canonical .apmignore implementation (gitignore semantics, including nested files and !) and wires it into install deploy copy, pack collection, and compile/discovery so package authors can exclude maintainer-only content (for example evals/) without splitting membership logic across subsystems.

Changes:

  • Introduce ApmIgnoreSpec in src/apm_cli/utils/apmignore.py as the single owner for ignore parsing and membership decisions, plus an architecture boundary guard (AC35).
  • Apply .apmignore filtering consistently across skill deploy copytree, bundle packing collectors, and primitive discovery walkers.
  • Add unit and integration coverage, and update docs and changelog to document the new behavior.

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
uv.lock Adds pathspec to the locked dependency set.
pyproject.toml Adds runtime dependency on pathspec>=0.12.0.
src/apm_cli/constants.py Introduces APM_IGNORE_FILENAME constant.
src/apm_cli/utils/apmignore.py New canonical .apmignore loader/matcher and copytree ignore helper.
src/apm_cli/primitives/discovery.py Applies package ignore spec to discovery scans and cache invalidation.
src/apm_cli/integration/skill_support.py Extends build_copy_ignore() to compose .apmignore with existing ignore callbacks.
src/apm_cli/integration/skill_integrator.py Routes skill deployment copy operations through the new ignore owner.
src/apm_cli/bundle/plugin_exporter.py Filters collected pack components using ApmIgnoreSpec.
scripts/lint-architecture-boundaries.sh Adds AC35 enforcement so .apmignore parsing and pathspec imports stay single-owned.
tests/unit/utils/test_apmignore.py Adds coverage for .apmignore semantics, copytree behavior, discovery pruning, and pack collectors.
tests/integration/test_architecture_authorities.py Adds an integration assertion that the owner + guard + architecture table entry exist.
packages/apm-guide/.apm/skills/apm-usage/package-authoring.md Documents .apmignore usage and constraints for authors.
docs/src/content/docs/producer/pack-a-bundle.md Documents .apmignore effect on bundling.
docs/src/content/docs/producer/author-primitives/skills.md Documents .apmignore for root SKILL.md packages.
docs/src/content/docs/concepts/package-anatomy.md Documents .apmignore as an optional package file.
CHANGELOG.md Adds an Unreleased entry describing .apmignore support.
.github/instructions/architecture.instructions.md Adds canonical owner table row for .apmignore membership authority.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/apm_cli/utils/apmignore.py Outdated
An unreadable or non-regular .apmignore now raises ApmIgnoreError
instead of being skipped, so install/pack/compile do not ship
maintainer-only files by accident.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sergio Sisternes and others added 7 commits August 25, 2026 19:37
Keep both architecture owner rows, combine compile inventory walks
with .apmignore filtering, and refresh the architecture instruction hash.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep architecture owner rows, thread package ignore through
_build_deployable_copy_ignore, and refresh lockfile hashes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…r row

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…e bump

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
… row

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

panel-review Trigger the apm-review-panel gh-aw workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants