feat(pack,doctor,init): vendor-neutral producer first-run UX#1362
Merged
Conversation
Closes #1322 (jKlaus, monorepo plugins) and #1332 (R. Collet, per-package versions); addresses #1348 acceptance criteria G2, G3+B, G4, G5, and G7 (format coverage). Wave 2 of the producer-experience epic. What changes (vendor-neutral throughout): - G2 (plugin_exporter): marketplace-publishing projects no longer emit the misleading '[!] No plugin.json found' warning when there is no bundle to author. When apm.yml ships a 'marketplace:' block, plugin.json synthesis is transparent (demoted to a single _rich_info pointer at most). A genuine parse-error path keeps the warning. - G3+B (pack): after a successful build, append a vendor-neutral artifact catalog ('Marketplace artifacts ready:' + per-output ljust-aligned '[profile] path' rows + one docs pointer to producer/publish-to-a-marketplace/#consume-from-any-assistant). Suppressed in dry-run. Never names a vendor CLI surface inline (no 'copilot plugin install', 'claude plugin install', etc.) -- APM is vendor-agnostic; per-assistant install paths live in docs. - G4 (init_template): 'apm marketplace init' / 'apm init --marketplace' scaffold now uses a single-line '# codex: {}' toggle instead of a multi-line block. Producers flip it on by removing the '# '. - G5 (init_template): per-package examples include a commented 'tag_pattern: "{name}-v{version}"' (snake_case, matching the schema) on both the remote example and the local-path example, so monorepo authors find the right knob immediately. - G7 partial (marketplace doctor): a new informational 'format coverage' row lists configured vs. supported outputs and nudges producers toward formats they don't yet publish (e.g. 'Configured: claude. Also supported: codex. Add e.g. codex: {} ...'). Always passes; never affects exit code. Skipped when no marketplace block. Documentation: - docs/.../publish-to-a-marketplace.md gains a 'Consume from any assistant' section with anchor #consume-from-any-assistant -- the single source of truth for per-assistant install paths, including the confirmed Codex URL. - packages/apm-guide/.apm/skills/apm-usage/commands.md updated per doc-sync rule 4 (apm pack + marketplace doctor entries). - CHANGELOG.md Unreleased entries integrated into Fixed/Changed. Validation: - 1220/1220 unit+integration tests green for impacted suites (test_pack, test_marketplace_doctor, test_plugin_exporter, test_init_template, test_pack_ux_e2e, test_doctor_integration). - Lint silent: ruff check + ruff format --check both pass. - Real-fixture validation on zava-agent-config (7-package monorepo): - With outputs: {claude, codex} -> catalog shows aligned [claude] and [codex ] columns with single docs pointer. - With outputs: {claude} only -> doctor surfaces 'format coverage' row nudging codex enablement. - No spurious 'No plugin.json' warning at any time. - Real init: fresh 'apm init --marketplace my-mkt' produces the single-line codex toggle and per-package snake_case tag_pattern comment as designed. - Vendor-neutrality regression guard: test asserts the post-pack output never contains 'copilot plugin install', 'claude plugin install', 'codex plugin install', or 'cursor plugin install'. Wave 1 (microsoft/apm-action#40) is independent and does not need to merge before this PR; the action's new pass-through inputs only become consumer-visible when v1 is re-cut. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves producer first-run UX around marketplace packing, initialization scaffolds, and doctor diagnostics, with matching docs and regression coverage.
Changes:
- Demotes/suppresses plugin.json synthesis chatter for marketplace authoring flows.
- Adds a vendor-neutral post-pack marketplace artifact catalog and doctor
format coveragerow. - Updates marketplace init scaffolding, docs, guide skill content, changelog, and tests.
Show a summary per file
| File | Description |
|---|---|
src/apm_cli/bundle/plugin_exporter.py |
Adjusts plugin.json synthesis messaging and marketplace-block suppression. |
src/apm_cli/commands/pack.py |
Adds marketplace artifact catalog and docs pointer after successful pack. |
src/apm_cli/commands/marketplace/doctor.py |
Adds informational format coverage diagnostics. |
src/apm_cli/marketplace/init_template.py |
Updates marketplace block scaffold for outputs and per-package tag_pattern. |
tests/unit/test_plugin_exporter.py |
Covers new synthesis info/suppression behavior. |
tests/unit/marketplace/test_init_template.py |
Covers updated marketplace block scaffold. |
tests/unit/commands/test_pack.py |
Covers post-pack catalog rendering behavior. |
tests/unit/commands/test_marketplace_doctor.py |
Covers doctor format coverage row. |
tests/integration/marketplace/test_pack_ux_e2e.py |
Adds CLI-level marketplace catalog/no-warning coverage. |
tests/integration/marketplace/test_doctor_integration.py |
Adds integration coverage for doctor format coverage. |
docs/src/content/docs/producer/publish-to-a-marketplace.md |
Documents consumer installation paths by assistant. |
packages/apm-guide/.apm/skills/apm-usage/commands.md |
Updates generated command guidance for pack and doctor UX. |
CHANGELOG.md |
Adds release notes for the marketplace UX changes. |
Copilot's findings
Comments suppressed due to low confidence (2)
tests/unit/commands/test_pack.py:192
- This test does not actually validate column alignment:
line.split("]")[0]produces different strings for different profile names whether or not the shorter label is padded, solen(label_lengths) == 2would still pass if the catalog rendered[codex]unpadded. Compare the rendered label widths or the exact row prefixes so a regression in the alignment logic is caught.
catalog_rows = [line for line in logger.infos if line.startswith(" [")]
assert len(catalog_rows) == 2
# Both rows have an aligned label width (e.g. "[claude]" and "[codex] ")
label_lengths = {line.split("]")[0] for line in catalog_rows}
assert len(label_lengths) == 2 # both profiles present
CHANGELOG.md:32
- These changelog entries also violate the project changelog format by including internal goal labels (
G3+B,G4,G7) and long explanatory prose instead of concise one-line entries ending with the PR number only.
- `apm pack` now appends a vendor-neutral catalog after per-output success lines, listing each marketplace artifact and pointing at one docs anchor (`producer/publish-to-a-marketplace/#consume-from-any-assistant`) that enumerates the per-assistant install path. The catalog deliberately never names a vendor CLI surface (Copilot, Claude, Codex, Cursor, ...) -- APM is vendor-agnostic and the install command varies by AI assistant. The block is suppressed in dry-run mode. (#1348, G3+B)
- `apm marketplace init` now scaffolds the outputs map as a single-line `# codex: {}` commented toggle, replacing the verbose multi-line `# codex:\n # path: ...` block. Authors enabling Codex output now flip one line, plus a one-line reminder that Codex requires `category:` on each package. (#1348, G4)
- `apm marketplace doctor` adds a new informational `format coverage` row when the project ships a `marketplace:` block: it lists which outputs are configured (`claude`, `codex`, ...) and which supported formats are missing, with a one-line nudge on how to enable them. Always passes (informational); never affects exit code. Skipped when there is no marketplace config. (#1348, G7)
- Files reviewed: 13/13 changed files
- Comments generated: 5
| dry_run_flags = [False] * len(profiles) | ||
| path_map = { | ||
| "claude": Path(".claude-plugin/marketplace.json"), | ||
| "codex": Path(".codex/plugins/marketplace.json"), |
Comment on lines
+130
to
+132
| assert any( | ||
| "publish-to-a-marketplace" in line and "consume-from-any-assistant" in line | ||
| for line in logger.infos |
Comment on lines
+370
to
+372
| # Single docs pointer, no per-vendor install commands. | ||
| assert "publish-to-a-marketplace" in out | ||
| for forbidden in ( |
Comment on lines
+12
to
+13
| - `apm pack` for marketplace-publishing projects (`marketplace:` block in `apm.yml`, no `dependencies:`) no longer prints a misleading yellow `No plugin.json found ... consider running apm init --plugin` warning. The synthesis path from `apm.yml` is the APM-native source of truth; it is now reported as an `[i]` info line when the user is genuinely authoring a bare plugin, and suppressed entirely when the surrounding apm.yml ships a `marketplace:` block. Resolves a consistent producer-confusion signal observed in the wild on monorepo plugin shapes. (#1348, G2) | ||
| - `apm marketplace init` and `apm init --marketplace` no longer scaffold a commented `tagPattern: "example-package-v{version}"` example under `packages:` -- the marketplace schema uses snake-case `tag_pattern` per package (the camelCase `tagPattern` is the marketplace-level `build.tagPattern` field and would fail schema validation if uncommented under `packages:`). The scaffold now writes `# tag_pattern: "{name}-v{version}"` so producers who uncomment it get a working monorepo-friendly tag template. (#1348, G5) |
| # --------------------------------------------------------------------------- | ||
|
|
||
|
|
||
| def _build_report_with_outputs(profiles_paths): |
- test_marketplace_init: assert single-line '# codex: {}' toggle per G4
design (was asserting stale verbose codex path).
- test_pack_ux_e2e: fix mocked Codex output path to .agents/plugins/
marketplace.json (production default in output_profiles.py); rewrite
URL substring assertion to use urlparse per repo test convention.
- test_pack: add type annotations to _build_report_with_outputs helper;
rewrite docs-URL assertion to use urlparse.
- CHANGELOG: condense Wave 2 entries to canonical (#1348) format;
drop internal G2/G3/G4/G5/G7 taxonomy labels.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ommended Original table presented APM and assistant-native install as parallel options. APM is the recommended path because it is the only one that gives consumers a committed apm.lock.yaml, content-hash pinning, transitive resolution, security scan, and apm audit --ci drift detection (per consumer/install-packages and reference/lockfile-spec). Native marketplace commands remain valid as a fallback for non-APM consumers (no producer-side lock-in), but trade away the governance posture. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #1336 (1e02d12) made MCPIntegrator.install gate calls to resolve_targets(cwd) and fail closed with NoHarnessError when cwd lacks harness markers. The 7 new tests added in that PR (in TestInstallMCPDependencies, TestInstallSelfDefinedSkipLogic, TestDiffAwareSelfDefinedInstall) mock _install_for_runtime and _check_self_defined_servers_needing_installation but not resolve_targets, so they rely on the worker's cwd having harness markers. Under pytest-xdist worksteal scheduling, a sibling test can leave a worker in a tmp cwd (no markers), causing these 7 tests to fail intermittently with '[x] No harness detected' instead of reaching the install path. Add a shared _isolated_targets fixture that patches apm_cli.core.target_detection.resolve_targets to return targets=['copilot'], decoupling the install-gate tests from cwd. Verified by running the file from /tmp (empty cwd): 64/64 pass. Drive-by fix for #1336; unblocks PR #1362 CI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced May 18, 2026
Producer experience: close the gap from "I built a plugin" to "every assistant can install it"
#1348
Closed
sergio-sisternes-epam
pushed a commit
that referenced
this pull request
May 19, 2026
* feat(pack,doctor,init): vendor-neutral producer first-run UX Closes #1322 (jKlaus, monorepo plugins) and #1332 (R. Collet, per-package versions); addresses #1348 acceptance criteria G2, G3+B, G4, G5, and G7 (format coverage). Wave 2 of the producer-experience epic. What changes (vendor-neutral throughout): - G2 (plugin_exporter): marketplace-publishing projects no longer emit the misleading '[!] No plugin.json found' warning when there is no bundle to author. When apm.yml ships a 'marketplace:' block, plugin.json synthesis is transparent (demoted to a single _rich_info pointer at most). A genuine parse-error path keeps the warning. - G3+B (pack): after a successful build, append a vendor-neutral artifact catalog ('Marketplace artifacts ready:' + per-output ljust-aligned '[profile] path' rows + one docs pointer to producer/publish-to-a-marketplace/#consume-from-any-assistant). Suppressed in dry-run. Never names a vendor CLI surface inline (no 'copilot plugin install', 'claude plugin install', etc.) -- APM is vendor-agnostic; per-assistant install paths live in docs. - G4 (init_template): 'apm marketplace init' / 'apm init --marketplace' scaffold now uses a single-line '# codex: {}' toggle instead of a multi-line block. Producers flip it on by removing the '# '. - G5 (init_template): per-package examples include a commented 'tag_pattern: "{name}-v{version}"' (snake_case, matching the schema) on both the remote example and the local-path example, so monorepo authors find the right knob immediately. - G7 partial (marketplace doctor): a new informational 'format coverage' row lists configured vs. supported outputs and nudges producers toward formats they don't yet publish (e.g. 'Configured: claude. Also supported: codex. Add e.g. codex: {} ...'). Always passes; never affects exit code. Skipped when no marketplace block. Documentation: - docs/.../publish-to-a-marketplace.md gains a 'Consume from any assistant' section with anchor #consume-from-any-assistant -- the single source of truth for per-assistant install paths, including the confirmed Codex URL. - packages/apm-guide/.apm/skills/apm-usage/commands.md updated per doc-sync rule 4 (apm pack + marketplace doctor entries). - CHANGELOG.md Unreleased entries integrated into Fixed/Changed. Validation: - 1220/1220 unit+integration tests green for impacted suites (test_pack, test_marketplace_doctor, test_plugin_exporter, test_init_template, test_pack_ux_e2e, test_doctor_integration). - Lint silent: ruff check + ruff format --check both pass. - Real-fixture validation on zava-agent-config (7-package monorepo): - With outputs: {claude, codex} -> catalog shows aligned [claude] and [codex ] columns with single docs pointer. - With outputs: {claude} only -> doctor surfaces 'format coverage' row nudging codex enablement. - No spurious 'No plugin.json' warning at any time. - Real init: fresh 'apm init --marketplace my-mkt' produces the single-line codex toggle and per-package snake_case tag_pattern comment as designed. - Vendor-neutrality regression guard: test asserts the post-pack output never contains 'copilot plugin install', 'claude plugin install', 'codex plugin install', or 'cursor plugin install'. Wave 1 (microsoft/apm-action#40) is independent and does not need to merge before this PR; the action's new pass-through inputs only become consumer-visible when v1 is re-cut. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(pack,tests): address PR #1362 review comments and CI failure - test_marketplace_init: assert single-line '# codex: {}' toggle per G4 design (was asserting stale verbose codex path). - test_pack_ux_e2e: fix mocked Codex output path to .agents/plugins/ marketplace.json (production default in output_profiles.py); rewrite URL substring assertion to use urlparse per repo test convention. - test_pack: add type annotations to _build_report_with_outputs helper; rewrite docs-URL assertion to use urlparse. - CHANGELOG: condense Wave 2 entries to canonical (#1348) format; drop internal G2/G3/G4/G5/G7 taxonomy labels. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs(publish): reframe consume section to position apm install as recommended Original table presented APM and assistant-native install as parallel options. APM is the recommended path because it is the only one that gives consumers a committed apm.lock.yaml, content-hash pinning, transitive resolution, security scan, and apm audit --ci drift detection (per consumer/install-packages and reference/lockfile-spec). Native marketplace commands remain valid as a fallback for non-APM consumers (no producer-side lock-in), but trade away the governance posture. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(tests): stub resolve_targets in MCP install tests PR #1336 (fc48f83) made MCPIntegrator.install gate calls to resolve_targets(cwd) and fail closed with NoHarnessError when cwd lacks harness markers. The 7 new tests added in that PR (in TestInstallMCPDependencies, TestInstallSelfDefinedSkipLogic, TestDiffAwareSelfDefinedInstall) mock _install_for_runtime and _check_self_defined_servers_needing_installation but not resolve_targets, so they rely on the worker's cwd having harness markers. Under pytest-xdist worksteal scheduling, a sibling test can leave a worker in a tmp cwd (no markers), causing these 7 tests to fail intermittently with '[x] No harness detected' instead of reaching the install path. Add a shared _isolated_targets fixture that patches apm_cli.core.target_detection.resolve_targets to return targets=['copilot'], decoupling the install-gate tests from cwd. Verified by running the file from /tmp (empty cwd): 64/64 pass. Drive-by fix for #1336; unblocks PR #1362 CI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Daniel Meppiel <copilot-rework@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
This PR closes the two most-cited gaps in the producer first-run experience (#1322 monorepo plugins; #1332 per-package versions) by making
apm pack,apm marketplace doctor, andapm marketplace inithonest, vendor-neutral, and quietly opinionated. The post-pack output now lists the artifacts you actually shipped (and one docs URL for every consumer recipe), the scaffold stops scaring producers with a spurious[!] No plugin.jsonwarning, the codex toggle becomes a one-line edit, and a newformat coveragedoctor row nudges single-format producers toward two-format reach. This is Wave 2 of the producer-experience epic (#1348); Wave 1 lives in microsoft/apm-action#40 and is independent.Problem (WHY)
apm packactually built. The previous output ended atBuilt marketplace.json [claude] -> ...with no list of all written files and no pointer to how a consumer would install them. The CLI is vendor-agnostic but the consumer-side install command is not, so silence here punts the question onto the producer with no link to chase.[!] No plugin.json foundwarning fires on marketplace-only projects. A marketplace publishes references to plugins, not a plugin bundle of its own. Surfacing a bundle warning on a producer that has not asked to author a bundle is anti-Progressive-Disclosure: "Context arrives just-in-time, not just-in-case.".# codex:block in the init template was multi-line and indented, which made the on-ramp feel like opting into a feature, not flipping a switch. Codex is in the sameknown_output_names()list as Claude; the scaffold should treat it like one edit, not a paragraph.tag_patternwas undocumented at the per-package level. Monorepo producers (Understanding Expectations #1322) had to read the schema or hunt examples to learn that each package can ship its own tag pattern.apm marketplace doctordid not surface format coverage. Producers had no quick way to see "you publish for Claude; you could also publish for Codex by addingcodex: {}."Anchor: "Add what the agent lacks, omit what it knows" — APM ships the producer enough context to make a vendor-neutral choice, then gets out of the way.
Approach (WHAT)
apm packno longer emits the misleading[!] No plugin.json foundwarning whenapm.ymlships amarketplace:block; demoted to an_rich_infopointer at most.[profile] pathrows + one docs pointer. Never names a vendor CLI surface inline. Suppressed in dry-run.apm init --marketplace/apm marketplace initscaffold uses a single-line# codex: {}toggle plus a note that enabling codex requirescategory:per package.tag_pattern: "{name}-v{version}"(snake_case, matching schema) on the remote and local-path entries.apm marketplace doctoradds an informationalformat coveragerow listing configured vs. supported outputs. Always passes; skipped when nomarketplace:block.Decisions deliberately rejected (see Trade-offs): per-vendor install commands inline in the post-pack output; auto-enabling codex; failing doctor when only one format is configured.
Implementation (HOW)
src/apm_cli/bundle/plugin_exporter.py_has_marketplace_block()helper; gated the legacy missing-plugin.jsonwarning behind it via a keyword-onlysuppress_missing_warningflag on_find_or_synthesize_plugin_json. Genuine parse errors still warn.src/apm_cli/commands/pack.pyMARKETPLACE_DOCS_URLconstant;_render_marketplace_resultnow records per-output(profile, path)tuples and calls_render_marketplace_catalogon non-dry-run runs. Catalog renders one info header, ljust-aligned[profile] pathrows, and one docs pointer.src/apm_cli/marketplace/init_template.pyoutputs:and per-package sample regions of_MARKETPLACE_BLOCK_TEMPLATE: single-line codex toggle + snake_casetag_patternexamples + CI/--jsontip.src/apm_cli/commands/marketplace/doctor.py_DoctorCheckbetween the marketplace config and duplicate-names checks; guarded byif yml_obj is not None. Informational only -- does not affect exit code.docs/src/content/docs/producer/publish-to-a-marketplace.md## Consume from any assistantsection with the four-row table covering APM-aware / Claude / Codex / Cursor consumers (and the confirmed Codex marketplace URL).packages/apm-guide/.apm/skills/apm-usage/commands.mdapm packandapm marketplace doctorrows.CHANGELOG.mdFixedandChangedsections (no new section headers).Tests added: 1220 unit + integration tests pass in the impacted suites, including four new G3+B regression tests (artifact catalog, dry-run suppression, vendor-neutrality, column alignment), four G4/G5 template tests (roundtrip, single-line toggle, snake_case, schema parse), three G7 doctor tests (partial, full, skip), and three Wave-2 e2e tests (vendor-neutral catalog real path, dry-run suppression, no-warning regression).
Diagrams
Sequence of
apm packon a marketplace-only project after this PR -- showing where the new vendor-neutral catalog renders and where the old warning used to fire:sequenceDiagram autonumber participant U as Producer participant CLI as apm pack participant E as plugin_exporter participant P as pack._render_marketplace_result participant C as _render_marketplace_catalog U->>CLI: apm pack CLI->>E: export_plugin_bundle(...) Note over E: G2 -- marketplace block detected.<br/>plugin.json synthesis suppressed.<br/>No spurious bundle warning. E-->>CLI: bundle ready (or absent) CLI->>P: render(report, dry_run=False) P->>P: per-output success lines P->>C: catalog(written=[(claude, path), (codex, path)]) C-->>U: catalog header + aligned profile rows + single docs pointerFormat-coverage decision tree inside
apm marketplace doctor-- shows why the new row never blocks exit:flowchart LR A[doctor start] --> B{marketplace:<br/>block parses?} B -- no --> Z[skip format coverage row] B -- yes --> C[compute configured = yml.outputs] C --> D[compute missing = supported - configured] D --> E{missing empty?} E -- yes --> F["[i] Publishing for all known formats"] E -- no --> G["[i] Configured ... Also supported ..."] F --> Y[informational -- does not affect exit code] G --> YTrade-offs
claude plugin install ...would be the friendliest one-line answer for that specific reader, but APM is vendor-agnostic and the install command set changes per assistant and over time. We chose one stable docs URL plus aligned artifact rows. The vendor-neutrality regression test asserts nocopilot plugin install,claude plugin install,codex plugin install, orcursor plugin installsubstring ever leaks into the catalog.codex: {}line) but never blocks.# codex: {}toggle, not on-by-default. Auto-enabling codex would break producers who have not added per-packagecategory:(codex requires it). Keep the toggle one keystroke away; document thecategory:constraint right under it.tag_patternper package is snake_case in scaffolds, buttagPatternat marketplace level is camelCase. This matches the existing schema (_BUILD_KEYSvs_PACKAGE_ENTRY_KEYS). The scaffold is faithful to the schema rather than to a stylistic preference.Benefits
[i] Marketplace artifacts ready:plus the path for each format. No more "did it write the codex file? let mels .agents/...".# codex: {}->codex: {}). Reaches more consumers without changing producer cognitive load.tag_patternknob in the scaffold immediately, in snake_case, with both an aggregator and a local-path example.apm marketplace doctorbecomes a coverage report: producers learn at audit time which formats they could publish without changing their packages.Validation
Unit + integration test runs (1220 passing for impacted suites)
Lint (canonical contract, both silent)
Real-fixture run on zava-agent-config (7-package monorepo) -- G2 + G3+B
No
[!] No plugin.json foundwarning surfaced (proves G2). Catalog shows aligned[claude]and[codex ]columns plus single docs pointer (proves G3+B).Real-fixture doctor on zava (G7 -- both states)
Both states render correctly; exit code stays 0 throughout (informational).
Real init fixture (G4 + G5)
Single-line codex toggle present (G4); snake_case
tag_patternon both the example package and the local-path entry (G5).Scenario Evidence
tests/integration/marketplace/test_pack_ux_e2e.py::TestVendorNeutralCatalog::test_catalog_lists_both_profiles_with_docs_pointerplugin.jsontests/integration/marketplace/test_pack_ux_e2e.py::TestNoSpuriousPluginJsonWarning::test_marketplace_only_project_no_plugin_json_warningtests/integration/marketplace/test_pack_ux_e2e.py::TestVendorNeutralCatalog::test_dry_run_suppresses_catalogtests/unit/commands/test_pack.py::test_post_pack_catalog_vendor_neutraltests/integration/marketplace/test_doctor_integration.py::TestDoctorFormatCoverage::test_partial_coverage_lists_missing_formatstests/integration/marketplace/test_doctor_integration.py::TestDoctorFormatCoverage::test_no_marketplace_block_skips_rowapm init --marketplacewrites a one-keystroke codex toggletests/unit/marketplace/test_init_template.py::TestRenderMarketplaceBlock::test_single_line_codex_toggletag_patternper-package in scaffoldtests/unit/marketplace/test_init_template.py::TestRenderMarketplaceBlock::test_snake_case_tag_pattern_per_packagetag_patternonce uncommentedtests/unit/marketplace/test_init_template.py::TestRenderMarketplaceBlock::test_uncommented_tag_pattern_parses_through_schemaHow to test
git fetch origin danielmeppiel/marketplace-monorepo-ux && git checkout danielmeppiel/marketplace-monorepo-ux.uv sync --extra dev.uv run --extra dev pytest tests/integration/marketplace/ tests/unit/commands/test_pack.py tests/unit/commands/test_marketplace_doctor.py tests/unit/marketplace/ tests/unit/test_plugin_exporter.py -q --tb=short-- expect 1220 passed.uv run --extra dev ruff check src/ tests/ && uv run --extra dev ruff format --check src/ tests/-- both must be silent.outputs: {claude: {}, codex: {}}tomarketplace:, runapm pack, and confirm the catalog block + single docs pointer + noplugin.jsonwarning. Then runapm marketplace doctorto see the newformat coveragerow.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com