Skip to content

Commit 5bd22b7

Browse files
yoelabriljaloncad
authored andcommitted
Merge branch 'main' into feature/windsurf-target
2 parents 87f6c12 + d5ef108 commit 5bd22b7

37 files changed

Lines changed: 1288 additions & 121 deletions
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
description: "Lint contract: run BEFORE pushing or producing artifacts that claim green CI. Mirrors the CI Lint job."
3+
---
4+
5+
# Linting (canonical contract)
6+
7+
The CI `Lint` job is a hard gate. Mirror it locally before `git push`
8+
and before producing any artifact (PR body, release note, audit
9+
report) that claims CI is green.
10+
11+
## CI-mirror commands
12+
13+
The `Lint` job runs:
14+
15+
- `uv run --extra dev ruff check src/ tests/`
16+
- `uv run --extra dev ruff format --check src/ tests/`
17+
18+
Both must be silent.
19+
20+
## Local workflow
21+
22+
- **Auto-fix style+imports:** `uv run --extra dev ruff check src/ tests/ --fix`
23+
- **Apply formatter:** `uv run --extra dev ruff format src/ tests/`
24+
- **Verify (must be silent):** `uv run --extra dev ruff check src/ tests/ && uv run --extra dev ruff format --check src/ tests/`
25+
26+
Always run the verify pair before `git push` -- the CI Lint job
27+
fails on any remaining diagnostic.
28+
29+
## Common surprises
30+
31+
- `RUF043` -- use `match=r"..."` for `pytest.raises` patterns with
32+
regex metacharacters (`(`, `)`, `[`, etc.).
33+
- `UP006` / `UP045` -- use `list` / `dict` / `X | None` instead of
34+
`List` / `Dict` / `Optional`.
35+
- `RUF100` -- drop stale `# noqa` directives.
36+
- `F401` / `F841` -- remove unused imports / unused locals.
37+
- `SIM103` -- inline negated returns where the body is one line.
38+
- `I001` -- import sort order (auto-fixable).
39+
40+
## Lifecycle binding
41+
42+
This is the canonical lint contract for the repo. Skills that
43+
produce artifacts asserting green CI -- notably `pr-description-skill`
44+
(whose "Validation evidence" row covers CI checks) -- inherit this
45+
gate transitively. Do NOT redefine ruff commands inside individual
46+
skills; honor this instruction before invoking them.

.apm/skills/pr-description-skill/SKILL.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,7 @@ Run these steps in order. Tick each before moving on.
216216
1. [ ] Confirm every row of the activation contract is filled in.
217217
Defense-in-depth gate: before drafting the body, confirm the
218218
repo's lint contract is green (canonical commands and lifecycle
219-
binding live in the project's `copilot-instructions.md` Linting
220-
block - do NOT inline or restate them here). If lint is red,
219+
binding live in `.apm/instructions/linting.instructions.md`). If lint is red,
221220
STOP, fix, re-run; a PR body claiming green CI while lint fails
222221
is a credibility tax we refuse to take on.
223222
2. [ ] Read the diff in full. Identify per-file change summary,

