Repository navigation
feat: add user-invocable agent frontmatter field (#3132) - #3133
richard-fowles-epam wants to merge 10 commits into
Conversation
Add an optional `user-invocable: false` frontmatter field to agent primitives (*.agent.md), defaulting to `true`, with `visibility: internal` accepted as an alias. The field marks an agent as programmatic-only: reachable via another agent's `handoffs:` but excluded from the user-facing agent picker. A single canonical resolver `resolve_user_invocable()` interprets the field; both the primitive parser and the agent integrator consume it so interpretation has one authority. Verbatim-copy targets preserve the field automatically. The two frontmatter-transform targets (Codex, Kiro) emit a non-silent lossy-compilation warning when the field is present and false, rather than silently dropping it -- addressing the regression class behind microsoft#3067 and microsoft#3126. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Extend the existing preserve-frontmatter tests (copy_agent, Claude, Cursor) with a user-invocable: false fixture so the field's verbatim preservation on pass-through targets is asserted rather than implied. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@microsoft-github-policy-service agree |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The canonical resolver lacks required architecture guards, and the degradation warning makes inaccurate reachability claims.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Adds programmatic-only agent metadata and warns when target formats cannot preserve it.
Changes:
- Adds canonical
user-invocable/visibilityresolution. - Preserves metadata or emits Codex/Kiro degradation warnings.
- Adds tests, documentation, and changelog coverage.
| File | Description |
|---|---|
src/apm_cli/primitives/models.py |
Defines invocability semantics. |
src/apm_cli/primitives/parser.py |
Parses invocability metadata. |
src/apm_cli/integration/agent_integrator.py |
Warns on lossy Codex/Kiro conversion. |
tests/unit/primitives/test_primitives.py |
Tests parser behavior. |
tests/unit/integration/test_agent_integrator.py |
Tests preservation and warnings. |
docs/src/content/docs/producer/author-primitives/instructions-and-agents.md |
Documents agent authoring behavior. |
packages/apm-guide/.apm/skills/apm-usage/package-authoring.md |
Updates packaged authoring guidance. |
CHANGELOG.md |
Records the feature. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Thank you for contributing this pull request. It links #3132, which has completed issue triage ( APM starts with an issue, then maintainer scope acceptance, before implementation is invited (CONTRIBUTING.md). This PR is labelled Proposed PR classification (mirrors the issue): CODEOWNERS review requests already include Daniel Meppiel (@danielmeppiel) and Sergio Sisternes (@sergio-sisternes-epam); this triage does not change review requests. Suggested next step: wait for maintainer Scope Decision / Generated by autopilot-pr-triage-worker. This comment is AI-generated and may contain errors. |
|
Linked issue #3132 now has Scope Decision approve and Recommendation: ready-for-review. This is advisory only -- not merge or scope approval. Classification (mirrors #3132): CODEOWNERS review requests already include Daniel Meppiel (@danielmeppiel) and Sergio Sisternes (@sergio-sisternes-epam); this triage does not change review requests. Ready-lane engagement for this PR is in progress separately. This comment is advisory classification only. Generated by autopilot-pr-triage-worker. This comment is AI-generated and may contain errors. |
|
Thanks for the PR, richard-fowles-epam - and for filing #3132. There are a couple of open review threads on the tip. Delivery is taking those from here on your branch, keeping your authorship, and driving the PR toward merge readiness for human approval. Generated by autopilot-pr-ready-takeover. This comment is AI-generated and may contain errors. |
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 0 | 2 | 0 | Canonical resolver is the right shape; register the owner + guard, and keep the Codex/Kiro warning accurate to what those renderers emit. |
| Test Coverage Expert | 0 | 1 | 0 | Parser and integrator warn/pass paths are covered; architecture owner mutation case for the new resolver is still missing. |
| Doc Writer | 0 | 0 | 0 | Starlight, apm-guide, and CHANGELOG agree on default, alias, verbatim preserve, and Codex/Kiro warn-not-strip. |
B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.
Top 2 follow-ups
- [Python Architect] Register
resolve_user_invocablein the architecture owner inventory with a linter guard and mutation proof -- Matches the single-canonical-owner rule already cited in the PR; keeps future parser/integrator paths from bypassing the resolver. - [Python Architect] Tighten the Codex/Kiro lossy warning copy -- Those renderers do not preserve handoffs or the field itself; say programmatic-only cannot be guaranteed in-target and name a concrete mitigation (APM source remains authority / picker filtering is harness-side).
Recommendation
Ship this tip through normal human review once the owner-inventory registration and warning-accuracy follow-ups are either landed on the branch or tracked as short follow-ups. Schema field, docs, and unit coverage for the accepted #3132 bar look sound on the current head. This is advisory prose for the reviewer, not approval or permission to merge.
Full per-persona findings
Python Architect
-
[recommended] Register
resolve_user_invocableas a durable interpretation owner atsrc/apm_cli/primitives/models.py
The new helper is correctly centralized and shared by parser and integrator, but it is not yet listed in the architecture owner inventory or covered by an architecture-linter guard plus a matching mutation case intests/integration/test_architecture_owner_rule_mutations.py. Without that triad, future call sites can re-interpret the field locally.
Suggested: Add the owner record, a static uniqueness/import guard, and one mutation proof that fails if a second interpretation appears undersrc/apm_cli. -
[recommended] Codex/Kiro lossy warning over-claims handoffs reachability at
src/apm_cli/integration/agent_integrator.py
The warning says the agent stays reachable via another agent'shandoffs:and thatuser-invocablewas dropped. Codex emits only name/description/developer_instructions; Kiro emits description/model/tools. Neither preserves handoffs, and the message namesuser-invocableeven when the source used onlyvisibility: internal.
Suggested: Report that programmatic-only semantics cannot be guaranteed in the target format, and point authors at APM source authority plus harness-side picker filtering as the mitigation.
Test Coverage Expert
- [recommended] Architecture owner mutation case missing for
resolve_user_invocableattests/integration/test_architecture_owner_rule_mutations.py
Unit tests cover default/true/false, visibility alias, canonical-wins, string coercion, verbatim preserve, and Codex/Kiro warn/silent paths (parser + integrator). Grep found no mutation/owner-guard case for the new resolver.
Proof (missing):tests/integration/test_architecture_owner_rule_mutations.py-- proves: bypassing or duplicatingresolve_user_invocablefails the architecture owner guard
Evidence tier: integration
Doc Writer
No findings.
This panel is advisory. It does not block merge. Re-apply the
panel-review label after addressing feedback to re-run.
Generated by autopilot-pr-review-worker. This comment is AI-generated and may contain errors.
Register resolve_user_invocable in the architecture owner inventory with a static guard and mutation proof. Rewrite Codex/Kiro drop warnings so they do not claim handoffs reachability or mis-attribute visibility:internal. apm-spec-waiver: optional agent frontmatter user-invocable; no OpenAPM-observable behaviour (scope excludes OpenAPM normative changes) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tory Add the newly registered architecture rule id to the frozen semantic contract inventory so the unit inventory test matches live registration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Resolve CHANGELOG.md conflict after main released v0.33.0: keep Unreleased user-invocable Added bullet (microsoft#3132) and full 0.33.0 section from main.
|
Thanks for the PR, richard-fowles-epam - and for filing #3132. This branch had fallen behind main after the v0.33.0 release, so it was not mergeable until the conflict was cleared. Checks on the prior tip looked green. Delivery took the conflict from here: merging the latest main while keeping your authorship and preferring your branch, then driving the PR toward merge readiness for human approval. Generated by autopilot-pr-ready-takeover. This comment is AI-generated and may contain errors. |
Merge main (26ec331, microsoft#3150 fix(codex): preserve native agent model settings; v0.33.0 microsoft#3152) into the PR branch. Conflicts resolved (both intents kept): - CHANGELOG.md: keep microsoft#3132 Added entry with microsoft#3150 Changed/Fixed entries under [Unreleased]. - packages/apm-guide/.apm/skills/apm-usage/package-authoring.md: keep the user-invocable agent paragraph and main's Codex native model settings subsection. - src/apm_cli/integration/agent_integrator.py (auto-merged, semantic): treat user-invocable/visibility as known Codex fields so only the dedicated user-invocable warning fires (no duplicate generic dropped-field warning). Co-authored-by: Richard Fowles <richard_fowles@epam.com>


Description
Adds an optional
user-invocableboolean frontmatter field to agent primitives (*.agent.md), defaulting totrue. Settinguser-invocable: falsemarks an agent as programmatic-only: still reachable via another agent'shandoffs:block, but excluded from the user-facing agent picker.visibility: internalis accepted as an alias (the canonicaluser-invocablekey wins when both are present).The field is interpreted by a single canonical resolver,
resolve_user_invocable()inprimitives/models.py. Both the primitive parser (_parse_chatmode) and the agent integrator consume that one resolver, so field interpretation has exactly one authority (per the single-canonical-owner architecture rule).Per-target handling honours the acceptance bar that the field must never be silently stripped:
copy_agent.user-invocable: falseis present and would be dropped. They stay silent for the default (true/absent).This closes the regression class behind the earlier frontmatter-dropping bugs #3067 and #3126, where fields vanished without warning.
Issue and approved scope
Issue: #3132 (feature request authored by the maintainer persona; the issue body is the approved scope)
Human scope-approval comment: the issue itself defines the narrow, lenient acceptance bar ("honored or safely degraded by each target renderer rather than silently stripped").
Does this PR complete the issue, or what remains? This PR completes the schema-field portion. Downstream semantic consumption (a picker actually filtering the agent out) is a separate harness concern, explicitly out of scope per the issue.
Fixes #3132
Type of change
Testing
Validation evidence (all run locally against the PR branch):
uv run --extra dev ruff check src/ tests/ scripts/lint_architecture_boundaries.py scripts/architecture_linter/-- PASS (clean)uv run --extra dev ruff format --check src/ tests/ scripts/lint_architecture_boundaries.py scripts/architecture_linter/-- PASS (clean)uv run --extra dev python -m pylint --disable=all --enable=R0801 --min-similarity-lines=10 --fail-on=R0801 src/apm_cli/ scripts/lint_architecture_boundaries.py scripts/architecture_linter/-- PASS (10.00/10)bash scripts/lint-auth-signals.sh-- PASSbash scripts/lint-architecture-boundaries.sh-- PASS (ARCH_EXIT=0)relative_togrep guards -- PASSuv run --extra dev pytest tests/unit/primitives/ tests/unit/integration/test_agent_integrator.py-- 226 passed, including 5 new parser tests and 6 new integrator degrade-warning tests (3 Codex, 3 Kiro).Spec conformance (OpenAPM v0.1)
req-XXXinopenapm-v0.1.mdcovers agent frontmatter fields or user-invocability; this adds a new optional authoring field with no normative spec surface.apm-spec-waiver: optional agent frontmatter user-invocable; no OpenAPM-observable behaviour (scope excludes OpenAPM normative changes)