Skip to content

Deepen installer around an Install Plan as the unit of work #83

@derek-palmer

Description

@derek-palmer

This was generated by AI from an Architecture Review (arch-review).

What to build

The installer's install() interleaves the same six-step dance twice — once for the skill body, once for the marketplace manifest: resolve target → validate source exists → (skill: canonical exists) → produce a Plan → route stream out/err → print → conditional write → return an exit code. The pure Plan dataclass is a clean seam but never escapes install(). install_all_skills just loops install() and prints — it returns no structured plans, so "what would change across all skills?" can't be inspected before any write. Verifying an abort (e.g. body-parity failure) today means calling install() with a full repo and scraping stderr.

Make the Install Plan the unit of work: planning returns a list[Plan] for both single and --all installs; a thin renderer prints them and an executor writes them. install() collapses to roughly plans = plan_all(...); render(plans); if not check_only: execute(plans). Skill vs marketplace differ only in which planner feeds the list. --check becomes "render, skip execute" with no branch duplication.

Behavior (exit codes, printed actions, dry-run prefix, idempotent/overlay/abort semantics) is unchanged — only the orchestration shape moves.

Acceptance criteria

  • Planning produces an inspectable list[Plan] for both single-target and --all installs (skill and marketplace).
  • Stream routing, dry-run prefix, and conditional write live in one render/execute path, not duplicated per kind.
  • --check / check-only is "render plans, do not execute" with no separate branch.
  • Tests assert on returned Plan objects (action / reason / target) rather than captured stdout/stderr; the abort cases are covered without a full write.
  • All existing installer exit codes and printed output are unchanged; full suite green.

Blocked by

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions