Skip to content

feat: add user-invocable agent frontmatter field (#3132) - #3133

Open
richard-fowles-epam wants to merge 10 commits into
microsoft:mainfrom
richard-fowles-epam:richard-fowles-epam-agent-user-invocable-field
Open

richard-fowles-epam wants to merge 10 commits into
microsoft:mainfrom
richard-fowles-epam:richard-fowles-epam-agent-user-invocable-field

Conversation

@richard-fowles-epam

@richard-fowles-epam richard-fowles-epam commented Oct 1, 2026 •

Copy link
Copy Markdown

Description

Adds an optional user-invocable boolean frontmatter field to agent primitives (*.agent.md), defaulting to true. Setting user-invocable: false marks an agent as programmatic-only: still reachable via another agent's handoffs: block, but excluded from the user-facing agent picker. visibility: internal is accepted as an alias (the canonical user-invocable key wins when both are present).

The field is interpreted by a single canonical resolver, resolve_user_invocable() in primitives/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:

  • Verbatim-copy targets (Copilot, Claude, Cursor, OpenCode, Grok) preserve the field automatically via copy_agent.
  • The two frontmatter-transform targets, Codex and Kiro, emit a non-silent lossy-compilation warning when user-invocable: false is 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

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally
  • All existing tests pass
  • Added tests for new functionality (if applicable)

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 -- PASS
  • bash scripts/lint-architecture-boundaries.sh -- PASS (ARCH_EXIT=0)
  • YAML I/O guard, file-length (<2100), and raw relative_to grep guards -- PASS
  • uv 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)

  • N/A -- this PR does not change OpenAPM-observable behaviour. No req-XXX in openapm-v0.1.md covers 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)

richard-fowles-epam and others added 2 commits October 1, 2026 20:25
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>
@richard-fowles-epam

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

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.

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 Medium severity · 1 Low severity

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/visibility resolution.
  • 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.

Comment thread src/apm_cli/primitives/models.py
Comment thread src/apm_cli/integration/agent_integrator.py Outdated
@sergio-sisternes-epam

Copy link
Copy Markdown
Collaborator

Thank you for contributing this pull request. It links #3132, which has completed issue triage (status/triaged) with classification type/feature, area/package-authoring, theme/portability.

APM starts with an issue, then maintainer scope acceptance, before implementation is invited (CONTRIBUTING.md). This PR is labelled status/deferred until #3132 carries status/accepted (Scope Decision). That label is processing only — not a decline.

Proposed PR classification (mirrors the issue): type/feature, area/package-authoring, theme/portability.

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 / status/accepted on #3132, then ready-lane engagement can proceed. This comment is advisory only — not merge or scope approval.


Generated by autopilot-pr-triage-worker. This comment is AI-generated and may contain errors.

@sergio-sisternes-epam Sergio Sisternes (sergio-sisternes-epam) added triage/recommended Automated advice completed; not human scope approval. status/deferred Not invited for implementation now; no release commitment. type/feature New capability, new flag, new primitive. area/package-authoring apm pack/unpack, plugin authoring, vendoring guidance, bundle format. theme/portability One manifest, every target. Multi-target deploy, marketplace, packaging, install. status/accepted Human scope approval; verify the issue's approval record and review contact before work. panel-review Request an advisory PR review; consumed after review. Not human approval or a merge gate. and removed status/deferred Not invited for implementation now; no release commitment. triage/recommended Automated advice completed; not human scope approval. labels Oct 2, 2026
@sergio-sisternes-epam

Copy link
Copy Markdown
Collaborator

Linked issue #3132 now has Scope Decision approve and status/accepted (work invited). This PR also carries status/accepted.

Recommendation: ready-for-review. This is advisory only -- not merge or scope approval.

Classification (mirrors #3132): type/feature, area/package-authoring, theme/portability.

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.

@sergio-sisternes-epam Sergio Sisternes (sergio-sisternes-epam) added the triage/recommended Automated advice completed; not human scope approval. label Oct 2, 2026
@sergio-sisternes-epam

Copy link
Copy Markdown
Collaborator

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.

@sergio-sisternes-epam Sergio Sisternes (sergio-sisternes-epam) added panel-review Request an advisory PR review; consumed after review. Not human approval or a merge gate. and removed panel-review Request an advisory PR review; consumed after review. Not human approval or a merge gate. labels Oct 2, 2026
@github-actions github-actions Bot removed the panel-review Request an advisory PR review; consumed after review. Not human approval or a merge gate. label Oct 2, 2026
@sergio-sisternes-epam

Copy link
Copy Markdown
Collaborator

APM Review Panel: ship_with_followups

Optional user-invocable agent frontmatter with a single canonical resolver, lossy-compilation warnings for Codex/Kiro, and matching docs/tests lands the #3132 schema field without silent strip.

panel-mode=lean; personas=python-architect,test-coverage-expert,doc-writer,apm-ceo

cc richard-fowles-epam Daniel Meppiel (@danielmeppiel) -- a fresh advisory pass is ready for your review.

This tip adds resolve_user_invocable() as the sole interpretation authority for user-invocable (with visibility: internal as alias), threads that value through the agent parser into Chatmode.user_invocable, and warns on Codex/Kiro when a programmatic-only agent would be dropped rather than stripping quietly. Verbatim-copy targets keep the field. Starlight, packaged apm-usage, and CHANGELOG describe the same contract. Linked #3132 is accepted at Scope Decision; OpenAPM normative coverage is out of scope for this field (a Spec Mode B waiver is the preferred Delivery path while the observable contract stays APM-authoring only).

Panel signals converge on a clean schema-field shape and unit coverage for default/alias/coercion plus Codex/Kiro degrade warnings. Two follow-ups remain on this head: register the new durable interpretation in the architecture owner inventory with a static guard and mutation proof, and tighten the Codex/Kiro warning so it does not over-claim handoffs reachability or name user-invocable when only the visibility alias was set.

Aligned with: single_canonical_owner -- one resolver owns meaning for parser and integrator; pragmatic_as_npm -- optional authoring field with safe degrade on targets that cannot encode it; no_silent_strip -- lossy targets warn instead of dropping programmatic-only without notice.

Panel summary

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

  1. [Python Architect] Register resolve_user_invocable in 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.
  2. [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_invocable as a durable interpretation owner at src/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 in tests/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 under src/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's handoffs: and that user-invocable was dropped. Codex emits only name/description/developer_instructions; Kiro emits description/model/tools. Neither preserves handoffs, and the message names user-invocable even when the source used only visibility: 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_invocable at tests/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 duplicating resolve_user_invocable fails 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>
richard-fowles-epam and others added 5 commits October 2, 2026 10:16
…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.
@sergio-sisternes-epam

Copy link
Copy Markdown
Collaborator

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>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/package-authoring apm pack/unpack, plugin authoring, vendoring guidance, bundle format. status/accepted Human scope approval; verify the issue's approval record and review contact before work. theme/portability One manifest, every target. Multi-target deploy, marketplace, packaging, install. triage/recommended Automated advice completed; not human scope approval. type/feature New capability, new flag, new primitive.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Schema field to mark an agent as programmatic-only (non-user-invocable)

3 participants