.github/copilot-instructions.md

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,52 @@
1-
- This project uses uv to manage Python environments and dependencies.
2-
- Use `uv sync` to create the virtual environment and install all dependencies automatically.
3-
- Use `uv run <command>` to run commands in the uv-managed environment.
4-
- For development dependencies, use `uv sync --extra dev`.
5-
- **Running tests**: Use pytest via `uv run`. Prefer targeted test runs during development:
6-
- **Targeted (fastest, use during iteration):** `uv run pytest tests/unit/path/to/relevant_test.py -x`
7-
- **Unit suite (default validation):** `uv run pytest tests/unit tests/test_console.py -x` (~2,400 tests, matches CI)
8-
- **Full suite (only before final commit):** `uv run pytest`
9-
- When modifying a specific module, run only its corresponding test file(s) first. Run the full unit suite once as final validation before considering your work done.
10-
- **Test coverage principle**: When modifying existing code, add tests for the code paths you touch, on top of tests for the new functionality.
11-
- **Linting (run BEFORE pushing - CI gate fails otherwise)**: The `Lint` job runs `uv run --extra dev ruff check src/ tests/` AND `uv run --extra dev ruff format --check src/ tests/`. Mirror it locally:
12-
- **Auto-fix style+imports:** `uv run --extra dev ruff check src/ tests/ --fix`
13-
- **Apply formatter:** `uv run --extra dev ruff format src/ tests/`
14-
- **Verify (must be silent):** `uv run --extra dev ruff check src/ tests/ && uv run --extra dev ruff format --check src/ tests/`
15-
- Always run the verify pair before `git push` -- the CI Lint job fails on any remaining diagnostic. Common surprises: `RUF043` (use `match=r"..."` for regex with metacharacters), `UP006/UP045` (use `list`/`dict`/`X | None` instead of `List`/`Dict`/`Optional`), `RUF100` (drop stale `# noqa`), `F401`/`F841` (unused import / unused local).
16-
- **Lifecycle binding**: this rule is the canonical lint contract for the repo. Any skill that produces an artifact claiming green CI -- notably `pr-description-skill` (whose "Validation evidence" row covers CI checks) -- inherits this gate transitively. Do NOT redefine ruff commands inside individual skills; honor this rule before invoking them.
17-
- **Development Workflow**: To run APM from source while working in other directories:
18-
- Install in development mode: `cd /path/to/awd-cli && uv run pip install -e .`
19-
- Use absolute path: `/Users/danielmeppiel/Repos/awd-cli/.venv/bin/apm compile --verbose --dry-run`
20-
- Or create alias: `alias apm-dev='/Users/danielmeppiel/Repos/awd-cli/.venv/bin/apm'`
21-
- Changes to source code are immediately reflected (no reinstall needed)
22-
- The solution must meet the functionality as explained in the [README.md](README.md) file.
23-
- The general high-level basis to the solution is depicted in [APPROACH.md](../../APPROACH.md).
24-
- When developing functionality, we need to respect our own [CONTRIBUTING.md](../../CONTRIBUTING.md) file.
25-
The architectural decisions and basis for the project in that document are only the inspiring foundation. It can and should always be challenged when needed and is not meant as the only truth, but a very useful context and grounding research.
26-
- The project is meant for the Open Source community and should be open to contributions and follow the standards of the community.
27-
- The project is meant to be used by developers and should be easy to use, with a focus on developer experience.
28-
- The philosophy when architecting and implementing the project is to prime speed and simplicity over complexity. Do NOT over-engineer, but rather build a solid foundation that can be iterated on.
29-
- APM is an active OSS project under the `microsoft` org with a growing community (250+ stars, external contributors). Breaking changes should be communicated clearly (CHANGELOG.md), but we still favor shipping fast over lengthy deprecation cycles.
30-
- The goal is to deliver a solid and scalable architecture but simple starting implementation. Not building something complex from the start and then having to simplify it later. Remember we are delivering a new tool to the developer community and we will need to rapidly adapt to what's really useful, evolving standards, etc.
31-
- **Cross-platform encoding rule**: All source code and CLI output must stay within printable ASCII (U+0020–U+007E). Do NOT use emojis, Unicode symbols, box-drawing characters, em dashes, or any character outside the ASCII range in source files or CLI output strings. Use bracket notation for status symbols: `[+]` success, `[!]` warning, `[x]` error, `[i]` info, `[*]` action, `[>]` running. This is required to prevent `charmap` codec errors on Windows cp1252 terminals.
32-
- **Path safety rule**: Any code that builds filesystem paths from user input or external data (marketplace names, plugin paths, lockfile entries, bundle contents) **must** use the centralized guards in `src/apm_cli/utils/path_security.py`. Use `validate_path_segments(value, context=)` at parse time to reject traversal sequences (`.`, `..`) with cross-platform backslash normalization, and `ensure_path_within(path, base_dir)` after resolution to assert containment (resolves symlinks). Never write ad-hoc `".." in x` checks.
33-
- **Expert review panel**: For any non-trivial change (cross-cutting refactor, new CLI surface, dependency/auth/lockfile work, release or positioning decision), invoke the [APM Review Panel skill](skills/apm-review-panel/SKILL.md). It orchestrates seven personas (Python Architect, CLI Logging Expert, DevX UX Expert, Supply Chain Security Expert, APM CEO, OSS Growth Hacker) with explicit routing: specialists raise findings, the CEO arbitrates disagreements and strategic calls, the Growth Hacker side-channels conversion / `WIP/growth-strategy.md` insights to the CEO. Individual per-persona skills (`devx-ux`, `supply-chain-security`, `apm-strategy`, `oss-growth`) auto-activate on relevant edits even outside the panel.
1+
<!-- Generated by APM CLI from .apm/ primitives -->
2+
<!-- Build ID: 3a5991d7ca52 -->
3+
<!-- APM Version: 0.11.0 -->
4+
5+
<!-- Source: .apm/instructions/linting.instructions.md -->
6+
# Linting (canonical contract)
7+
8+
The CI `Lint` job is a hard gate. Mirror it locally before `git push`
9+
and before producing any artifact (PR body, release note, audit
10+
report) that claims CI is green.
11+
12+
## CI-mirror commands
13+
14+
The `Lint` job runs:
15+
16+
- `uv run --extra dev ruff check src/ tests/`
17+
- `uv run --extra dev ruff format --check src/ tests/`
18+
19+
Both must be silent.
20+
21+
## Local workflow
22+
23+
- **Auto-fix style+imports:** `uv run --extra dev ruff check src/ tests/ --fix`
24+
- **Apply formatter:** `uv run --extra dev ruff format src/ tests/`
25+
- **Verify (must be silent):** `uv run --extra dev ruff check src/ tests/ && uv run --extra dev ruff format --check src/ tests/`
26+
27+
Always run the verify pair before `git push` -- the CI Lint job
28+
fails on any remaining diagnostic.
29+
30+
## Common surprises
31+
32+
- `RUF043` -- use `match=r"..."` for `pytest.raises` patterns with
33+
regex metacharacters (`(`, `)`, `[`, etc.).
34+
- `UP006` / `UP045` -- use `list` / `dict` / `X | None` instead of
35+
`List` / `Dict` / `Optional`.
36+
- `RUF100` -- drop stale `# noqa` directives.
37+
- `F401` / `F841` -- remove unused imports / unused locals.
38+
- `SIM103` -- inline negated returns where the body is one line.
39+
- `I001` -- import sort order (auto-fixable).
40+
41+
## Lifecycle binding
42+
43+
This is the canonical lint contract for the repo. Skills that
44+
produce artifacts asserting green CI -- notably `pr-description-skill`
45+
(whose "Validation evidence" row covers CI checks) -- inherit this
46+
gate transitively. Do NOT redefine ruff commands inside individual
47+
skills; honor this instruction before invoking them.
48+
<!-- End source: .apm/instructions/linting.instructions.md -->
49+
50+
---
51+
*This file was generated by APM CLI. Do not edit manually.*
52+
*To regenerate: `specify apm compile`*
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
description: "Lint contract: run BEFORE pushing or producing artifacts that claim green CI. Mirrors the CI Lint job."
3+
---
4+
5+
# Linting (canonical contract)
6+
7+
The CI `Lint` job is a hard gate. Mirror it locally before `git push`
8+
and before producing any artifact (PR body, release note, audit
9+
report) that claims CI is green.
10+
11+
## CI-mirror commands
12+
13+
The `Lint` job runs:
14+
15+
- `uv run --extra dev ruff check src/ tests/`
16+
- `uv run --extra dev ruff format --check src/ tests/`
17+
18+
Both must be silent.
19+
20+
## Local workflow
21+
22+
- **Auto-fix style+imports:** `uv run --extra dev ruff check src/ tests/ --fix`
23+
- **Apply formatter:** `uv run --extra dev ruff format src/ tests/`
24+
- **Verify (must be silent):** `uv run --extra dev ruff check src/ tests/ && uv run --extra dev ruff format --check src/ tests/`
25+
26+
Always run the verify pair before `git push` -- the CI Lint job
27+
fails on any remaining diagnostic.
28+
29+
## Common surprises
30+
31+
- `RUF043` -- use `match=r"..."` for `pytest.raises` patterns with
32+
regex metacharacters (`(`, `)`, `[`, etc.).
33+
- `UP006` / `UP045` -- use `list` / `dict` / `X | None` instead of
34+
`List` / `Dict` / `Optional`.
35+
- `RUF100` -- drop stale `# noqa` directives.
36+
- `F401` / `F841` -- remove unused imports / unused locals.
37+
- `SIM103` -- inline negated returns where the body is one line.
38+
- `I001` -- import sort order (auto-fixable).
39+
40+
## Lifecycle binding
41+
42+
This is the canonical lint contract for the repo. Skills that
43+
produce artifacts asserting green CI -- notably `pr-description-skill`
44+
(whose "Validation evidence" row covers CI checks) -- inherit this
45+
gate transitively. Do NOT redefine ruff commands inside individual
46+
skills; honor this instruction before invoking them.

.github/skills/pr-description-skill/SKILL.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,7 @@ Run these steps in order. Tick each before moving on.
216216
1. [ ] Confirm every row of the activation contract is filled in.
217217
Defense-in-depth gate: before drafting the body, confirm the
218218
repo's lint contract is green (canonical commands and lifecycle
219-
binding live in the project's `copilot-instructions.md` Linting
220-
block - do NOT inline or restate them here). If lint is red,
219+
binding live in `.apm/instructions/linting.instructions.md`). If lint is red,
221220
STOP, fix, re-run; a PR body claiming green CI while lint fails
222221
is a credibility tax we refuse to take on.
223222
2. [ ] Read the diff in full. Identify per-file change summary,

.github/workflows/notice-drift.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# NOTICE Drift Check -- guards the third-party attribution file (NOTICE.md)
1+
# NOTICE Drift Check -- guards the third-party attribution file (NOTICE)
22
# against silent drift on every PR and every merge-queue entry. Also runs
33
# a license-policy gate (dependency-review-action) on PR-time only.
44
#
55
# Why this gate exists
66
# --------------------
7-
# `NOTICE.md` is a legally significant artifact: it lists every third-party
7+
# `NOTICE` is a legally significant artifact: it lists every third-party
88
# OSS component shipped inside the apm-cli wheel, with verbatim license
99
# texts. Microsoft CELA's "Manual NOTICE Generation" process makes this
1010
# file *normative* -- if it drifts from the actual install graph (someone
@@ -81,7 +81,7 @@ jobs:
8181
steps:
8282
- uses: actions/checkout@v4
8383

84-
# Pinned to the same Python version as ci.yml. NOTICE.md content
84+
# Pinned to the same Python version as ci.yml. NOTICE content
8585
# depends on which dist-info layout the installed wheels use, and
8686
# different interpreters can resolve different conditional deps
8787
# (e.g. tomli is only installed under python_version<'3.11').
@@ -101,14 +101,14 @@ jobs:
101101
# --extra dev brings in ruamel.yaml that the generator imports.
102102
# --frozen guarantees we resolve to the exact versions that the
103103
# maintainer locked, so the LICENSE text read from dist-info
104-
# matches what NOTICE.md was generated against locally.
104+
# matches what NOTICE was generated against locally.
105105
run: uv sync --frozen --extra dev
106106

107-
# Drift check: regenerate NOTICE.md to memory and diff against the
107+
# Drift check: regenerate NOTICE to memory and diff against the
108108
# committed copy. Exit 1 with a unified diff to stderr if they
109109
# differ -- the diff lands in the GitHub Actions log so the PR
110110
# author can see exactly what to regenerate.
111-
- name: Verify NOTICE.md is up to date
111+
- name: Verify NOTICE is up to date
112112
run: uv run python scripts/generate-notice.py --check
113113

114114
# Supply-chain hygiene: surface any newly-introduced dep whose

CHANGELOG.md

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010

1111
### Changed
1212

