Conversation
Phase 0 / Track D of the AI-discoverability rollout
(.github/docs/phase0-plan.md). Ships the tier-1 per-repo contract for
m-cli: a hand-authored repo.meta.json plus three machine-readable
payloads it exposes, all derived from the in-process registries.
* `m capabilities --json` — argparse parser tree → dist/commands.json
* `m lint --list-rules --json` — Rule registry + Profile reverse-index
→ dist/lint-rules.json
* `m fmt --list-rules --json` — FmtRule registry + preset reverse-index
→ dist/fmt-rules.json
The argparse / Rule / FmtRule registries remain the only source of
truth; nothing in dist/ is hand-curated. `make manifest` regenerates
all three artifacts; `make check-manifest` regenerates and asserts no
drift, wired into CI as a separate step.
Other changes:
* `CLAUDE.md` → `AGENTS.md`, with `CLAUDE.md` symlinked back. AGENTS.md
gains the agent-quickstart sections required by the tier-1 contract
(Setup / Test / Build / Verify / Guardrails); the existing detailed
conventions sections are preserved as deeper reference.
* `m_cli.cli.build_parser()` extracted from `main()` so the
capabilities walker introspects the same tree the dispatcher
runs against (plugins included).
* `dist/` allowlisted in .gitignore for the four manifest files only;
everything else under `dist/` stays untracked.
Verified: 1362 tests pass, 1 skipped. dist/repo.meta.json validates
against the Phase 0 schema (track A) via validate-repo-meta.py.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `Manifest drift gate` step on PR #8 surfaced two real drift causes between local generation and CI regeneration: 1. Plugin-contributed subcommands. `corpus-stats` (from m-cli-extras, installed in the maintainer's local venv) was getting baked into dist/commands.json. CI doesn't install plugins, so its regeneration produced a different manifest. Fix: `build_capabilities(...)` now filters to built-in subcommands by default. The dispatcher stashes the built-in name set on the parser via `set_defaults(_m_cli_builtins=...)`; the walker reads it via `parser.get_default()`. New `include_plugins=True` kwarg for callers (e.g. ad-hoc inspection) that want everything. 2. Positional `required` attribute. argparse derives `required` for positionals from `nargs` in a way that varies across CPython 3.12.x patch releases — observed False locally (3.12.13) but True in CI's setup-uv-resolved Python. Including `required` in the option dict broke the drift gate on every run. Fix: drop `required` from the emitted option dicts entirely. The field was redundant (positionals are required by convention, optionals are typically not) and unreliable. Two new regression tests pin both fixes (`test_plugin_contributed_subcommands_are_excluded_by_default`, `test_options_omit_required_field`). Verified: 1364 tests pass, 1 skipped. dist/commands.json drops from 732 to 630 lines after the two filters. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The org-level schema's `exposes.*` contract resolves paths relative to the repo root (via .git ancestor walk, per .github/profile/ repo.meta.schema.json description text and the validator's fix in .github commit e8be174). m-cli's manifest shipped with bare filenames in commit 8908508, which would have left phase0-smoke's URL-mode resolver looking for /commands.json at the repo root — 404. Fix is mechanical: "commands": "commands.json" → "dist/commands.json" "lint_rules": "lint-rules.json" → "dist/lint-rules.json" "fmt_rules": "fmt-rules.json" → "dist/fmt-rules.json" Verified: - .github's validate-repo-meta.py against this manifest: OK (walks to m-cli's .git, resolves dist/commands.json correctly). - All three referenced files exist under dist/ and are current (make manifest produces zero diff against committed payloads). - make check-manifest will now pass once this commit lands and regen produces no diff. Brings m-cli in line with m-stdlib (dist/stdlib-manifest.json) and m-standard (docs/integrated/grammar-surface.json), both of which use repo-root-relative paths. Unblocks phase0-smoke's 3/3 dry-run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.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.
Summary
.github/docs/phase0-plan.md). Ships m-cli's tier-1 per-repo contract: a hand-authoreddist/repo.meta.jsonplus three machine-readable payloads it exposes.m capabilities --json→dist/commands.json(argparse parser tree)m lint --list-rules --json→dist/lint-rules.json(Rule registry + Profile reverse-index)m fmt --list-rules --json→dist/fmt-rules.json(FmtRule registry + preset reverse-index)make manifestregenerates all three artifacts;make check-manifestregenerates and asserts no drift, wired into CI as a separate step.CLAUDE.md→AGENTS.md(withCLAUDE.mdsymlinked back); AGENTS.md gains the agent-quickstart sections required by the tier-1 contract (Setup / Test / Build / Verify / Guardrails). Existing detailed conventions sections preserved.m_cli.cli.build_parser()factored out ofmain()so the capabilities walker introspects the same tree the dispatcher dispatches against (plugins included).dist/allowlisted in.gitignorefor the four manifest files only; everything else underdist/stays untracked.Per the plan:
exposespaths indist/repo.meta.jsonare sibling-relative (commands.json, notdist/commands.json) — the validator and Track E's smoke test resolve relative to the manifest's own dir; the plan's literal template would have produceddist/dist/...404s on the raw URL.Test plan
pytest tests/— 1362 passed, 1 skipped (no regressions; 44 of those tests are new for D3 / D6 / D7).dist/repo.meta.jsonvalidates against the published Track A schema (OK: dist/repo.meta.jsonviavalidate-repo-meta.py).m capabilities --json | python3 -m json.toolparses;m lint --list-rules --json | jq lengthreturns the registered rule count; same form fmt.profiles(lint) /presets(fmt) list equals the set of profiles/presets whose selector returns it (covered by unit tests).make check-manifeststep is new — first push will exercise it. Failure here would mean CI'suv syncproduced a parser tree that drifts from what was committed.https://raw.githubusercontent.com/m-dev-tools/m-cli/main/dist/repo.meta.jsonhttps://raw.githubusercontent.com/m-dev-tools/m-cli/main/dist/commands.jsonhttps://raw.githubusercontent.com/m-dev-tools/m-cli/main/dist/lint-rules.jsonhttps://raw.githubusercontent.com/m-dev-tools/m-cli/main/dist/fmt-rules.json🤖 Generated with Claude Code