Full Uninstall Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Make codealmanac uninstall remove every CodeAlmanac-owned machine artifact while never deleting a repo's committed almanac/ tree.
Architecture: SetupService owns the uninstall product verb. Concrete file removal and package-manager commands sit behind setup-owned ports and are wired in src/codealmanac/app.py, matching the Cosmic Python service-layer and composition-root guidance.
Tech Stack: Python, Pydantic request/result models, pytest, Rich CLI rendering, uv/pip package commands.
Source Of Truth#
notes.md: uninstall has one meaning, removes binary/instructions/automation/global state, never deletes repoalmanac/.implementation-tickets.mdTicket 11: remove global instructions, sync/Garden/update automation,~/.codealmanac/, supported installed tool, and partial uninstall flags.MANUAL.md: build the seam, keep product decisions in services, wire concrete adapters at the composition root.
Code Wireframe#
result = app.setup.uninstall(RunUninstallRequest(yes=True))
SetupService.uninstall:
instructions.uninstall(DEFAULT_SETUP_TARGETS)
automation.uninstall(UninstallAutomationRequest())
global_state.remove()
package_uninstaller.uninstall()Task 1: Lock The Request Shape#
Files:
- Modify:
src/codealmanac/services/setup/requests.py - Modify:
src/codealmanac/services/setup/service.py - Test:
tests/test_setup_service.py
Steps:
- Remove
automation_tasksfromRunUninstallRequest. - Make
SetupService.uninstallcallUninstallAutomationRequest(home=request.home)with no task list. - Update tests to assert uninstall always asks automation to remove sync, Garden, and update.
- Run
uv run pytest tests/test_setup_service.py.
Task 2: Add Full Machine-State Removal Ports#
Files:
- Modify:
src/codealmanac/services/setup/models.py - Modify:
src/codealmanac/services/setup/ports.py - Create:
src/codealmanac/integrations/setup/uninstall.py - Modify:
src/codealmanac/integrations/setup/__init__.py - Modify:
src/codealmanac/app.py - Test:
tests/test_setup_service.py
Steps:
- Add
GlobalStateRemovalResultandPackageUninstallResultmodels. - Add setup-owned
GlobalStateRemoverandPackageUninstallerprotocols. - Implement a filesystem remover for
~/.codealmanac/. - Add fake removers in service tests.
- Assert uninstall removes
~/.codealmanac/and does not remove a repoalmanac/. - Run
uv run pytest tests/test_setup_service.py.
Task 3: Add Supported Package Uninstall#
Files:
- Modify:
src/codealmanac/integrations/setup/uninstall.py - Modify:
src/codealmanac/app.py - Test:
tests/test_setup_service.py - Test:
tests/test_cli.py
Steps:
- Use install metadata to choose:
- uv tool:
uv tool uninstall codealmanac - pip:
<python> -m pip uninstall -y codealmanac - editable/source/unknown: skip with a clear unsupported message.
- uv tool:
- Run the package command only through the injected command runner.
- Report removed, skipped, or failed in the result model.
- Add tests for uv, pip, editable/source, and failed command behavior.
- Run
uv run pytest tests/test_setup_service.py tests/test_cli.py.
Task 4: Render And Confirm Safely#
Files:
- Modify:
src/codealmanac/cli/dispatch/setup.py - Modify:
src/codealmanac/cli/render/setup.py - Test:
tests/test_cli.py
Steps:
- Keep
--yesas the non-interactive path. - When a terminal is interactive and
--yesis absent, ask for confirmation before calling the service. - In non-interactive mode without
--yes, return a non-zero exit before mutating. - Render global state and package uninstall results in text and JSON output.
- Run
uv run pytest tests/test_cli.py.
Task 5: Verify And Commit#
Commands:
uv run pytest tests/test_setup_service.py tests/test_cli.py
uv run ruff check .
uv run pytest
git diff --checkCommit as:
git add docs/plans/2026-07-06-full-uninstall.md src tests
git commit -m "feat(ticket-11): fully remove machine state"