Conversation
Sets up the shared CLI scaffolding that PR-D C1b will use to add ``mm wiki agent override`` and ``mm wiki command override`` alongside the existing ``mm wiki skill override``. No behavior change for users. What changes: - ``wiki/override.py``: new ``SeedResult`` dataclass. ``render_seed_bytes`` returns ``(bytes, dropped: list[str])`` and ``seed_override`` returns ``SeedResult(path, dropped)``. C1a (#628) silently discarded the ``dropped`` list from the vendor renderers; the new shape carries it through to the caller so the upcoming agent / command CLI can warn the user about fields the vendor format cannot represent. - ``cli/wiki_cmd.py``: new ``_run_seed_override`` helper centralises the seed → stdout summary → optional stderr drop-warning → optional ``$EDITOR`` flow. The five known errors (``WikiNotFoundError``, ``OverrideExistsError``, ``FileNotFoundError``, ``InvalidNameError``, ``NotImplementedError``) are siblings (verified disjoint), so they collapse into one ``except (...)`` tuple that maps to a classified ``ClickException``. The skill-only ``is_relative_to`` fallback is removed: ``seed_override`` invariant is target-under-store.root, and a violation should surface as ``ValueError``, not as a silent path mismatch. ``skill_override_cmd`` now delegates to the helper. Migration safety gate: - ``test_wiki_skill_override_no_stderr_warning`` is the collapse invariant. Skills always seed via byte-copy of the canonical ``SKILL.md``, so ``SeedResult.dropped == []`` and the new warning path must stay quiescent. The other ten skill tests assert on ``result.output`` (combined) and would not catch a silent regression if the warning fired for skills. Pattern follows ``feedback_pre_collapse_parity_grep``: surviving path's invariants pinned before / during the N→1 collapse. - ``test_wiki_override.py`` pin tests: the two that consume the ``render_seed_bytes`` return (`*_for_agents_uses_vendor_generator`, `*_for_commands_uses_vendor_generator`) now unpack the tuple and assert ``dropped == []`` for the minimal canonical fixtures (no vendor-uncovered fields → no drops). The other two are exception-only and unchanged. Out of scope (lands in C1b commit 2): - ``mm wiki agent override`` / ``mm wiki command override`` CLI commands. - The dropped-fields stderr warning is wired in the helper but only exercised once those commands and their mirror tests land — no skill fixture today produces drops. Tests: ``packages/memtomem/tests/test_wiki_override.py`` 4/4 pass, ``test_wiki_cmd_override.py`` 11/11 pass (10 existing + 1 new safety gate). Wider sweep: 776 wiki/override/context tests pass. Co-Authored-By: Claude <[email protected]>
Closes the CLI gap left by PR-D C1a (#628), which lifted the agents / commands branch in ``wiki/override.py:render_seed_bytes`` but shipped no CLI to drive it. Users now have a single, symmetric surface across all three asset types: mm wiki skill override <name> --vendor <claude|gemini|codex> mm wiki agent override <name> --vendor <claude|gemini|codex> mm wiki command override <name> --vendor <claude|gemini|codex> What changes: - ``cli/wiki_cmd.py`` adds ``agent_group`` and ``command_group`` with ``override`` subcommands. Both delegate to ``_run_seed_override`` (the shared helper landed in the previous commit), so the trust-UX is identical: classified ClickException for known errors, no Python traceback leaks, and any vendor-renderer drops surface as a yellow stderr line so the user knows what the runtime won't see in the override. - ``("commands", "codex")`` keeps its permanent placeholder behaviour — ``seed_override`` raises ``NotImplementedError`` with a diagnostic message and the helper surfaces it as a classified ClickException rather than a traceback. There is no ``codex_commands`` generator, so this row in ``OVERRIDE_FORMATS`` cannot ship until Codex grows a slash-command surface. - The dropped-fields warning is wired through the helper. For agents, ``gemini`` drops ``skills`` / ``isolation``; for commands, ``gemini`` drops ``argument-hint`` / ``allowed-tools`` / ``model``. ``claude`` agents drop nothing in the common case, ``codex`` agents drop ``tools`` / ``skills`` / ``isolation`` / ``kind`` / ``temperature``. Skills always seed via byte-copy and never warn (pinned by the commit-1 safety gate test). - ``tests/test_wiki_cmd_override.py`` adds 21 mirror tests (10 agent + 11 command, including the codex commands placeholder) plus the ``_seed_agent`` / ``_seed_command`` test helpers. Coverage parallels the existing skills surface: happy path, dropped-fields warning, refuse-vs-force, ``--force`` writes ``.bak``, unknown vendor, missing asset (with overrides-dir cleanliness assertion), missing wiki, ``--editor`` invocation, no-editor default, and stdout contract. The stdout-contract tests pin the variable extension (``codex.toml``, ``gemini.toml``) so a regression in OVERRIDE_FORMATS would surface immediately. Out of scope (subsequent PRs in the ADR-0008 sequence): - ``mm wiki <type> {edit, diff, lint}`` — defined in ADR §Subcommands but C1b is explicitly override-only. - ``mm context update`` / ``status`` / ``install --all`` / ``migrate`` — C2 / C3 / C4. Tests: ``test_wiki_cmd_override.py`` 32/32 pass (10 skill + 1 safety gate + 10 agent + 11 command). Full suite: 3475 pass, 46 deselected (ollama). ``ruff check`` + ``ruff format --check`` clean across ``packages/memtomem/src`` and ``packages/memtomem/tests``. Co-Authored-By: Claude <[email protected]>
`_seed_agent` / `_seed_command` frontmatter assembly silently breaks if `frontmatter_extra` is missing a trailing newline — the closing ``---`` merges into the previous line and YAML parse fails with a cryptic error. Current call sites all pass values that end with ``\n``, but a future fixture can forget it. Per self-review item #1: defensive 4 lines per helper, test-only impact. The failure mode would otherwise look like a "why doesn't this fixture work?" debugging session for whoever adds the next drop-set fixture. Co-Authored-By: Claude <[email protected]>
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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
Closes the CLI gap left by PR-D C1a (#628), which lifted
wiki/override.py:render_seed_bytesfor agents / commands but shipped no CLI to drive them. Users now have a symmetric surface across all three asset types:Vendor renderers report which canonical fields they cannot represent (gemini agents drop
skills/isolation; gemini commands dropargument-hint/allowed-tools/model); the new CLI surfaces those via stderrwarning:so the user editing the override knows what the runtime won't see.Series position (ADR-0008 PR-D)
mm context updatestatus,install --all,migrateWhy two commits
The plan splits the work along a refactor / new-feature axis so each commit is a working, reviewable unit:
0cc705drefactor — extract_run_seed_overridehelper for override CLI. Three call sites are about to share a body, so the YAGNI window for the helper is open now.wiki/override.pygrows aSeedResult(path, dropped)dataclass, andrender_seed_bytes/seed_overridepropagate the renderer'sdroppedlist (C1a silently discarded it).skill_override_cmdcollapses to the helper. The five known errors collapse into oneexcept (...)tuple — verified disjoint via inheritance grep (WikiNotFoundError/OverrideExistsError/NotImplementedError→RuntimeError;FileNotFoundError→OSError;InvalidNameError→ValueError).e313da5feat —mm wiki {agent,command} override+ dropped-fields warning. Two newwiki.groupblocks, each with anoverridesubcommand that delegates to the helper. The helper now exercises the dropped-fields stderr branch (skills always havedropped == []; agents / commands populate it depending on vendor).("commands", "codex")keeps its permanent placeholder behaviour —seed_overrideraisesNotImplementedErrorand the helper surfaces it as a classifiedClickExceptionrather than a Python traceback.Collapse safety gate
feedback_pre_collapse_parity_greppattern: surviving path's invariants are pinned before / during the N→1 collapse. Skills had ten existing CLI tests (all assert onresult.output, the combined stream), so a silent regression where the new dropped-fields warning fired for skills would not surface. Commit 1 addstest_wiki_skill_override_no_stderr_warning, which usesresult.stderr == ""(Click 8.3 keepsresult.stderrseparate by default — earliermix_stderr=Falseconstructor arg was removed) to pin the four-axis invariant for skills:test_wiki_skill_override_stdout_contracttest_wiki_skill_override_happy_pathtest_wiki_skill_override_happy_path(byte-equality)test_wiki_skill_override_no_stderr_warningThe first three were already pinned before this PR; the fourth is the new collapse-specific gate.
Test surface
test_wiki_override.py4 / 4 pass. Two pin tests (*_for_agents_uses_vendor_generator,*_for_commands_uses_vendor_generator) unpack the new tuple shape and assertdropped == []for the minimal canonical fixtures (no vendor-uncovered fields → no drops). The other two are exception-only and unchanged.test_wiki_cmd_override.py32 / 32 pass:test_wiki_skill_override_no_stderr_warning(commit 1 safety gate).test_wiki_command_override_codex_classified_error(the permanent placeholder pin).uv run pytest packages/memtomem/tests/ -m "not ollama" -q→ 3475 pass, 46 deselected (ollama), +22 over C1a's 3453 (1 safety gate + 21 mirror).ruff check+ruff format --checkclean acrosspackages/memtomem/src+packages/memtomem/tests.Manual smoke (mode 2 isolation,
MEMTOMEM_WIKI_PATHoverride)Out of scope (subsequent PRs)
mm wiki <type> {edit, diff, lint}— defined in ADR-0008 §Subcommands but C1b is explicitly override-only.mm context update/status/install --all/migrate— C2 / C3 / C4.Test coverage gap (follow-up)
tools/skills/isolation/kind/temperature) is exercised only through the shared helper path, not via a vendor-specific fixture. Gemini agents (skills/isolation) and gemini commands (argument-hint/allowed-tools/model) cover the warning code path; codex agents share that same path so the marginal regression-detection value is low. Add a codex-specific fixture when generator drop sets change or as part of a vendor-coverage cleanup PR — not C2 scope, since C2's dirty detection deals with file mtime, not vendor renderer drops.Post-review fixup
0a114df fixup(c1b): newline guard in test fixture helpers—_seed_agent/_seed_commandnow normalisefrontmatter_extrato end with a trailing\n. Current call sites already do this; the guard prevents a future fixture from silently producing a malformed YAML frontmatter (closing---merging into the previous line). Test-only impact, +12 / -2 lines.Test plan
uv run pytest packages/memtomem/tests/test_wiki_cmd_override.py packages/memtomem/tests/test_wiki_override.py -v— 36 pass.uv run pytest packages/memtomem/tests/ -m "not ollama" -q— 3475 pass.uv run ruff check packages/memtomem/src packages/memtomem/tests— clean.uv run ruff format --check packages/memtomem/src packages/memtomem/tests— clean.🤖 Generated with Claude Code