13+
- **Renamed `NOTICE.md` -> `NOTICE`** to follow the Apache / CNCF convention used by upstream third-party-attribution files (e.g. `kubernetes-sigs/kro`, `kubernetes-sigs/headlamp`). The generator (`scripts/generate-notice.py`), `make notice` target, and `NOTICE Drift Check` workflow now operate on the extension-less path. (#1073)
14+
- **NOTICE: added "Submitted on behalf of a third-party" section** crediting five contributors whose pull requests landed before the `microsoft-github-policy-service` CLA bot recorded a signature on file -- in keeping with the section-7 wording adopted by CNCF NOTICE files. Driven by a new `_third_party_submissions` block in `scripts/notice-metadata.yaml`. (#1073)
1315
- **BREAKING: `apm pack` now produces a Claude Code plugin directory by default — zero extra flags, schema-validated `plugin.json`, convention dirs auto-discovered.** The legacy APM bundle layout is preserved under `--format apm`. Migration: CI workflows and scripts that consume the legacy bundle must add `--format apm` (the [`microsoft/apm-action`](https://github.com/microsoft/apm-action) wrapper has been updated accordingly). (#1061)
1416
- **Plugin manifest schema conformance.** The synthesized/written `plugin.json` no longer emits `agents`/`skills`/`commands`/`instructions` keys pointing at the convention directories — these are auto-discovered by Claude Code, and per the [official schema](https://json.schemastore.org/claude-code-plugin.json) those array entries must be `./*.md` paths to *additional* files. The convention dirs themselves are still copied to disk. When stripping such keys from an authored `plugin.json`, `apm pack` now emits a warning so authors can clean up their source. (#1061)
1517

@@ -49,29 +51,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4951
- **`shared/apm.md` single-credential-group runs no longer fail validation** with a spurious `missing APM bundles: apm-default` -- a normalisation step recreates the per-group subdir layout that `actions/download-artifact@v5+` flattens away. (#1051)
5052
- **`apm pack` works against GitHub Enterprise and other Git hosts** -- honors `GITHUB_HOST` for GHES auth and accepts GitHub / GHES / GitLab / Bitbucket / ADO / SSH URL forms. (#1008)
5153
- **ADO Entra ID auth no longer silently fails.** Bearer tokens from `az account get-access-token` are plumbed through, errors are typed + actionable (4-case diagnostic), and `apm install --update` pre-flights auth before touching files. (#1015)
54+
- `apm marketplace add` now uses the `name` field from the fetched `marketplace.json` as the default local alias, falling back to the repo name only when the manifest omits it or declares an invalid value. This restores parity with Claude Code install instructions (e.g. `addyosmani/agent-skills` registers as `addy-agent-skills` as that repo's README documents). Existing marketplace entries are unaffected; use `--name` to override explicitly. (#1032)
5255
- `GEMINI.md` is now only created when explicitly targeted. (#1019)
5356
- Windows-friendly: auto-discovery CLI output uses POSIX paths so `apm install` / `apm compile` output is readable on Windows. (#1018)
5457
- Generated-file footer no longer prints stray `specify` before `apm compile`. (#996)
5558
- CodeQL `clear-text-storage` false-positive resolved (variable rename). (#1002)
5659

57-
### Maintainer tooling
58-
59-
- **NOTICE.md** added at repo root per CELA template -- one entry per direct dependency with verbatim license text. (#1043)
60-
- **NOTICE.md is self-maintaining**: a CI drift gate fails with an exact diff + a `make notice` fix command, plus `dependency-review-action` denies GPL/AGPL/SSPL additions on PR. (#1045, closes #1044)
61-
- `shared/apm.md` ships a `repair_string_array` helper to unblock `apm-prep` on gh-aw's `[a b]` Go-default formatting (paper-cut filed upstream). (#1033)
62-
- PR-review-panel and triage-panel skip cleanly (gray ⊘) on unmatched labels instead of failing -- no failed check, no quota burn. Bumps `gh-aw` to v0.71.1. (#1030)
63-
- `shared/apm.md` recompiled against `microsoft/apm-action@v1.5.0` for the new `bundles-file:` matrix restore (used by #982). (#1026)
64-
- Review-panel: true matrix fan-out per reviewer persona, binary `approve` / `request-changes` aggregation, label-driven merge gate. (#1022)
65-
- **Dev Container Feature scaffolded** under `devcontainer/` (closes #717) -- `install.sh` + 37 bats unit tests + 6-distro integration matrix. Not yet published to `ghcr.io`; will be announced in the release that publishes the OCI artifact. (#861)
66-
67-
### Security
68-
69-
- `apm audit --ci` and `apm install` now fail-closed when `apm.yml` is malformed YAML or not a mapping -- previously, policy and baseline checks were silently skipped (severity: medium -- policy bypass). **Migration:** repos with latently malformed `apm.yml` will go from CI-pass to CI-fail on upgrade. Validate before upgrading with `python -c "import yaml; yaml.safe_load(open('apm.yml'))"` or run `apm audit --ci` locally. Fix any YAML syntax errors in `apm.yml` (stray tabs, unquoted colons, non-mapping root). (#936)
70-
71-
### Changed
72-
73-
- Replace `black` + `isort` with Ruff for linting and formatting; add deterministic CI lint gate (~3s), configure 10 rule sets with strangler-fig complexity thresholds, and fix a Python 3.10 f-string compatibility bug in `audit_report.py` -- by @sergio-sisternes-epam (#999)
74-
7560
## [0.10.0] - 2026-04-27
7661

7762
### Added

0 commit comments

Comments
 (0)