Skip to content

[agentry] Add reversible ownership for provider config merges and uninstall #314

Description

@azalio

Source

Local source note: /Users/azalio/Downloads/Telegram Desktop/medium-agent-rag-batch-20260629/we-built-pip-for-ai-coding-agents-meet-agentry-65dd8f30f662.md, extracted from Medium article "We Built pip for AI Coding Agents — Meet agentry" (https://medium.com/@korotkin/we-built-pip-for-ai-coding-agents-meet-agentry-65dd8f30f662).

Source-specific idea used here: agentry installs config-based components such as hooks and MCP servers through reversible config merges, owning exactly the keys it injected and stripping only those keys on uninstall/sync, while preserving user-added config.

Relevant source takeaways

  • File/directory components can be symlinked or copied, but config components need reversible merge semantics.
  • The important property is ownership granularity: the installer must know which keys it owns and must not delete user keys.
  • A safe uninstall/sync path is part of package-manager behavior, not an afterthought.

Repo evidence

  • src/mapify_cli/config/mcp.py:162-190 merges mcpServers by preserving existing entries and adding missing MAP-selected servers. This is safe for install, but it does not mark which entries MAP owns or provide a cleanup/remove operation.
  • src/mapify_cli/config/mcp.py:193-211 documents create_or_merge_project_mcp_json() as create/merge only; no uninstall/reconcile path is present in this module.
  • src/mapify_cli/delivery/file_copier.py:657-720 wires Claude statusLine into .claude/settings.local.json only if no statusline exists and preserves other keys. Docs at docs/USAGE.md:89 say disabling later means manually removing the key. That is non-destructive, but not reversible package-manager ownership.
  • README.md:236-239 and docs/USAGE.md:403-427 document --autonomy / --no-autonomy for one local settings posture. That is a narrower reversible path; it does not cover MCP/statusline/hooks/config merges generically.
  • Codex hooks.json generator writes unsupported _map_managed top-level key #270 closed a Codex hooks.json metadata/schema bug and merge preservation issue. It does not establish a general reversible ownership model for all MAP config mutations.

Existing issue search

Commands/searches used:

  • gh issue list --state all --limit 120 --search "agentry OR package manager OR lockfile OR lock file OR install manifest OR uninstall OR reversible config OR provider sync OR component registry OR catalog"
  • gh issue list --state all --limit 120 --search "managed file copier OR MAP-MANAGED OR drift detection OR fence-aware merge OR statusline OR mcp json"
  • gh issue view 270 --json number,title,state,body,comments,labels,url

Related issue checked:

Why this is not already covered

MAP has safe merge behavior in several places, but ownership is inconsistent:

  • .mcp.json can receive MAP-selected MCP servers, but there is no owner marker or uninstall path for those entries.
  • statusline can be injected into local settings, but later removal is manual.
  • autonomy has --no-autonomy, but that is a one-off path, not a reusable config-merge primitive.
  • file copier metadata does not apply cleanly to strict provider JSON schemas, as Codex hooks.json generator writes unsupported _map_managed top-level key #270 demonstrated.

Problem

Config-based provider surfaces accumulate over time. Without reversible ownership, mapify init can add entries but cannot reliably answer "remove only MAP-owned config and leave the user's config intact." That becomes more important as MAP adds providers/hooks/MCP integrations.

Proposed slice

Introduce a reusable reversible config-merge primitive for MAP-owned provider config entries.

Concrete first slice:

  • Define ownership metadata out-of-band when provider schemas cannot accept extra keys, e.g. in the install manifest from the companion install-lock issue or a gitignored/local sidecar for machine-local settings.
  • Apply it first to .mcp.json MCP server entries and Claude statusline settings, because both are current config merge surfaces.
  • Add a command/path such as mapify uninstall --provider claude --config-only or mapify sync --remove-stale that removes only MAP-owned config entries and leaves user-owned keys unchanged.
  • Preserve existing safe behavior: never overwrite existing user MCP server entries; if a user entry conflicts with a MAP desired key, report conflict rather than taking ownership.
  • Add tests for remove/reconcile behavior with mixed MAP-owned and user-owned config.

Acceptance criteria

  • MAP can record ownership of config entries it injected without violating strict provider schemas.
  • .mcp.json removal/reconcile deletes only MAP-owned MCP server entries and preserves user entries/top-level keys.
  • Claude statusline cleanup removes only a MAP-owned statusline entry and refuses to remove a user-defined statusline.
  • Existing --no-autonomy behavior either reuses the primitive or is documented as a separate legacy path.
  • Tests cover install, idempotent re-install, user-modified config, conflict detection, and uninstall/reconcile.
  • Docs replace manual-only cleanup instructions where the new command applies.

Guardrails

  • Do not put unsupported metadata into provider-owned strict schemas; Codex hooks.json generator writes unsupported _map_managed top-level key #270 is the regression to avoid.
  • Do not delete user config keys on uninstall.
  • Do not store secrets or absolute local paths in committed ownership files.
  • Do not make config cleanup destructive by default; require an explicit uninstall/reconcile command.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions