diff --git a/README.md b/README.md index c5deb2f..308126d 100755 --- a/README.md +++ b/README.md @@ -196,8 +196,7 @@ setup update dotfiles # Sync dotfiles from repo The full catalog lives in [`bootstrap/manifest.toml`](bootstrap/manifest.toml). Run `setup list` to see it with your local profile and tag filters applied. -See [plans/2026-04-18-manifest-architecture-design.md](plans/2026-04-18-manifest-architecture-design.md) -for the manifest architecture. +See [docs/MANIFEST.md](docs/MANIFEST.md) for the manifest and profile architecture. ## Features diff --git a/cli/src/manifest/mod.rs b/cli/src/manifest/mod.rs index 32fc3bb..07d3687 100644 --- a/cli/src/manifest/mod.rs +++ b/cli/src/manifest/mod.rs @@ -1,6 +1,6 @@ //! Declarative manifest describing available components and profiles. //! -//! See `plans/2026-04-18-manifest-architecture-design.md` for the full design. +//! See `docs/MANIFEST.md` for the user-facing manifest and profile documentation. pub mod loader; pub mod intent; diff --git a/docs/MANIFEST.md b/docs/MANIFEST.md new file mode 100644 index 0000000..67ec391 --- /dev/null +++ b/docs/MANIFEST.md @@ -0,0 +1,125 @@ +# Manifest and Profiles + +The setup CLI uses a TOML manifest to describe what components exist, how they depend on each other, and which components belong to each machine profile. Install logic still lives in Rust; the manifest is the catalog and selection layer. + +## Manifest Location + +The repo catalog lives at `bootstrap/manifest.toml`. + +Users may optionally create `~/.config/setup/manifest.toml` to replace existing component or profile entries. This is an override layer, not a plugin mechanism: every referenced component ID must already have a Rust implementation. + +## Components + +Each `[[components]]` entry describes one installable component: + +```toml +[[components]] +id = "docker" +display_name = "Docker" +description = "Container runtime" +depends_on = ["apt"] +tags = ["container", "dev"] +requires_sudo = true +requires_systemd = true +requires_privileged = true +interactive = false +``` + +Common fields: + +| Field | Meaning | +|---|---| +| `id` | Unique kebab-case ID. Must match a Rust component in `cli/src/components/`. | +| `display_name` | Human-readable name for list and prompt output. | +| `description` | Longer description shown by `setup list`. | +| `depends_on` | Component IDs that must be installed first. | +| `tags` | Free-form labels used for filtering and grouping. | +| `requires_sudo` | Component needs root privileges. | +| `requires_systemd` | Component needs systemd and is skipped in the Docker test harness. | +| `requires_privileged` | Component needs host or privileged-container access. | +| `interactive` | Component may prompt or require auth, so it is not included in non-interactive `--all` installs. | + +Docker testability is derived from the capability flags. A component is Docker-testable when it does not require systemd, privileged access, or interactivity. + +## Profiles + +Profiles define reusable machine shapes. They can extend other profiles and compose by union when multiple `--profile` flags are passed. + +```toml +[profiles.workstation] +description = "Desktop/laptop dev box" +extends = ["base"] +components = ["ghostty", "docker", "lazygit", "tpm", "neovim", "gh", "chromium", "obsidian"] +``` + +Profile resolution: + +1. Expand every requested profile, including transitive `extends`. +2. Add explicitly named components, if any. +3. Pull in transitive component dependencies from `depends_on`. +4. Validate that every ID exists in both the manifest and Rust registry. +5. Install in deterministic topological order. + +## User Overrides + +If `~/.config/setup/manifest.toml` exists, it is loaded on top of the repo manifest. + +Components merge by `id`: redefining an existing component replaces the repo entry completely. + +Profiles merge by name: redefining a profile replaces the repo profile completely. Users may define new profiles as long as all referenced component IDs exist in the Rust registry. + +Unknown component IDs, invalid dependency references, and profile cycles fail fast during manifest loading. + +## Active Profile Intent + +Profile intent is stored separately from install state: + +```toml +# ~/.config/setup/active.toml +active_profiles = ["server", "ai-heavy"] +``` + +The system does not keep a persistent record of what is installed. Components answer that by probing the machine through `is_installed()`. The intent file only records what profiles the user says this machine should have. + +Intent is updated by profile-oriented commands: + +| Command | Effect | +|---|---| +| `setup install --profile ` | Adds the profile after a successful install. | +| `setup install --profile --keep-going` | Adds the profile even if some components failed, so `setup doctor` can report what remains missing. | +| `setup profile activate ` | Adds profile intent without installing anything. | +| `setup profile deactivate ` | Removes profile intent without uninstalling anything. | +| `setup install ` | Leaves profile intent unchanged. | +| `setup install --all` | Leaves profile intent unchanged. | + +## Doctor Behavior + +`setup doctor` runs machine-health checks every time. These include PATH sanity, dotfile drift, broken symlinks, and optional component verification. + +Profile-drift checks require an active set. The active set comes from explicit `--profile` flags first, then `~/.config/setup/active.toml`. If neither is present, doctor skips profile-drift checks and prints a note. + +Useful commands: + +```bash +setup doctor +setup doctor --profile workstation +setup doctor --verify +setup doctor --warn-only +``` + +## Component Lifecycle + +Each Rust component implements the lifecycle contract in `cli/src/components/mod.rs`: + +| Method | Purpose | +|---|---| +| `is_installed()` | Probe real machine state. | +| `install()` | Idempotently install the component. | +| `verify()` | Optional deeper post-install check. | +| `dry_run()` | Explain what install would do without side effects. | +| `uninstall()` | Remove the component when removal is supported. | +| `is_reversible()` | Declare whether automatic rollback may uninstall it safely. | + +`setup uninstall ` calls the component's uninstall implementation. Components that manage user material, such as SSH or GPG material, can be uninstallable but non-reversible; those require `--force` for manual uninstall and are skipped by automatic rollback. + +Historical design notes are kept in [`plans/manifest-architecture-spec.md`](../plans/manifest-architecture-spec.md). diff --git a/plans/README.md b/plans/README.md new file mode 100644 index 0000000..fa303eb --- /dev/null +++ b/plans/README.md @@ -0,0 +1,7 @@ +# Plans + +This directory is for temporary or historical planning material. + +Use `docs/` for durable user-facing documentation that describes shipped behavior. Use `plans/` for proposed specs, implementation checklists, and archival design notes. + +Plan filenames should be stable and descriptive, without date prefixes. Prefer names like `maintenance-spec.md` or `manifest-architecture-plan.md`. diff --git a/plans/maintenance-spec.md b/plans/maintenance-spec.md new file mode 100644 index 0000000..9a8e9c2 --- /dev/null +++ b/plans/maintenance-spec.md @@ -0,0 +1,312 @@ +# Workstation Maintenance System + +**Status:** proposed / not implemented. + +This is a planning spec, not user-facing documentation for shipped functionality. If this system is implemented, the durable user docs should live in `docs/MAINTENANCE.md` and describe the behavior that actually shipped. + +A layered, AI-provider-agnostic system that scans this workstation for cleanup opportunities, configuration drift, and emerging issues; writes its findings to a versioned journal; and surfaces them through both scheduled (systemd) and on-demand (slash command) entry points. + +## Motivation + +Computer maintenance currently happens ad hoc, when something is already noticeably wrong. The `setup` CLI already covers managed configs (`setup doctor`, `setup drift`, `setup check`, `setup update`) but does not address: disk cruft, docker/k8s leftovers, journald growth, dead branches and abandoned worktrees, stale Claude/agent artifacts, listening-port drift, or trends over time. + +The goal is a small, mostly-bash system whose load-bearing logic lives outside any single AI agent, with thin per-provider glue. Switching to or adding Codex / OpenCode should not require rewriting any of the maintenance work itself. + +## Goals + +- **Scheduled, unattended scans** that produce a digest readable by humans, AI agents, or `grep`. +- **On-demand entry points** through slash commands for focused work (full audit, disk, dev cruft). +- **Passive surfacing** of unresolved items at the start of each AI session (one line, fast). +- **Provider-agnostic substrate** — the scanners, the journal, and the timer survive any agent change. +- **Report-only by default** — never delete or modify without explicit user action in a session. +- **Leverage `setup`** — call `setup doctor` and `setup drift` rather than re-implementing them. + +## Non-goals + +- Auto-cleanup of any kind. Even "obviously safe" pruning waits for explicit user action. +- Browser cache / GUI app cruft — too varied per app, not worth the maintenance burden. +- Cross-host sync of the journal or deferred list — per-host state by design. +- A `setup` CLI Rust component for installing the timer (use a bash installer for now; promote to a Rust component if the system proves worth it). +- Trend analysis beyond simple week-over-week deltas (e.g. "Downloads grew 4 GB"). +- Per-session anomaly detection. SessionEnd logs only ` `; the weekly scan does the interpretation. + +## Architecture + +Three tiers, each with one job: + +1. **Substrate** (provider-agnostic): bash scanners, the digest format, the journal, the systemd timer. Lives in `git/setup/bootstrap/scripts/maintenance/` and `git/setup/bootstrap/systemd/`. Per-host state lives at `~/.local/state/maintenance/`. +2. **Shared agent skills** (provider-agnostic markdown): `.agents/skills/maintenance-audit/SKILL.md` and `.agents/skills/maintenance-act/SKILL.md`. These tell *any* agent how to walk a digest with the user and how to safely run a suggested action. +3. **Per-provider shims** (thin): `.claude/commands/.md` files that delegate to the skill. When Codex or OpenCode are adopted, equivalent shims get added under `.codex/` or `.opencode/` without touching the substrate or skills. + +``` +git/setup/ +├── .agents/ +│ ├── README.md ← explains the .agents convention and shim pattern +│ └── skills/ +│ ├── maintenance-audit/SKILL.md +│ └── maintenance-act/SKILL.md +├── .claude/commands/ +│ ├── maintenance.md ← /maintenance [category] +│ ├── clean-disk.md ← /clean-disk +│ └── clean-dev.md ← /clean-dev +├── bootstrap/scripts/maintenance/ +│ ├── scan.sh ← driver: invokes scanners, writes digest +│ ├── show-digest.sh ← prints top N items (called by SessionStart) +│ ├── log-session-end.sh ← appends timestamp+cwd (called by SessionEnd) +│ ├── install.sh ← installs the timer + symlinks the hooks +│ └── scanners/ +│ ├── setup-doctor.sh +│ ├── disk.sh +│ ├── docker-k8s.sh +│ ├── system-health.sh +│ ├── dev-cruft.sh +│ └── config-drift.sh +├── bootstrap/systemd/ +│ ├── maintenance-scan.service +│ └── maintenance-scan.timer +└── docs/MAINTENANCE.md ← user-facing documentation + +~/.local/state/maintenance/ +├── journal.md ← append-only, sectioned by date +├── deferred.md ← items the user chose to keep, with expiry +├── last-digest.md ← latest scan output (overwritten weekly) +└── sessions.log ← per AI session + +~/.claude/hooks/ +├── session-start-nudge.sh ← thin shim: exec setup repo's show-digest.sh +└── session-end-cwd-log.sh ← thin shim: exec setup repo's log-session-end.sh +``` + +## Components + +### scan.sh (driver) + +Single bash script that runs every scanner under `scanners/` with a 60s timeout each. Each scanner emits findings on stdout in the shared format (see Data Formats). `scan.sh` concatenates them, prepends a date heading, writes the result to `~/.local/state/maintenance/last-digest.md`, and appends the same content to `~/.local/state/maintenance/journal.md`. + +Flags: +- `--scope=` — run only the named scanners (default: all). +- `--json` — emit machine-readable JSON instead of markdown (used by the audit skill). +- `--no-write` — print to stdout only; don't update digest or journal (used for dry runs). + +Items present in `deferred.md` (and not yet expired) are filtered out before writing. + +### Scanners + +Each scanner is a self-contained bash script with the same contract: read no arguments, print findings to stdout in the shared format, exit 0 on success even if findings are present. Exit nonzero only on scanner failure (broken environment, missing binary). + +| Scanner | What it checks | +|---|---| +| `setup-doctor.sh` | Shells out to `setup doctor` and `setup drift --json`. Captures their summary lines as `info` or `warn` items. | +| `disk.sh` | `~/Downloads` size + week-over-week delta; files >100MB under `$HOME` (excluding `~/.cache`, `~/.local/share`, any `node_modules`, any `.git/objects`); `node_modules` / `target/` / `.venv` directories untouched 90+ days; `/tmp` files older than 30 days. | +| `docker-k8s.sh` | `docker images -f dangling=true`, `docker volume ls -f dangling=true`, total reclaimable space from `docker system df`. For each context in `~/.kube/config`, with `kubectl --request-timeout=5s`: evicted pods, terminating pods stuck >1h. Contexts that time out are reported as a single `info` item rather than failing the scan. | +| `system-health.sh` | `systemctl --user --failed` and `systemctl --failed`; `journalctl -p err --since "7 days ago"` count per unit; `apt list --upgradable` filtered to security updates; new listening ports vs. last week's snapshot (snapshot kept under `~/.local/state/maintenance/ports-prev.txt`). | +| `dev-cruft.sh` | `~/.claude/sessions/` JSONLs >30 days; `~/.claude/plans/` and `~/.claude/todos/` >60 days; isolation-mode worktrees untouched 30+ days that are not the cwd of any session in the last 30 days of `sessions.log`; for each tracked git repo under `~/git/`, local branches fully merged into the repo's default branch. Default branch detection should try `git symbolic-ref --short refs/remotes/origin/HEAD`, then fall back to `main`, then `master`; cwds appearing in `sessions.log` (last 30 days) with lingering untracked files per `git status --porcelain`. | +| `config-drift.sh` | Size and entry count of `~/.claude/settings.json` permission lists; flags lists that exceed a threshold (e.g. >150 entries). Future: track per-entry trigger counts. | + +Adding a scanner: drop a new script under `scanners/`, no driver changes needed. + +### Skills + +`.agents/skills/maintenance-audit/SKILL.md` — workflow for walking findings with the user. Steps: + +1. Run `bootstrap/scripts/maintenance/scan.sh --scope= --json` to get a fresh structured list. +2. Group findings by category, present worst severity first (`warn` → `suggest` → `info`). +3. For each item, offer three choices: **act**, **defer**, **ignore**. +4. If **act**: invoke the `maintenance-act` skill with the item's command. +5. If **defer**: append a line to `~/.local/state/maintenance/deferred.md` with date, item key, reason, and expiry (default 90 days). +6. If **ignore**: do nothing — the item will reappear on the next scan. +7. After all items are handled, summarize what was acted on, deferred, ignored. + +`.agents/skills/maintenance-act/SKILL.md` — safe execution wrapper. Steps: + +1. Echo the proposed command verbatim. +2. Ask the user: run as-is, modify, or skip. If they propose a modified command, echo the modified form back for confirmation before running. +3. Run the chosen command, capture stdout/stderr/exit. +4. Report outcome. +5. If the action was a deletion, suggest re-running `scan.sh --scope= --no-write` to verify the item is gone. + +Both skills are plain markdown with no Claude-specific syntax — invokable from any agent. + +### Per-provider shims + +`.claude/commands/maintenance.md` (and the two siblings) are each ~5 lines of markdown that say: + +```markdown +# Maintenance Audit +Use the `maintenance-audit` skill with scope=`$ARGUMENTS or "all"`. +``` + +When other providers are adopted, their command directories get analogous shims pointing at the same skill. + +### Hooks + +`~/.claude/hooks/session-start-nudge.sh`: + +```bash +#!/usr/bin/env bash +exec ~/git/setup/bootstrap/scripts/maintenance/show-digest.sh 3 +``` + +`~/.claude/hooks/session-end-cwd-log.sh`: + +```bash +#!/usr/bin/env bash +exec ~/git/setup/bootstrap/scripts/maintenance/log-session-end.sh +``` + +`show-digest.sh N` reads `~/.local/state/maintenance/last-digest.md` and prints up to N items, warn-first. If the digest is missing or older than 14 days, prints a one-line reminder pointing at `systemctl --user status maintenance-scan.timer`. Must complete in <50ms (target <20ms). + +`log-session-end.sh` appends ` ` to `~/.local/state/maintenance/sessions.log`. No interpretation — the weekly scan reads this log later. + +Hooks registered in `~/.claude/settings.json` under existing `hooks` block: + +```json +{ + "hooks": { + "SessionStart": [{ "type": "command", "command": "bash ~/.claude/hooks/session-start-nudge.sh", "timeout": 2 }], + "SessionEnd": [{ "type": "command", "command": "bash ~/.claude/hooks/session-end-cwd-log.sh", "timeout": 2 }] + } +} +``` + +These are added alongside existing hook entries; no existing hook is modified. + +### Systemd timer + +`bootstrap/systemd/maintenance-scan.timer`: + +``` +[Unit] +Description=Weekly workstation maintenance scan + +[Timer] +OnCalendar=Sun 09:00 +RandomizedDelaySec=2h +Persistent=true + +[Install] +WantedBy=timers.target +``` + +`bootstrap/systemd/maintenance-scan.service`: + +``` +[Unit] +Description=Run workstation maintenance scan + +[Service] +Type=oneshot +ExecStart=/bootstrap/scripts/maintenance/scan.sh +TimeoutStartSec=10min +``` + +User-level systemd (`systemctl --user`), no root. `install.sh` writes the installed unit with the actual repo path detected at install time, so the timer does not assume the checkout lives at `~/git/setup`. `Persistent=true` ensures missed runs (laptop closed Sunday morning) catch up on next boot. + +### install.sh + +Installs the timer and symlinks the hooks. Idempotent. Single command: + +```bash +~/git/setup/bootstrap/scripts/maintenance/install.sh +``` + +Steps it performs: +1. `mkdir -p ~/.local/state/maintenance ~/.config/systemd/user ~/.claude/hooks`. +2. Symlink the systemd unit files into `~/.config/systemd/user/`. +3. Write the two hook shims to `~/.claude/hooks/` (overwriting if present). +4. Print a manual instruction for the user to add the two `~/.claude/settings.json` hook entries (we don't auto-edit settings.json — too easy to corrupt). +5. `systemctl --user daemon-reload && systemctl --user enable --now maintenance-scan.timer`. +6. Run `scan.sh` once immediately to populate the first digest. + +## Data Formats + +### Digest / journal entry + +```markdown +## 2026-05-09 (weekly scan) +### setup +- [info] setup doctor: all green +- [warn] setup drift: 2 dotfiles changed in home :: review and reconcile :: `setup drift` + +### disk +- [warn] ~/Downloads: 12.4 GB (up from 8.1 GB last week) :: review and prune :: `du -sh ~/Downloads/* | sort -h` +- [suggest] ~/projects/old-thing/node_modules: 1.2 GB, untouched 187d :: rm if dead :: `rm -rf ~/projects/old-thing/node_modules` + +### docker-k8s +- [suggest] 8 dangling images, ~2.4 GB reclaimable :: prune :: `docker image prune -f` +``` + +Format spec, per item: + +``` +- [] :: :: `` +``` + +`severity ∈ {info, suggest, warn}`. The `:: ` segment is optional for items with no obvious one-liner. + +### JSON form (for skill consumption) + +```json +{ + "scan_date": "2026-05-09T09:00:00+02:00", + "items": [ + { + "category": "disk", + "severity": "warn", + "key": "downloads-size", + "description": "~/Downloads: 12.4 GB (up from 8.1 GB last week)", + "action": "review and prune", + "command": "du -sh ~/Downloads/* | sort -h" + } + ] +} +``` + +`key` is a stable identifier per scanner+item, used to match against `deferred.md`. + +### deferred.md + +```markdown +- 2026-05-02 :: dev-cruft :: ~/projects/quarterly-thing/node_modules :: kept — used quarterly :: expires 2026-08-02 +- 2026-04-15 :: disk :: ~/Downloads/old-installer.iso :: keep until next migration :: expires 2026-07-15 +``` + +Plain text, manually editable. `scan.sh` reads it and filters items whose `category::key` matches an unexpired entry. + +### sessions.log + +``` +2026-05-09T14:32:11+02:00 /home/al/git/setup +2026-05-09T15:01:44+02:00 /home/al/projects/foo +``` + +Append-only. The `dev-cruft.sh` scanner reads this to surface "cwds you worked in recently that have lingering untracked files." + +## Documentation Deliverables + +- `docs/MAINTENANCE.md` (new) — user-facing: what gets scanned, how to read the digest, how to run on-demand commands, how to defer items, how to disable the timer, how to add a new scanner. Style matches existing `docs/GHOSTTY.md` and `docs/TMUX.md`. +- `README.md` — new "Maintenance" subsection under Features pointing at `docs/MAINTENANCE.md`. +- `CHANGELOG.md` — new entry under unreleased: `feat(maintenance): add provider-agnostic workstation maintenance system`. +- `.agents/README.md` (new) — short note on the `.agents/` convention and the per-provider shim pattern; references the `maintenance-audit` and `maintenance-act` skills as canonical examples. +- `.agents/skills/maintenance-audit/SKILL.md` and `.agents/skills/maintenance-act/SKILL.md` — agent-facing instructions; not user docs but should be readable by a human. + +## Risks and Open Questions + +- **SessionStart latency.** Hook adds wall time to every Claude session start. Target <20ms; the `tail`-based shim should beat that, but worth measuring on real hardware before committing. +- **`setup doctor` hang risk.** If `setup doctor` ever blocks on network or a missing binary, the systemd timer's `TimeoutStartSec=10min` cap saves us, but the resulting digest will be partial. The driver should print which scanners timed out. +- **Reachable kube contexts.** `docker-k8s.sh` scans every context in `~/.kube/config`. If a context points at an unreachable cluster, it'll hang on connect. Solution: per-context timeout via `kubectl --request-timeout=5s`. +- **`apt` on systems without it.** `system-health.sh` assumes Ubuntu. Acceptable per the setup repo's stated Ubuntu 22.04/24.04 scope, but the scanner should detect-and-skip rather than error on non-apt systems. +- **`deferred.md` growth.** Without expiry enforcement, the deferred list grows forever. Expiry is per-entry, but the driver should warn when entries are past their expiry so the user can re-decide rather than silently re-surfacing them. +- **Promotion to a `setup` Rust component.** If the system proves valuable, the install step becomes a `setup` component (`cli/src/components/maintenance.rs`) so it gets profile-aware install/uninstall. Tracked as future work, not in this spec. + +## Phased Delivery + +The implementation plan should sequence work so partial delivery still produces value: + +1. **Phase 1 — substrate.** `scan.sh` driver, three highest-value scanners (`setup-doctor.sh`, `disk.sh`, `dev-cruft.sh`), digest/journal format, `install.sh`, systemd units. No agent integration yet — the digest is readable directly. +2. **Phase 2 — hooks.** `show-digest.sh`, `log-session-end.sh`, the two thin Claude hook shims, settings.json entries. SessionStart nudge becomes the primary "you have unresolved items" surface. +3. **Phase 3 — skills and commands.** `maintenance-audit` and `maintenance-act` skills, three Claude command shims. On-demand `/maintenance`, `/clean-disk`, `/clean-dev` work end-to-end. +4. **Phase 4 — remaining scanners.** `docker-k8s.sh`, `system-health.sh`, `config-drift.sh`. Each is independent and can land when the relevant trade-off (e.g. kubectl timeout handling) is sorted. +5. **Phase 5 — docs.** `docs/MAINTENANCE.md`, README section, CHANGELOG, `.agents/README.md`. Done last so the docs reflect what shipped, not what was planned. + +After Phase 1 the system already produces value: a weekly digest you can read manually. Each subsequent phase adds an interaction layer on top. diff --git a/plans/2026-04-18-manifest-architecture-plan.md b/plans/manifest-architecture-plan.md similarity index 99% rename from plans/2026-04-18-manifest-architecture-plan.md rename to plans/manifest-architecture-plan.md index 97beb92..3a9c567 100644 --- a/plans/2026-04-18-manifest-architecture-plan.md +++ b/plans/manifest-architecture-plan.md @@ -1,4 +1,6 @@ -# Manifest-Driven Architecture + Profiles — Implementation Plan +# Manifest-Driven Architecture + Profiles - Implementation Plan + +**Status:** completed / archival. Durable user-facing documentation lives in [`docs/MANIFEST.md`](../docs/MANIFEST.md); the historical design spec is [`manifest-architecture-spec.md`](manifest-architecture-spec.md). > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. @@ -8,7 +10,7 @@ **Tech Stack:** Rust 2021, `clap` 4 (CLI), `serde` + `toml` 0.8 (schema), `anyhow` (errors), `which` (binary probing), `dirs` (home/config paths), existing test harness (Docker + bash). -**Reference spec:** `plans/2026-04-18-manifest-architecture-design.md`. Implementation is authoritative where the two differ, but any such divergence must be a deliberate choice flagged in a commit message. +**Reference spec:** `plans/manifest-architecture-spec.md`. Implementation is authoritative where the two differ, but any such divergence must be a deliberate choice flagged in a commit message. --- @@ -57,7 +59,7 @@ Write `cli/src/manifest/mod.rs`: ```rust //! Declarative manifest describing available components and profiles. //! -//! See `plans/2026-04-18-manifest-architecture-design.md` for the full design. +//! See `plans/manifest-architecture-spec.md` for the full design. pub mod schema; ``` @@ -3102,7 +3104,7 @@ Expected: all tests pass. - [ ] **Step 5: Commit** ```bash -git add cli/src/ +git add cli/src/ git commit -m "refactor: delete legacy system/packages/ module (migrated to components/)" ``` @@ -4644,7 +4646,7 @@ Also update the "Available Components" table row-style description to a short pa The full catalog lives in [`bootstrap/manifest.toml`](bootstrap/manifest.toml). Run `setup list` to see it with your local profile/tag filters applied. -See [plans/2026-04-18-manifest-architecture-design.md](plans/2026-04-18-manifest-architecture-design.md) +See [plans/manifest-architecture-spec.md](plans/manifest-architecture-spec.md) for the architecture. ``` @@ -4713,7 +4715,7 @@ git commit -m "docs(changelog): document manifest + profiles release" Run through this before declaring the plan ready to execute: -- [ ] **Spec coverage:** every numbered requirement in `plans/2026-04-18-manifest-architecture-design.md` §§1–12 maps to a task above. +- [ ] **Spec coverage:** every numbered requirement in `plans/manifest-architecture-spec.md` §§1–12 maps to a task above. - [ ] **Placeholders:** grep the plan for "TBD", "TODO", "fill in", "similar to". Fix any hits. - [ ] **Type consistency:** `ComponentSpec` field names match between schema.rs, the manifest TOML, and the resolver references (id, display_name, depends_on, tags, requires_*, interactive). - [ ] **Command consistency:** `setup install`, `setup uninstall`, `setup doctor`, `setup list`, `setup profile`, `setup check` all match the design's CLI surface (§7). @@ -4724,7 +4726,7 @@ Run through this before declaring the plan ready to execute: ## Execution handoff -Plan complete and saved to `plans/2026-04-18-manifest-architecture-plan.md`. Two execution options: +Plan complete and saved to `plans/manifest-architecture-plan.md`. Two execution options: 1. **Subagent-Driven (recommended)** — a fresh subagent per task, two-stage review between tasks, fast iteration. 2. **Inline Execution** — work the plan in this session, batch checkpoints for review. diff --git a/plans/2026-04-18-manifest-architecture-design.md b/plans/manifest-architecture-spec.md similarity index 99% rename from plans/2026-04-18-manifest-architecture-design.md rename to plans/manifest-architecture-spec.md index f98e91c..5f64557 100644 --- a/plans/2026-04-18-manifest-architecture-design.md +++ b/plans/manifest-architecture-spec.md @@ -1,6 +1,7 @@ -# Manifest-Driven Architecture + Profiles — Design +# Manifest-Driven Architecture + Profiles - Spec + +**Status:** implemented; durable user-facing documentation lives in [`docs/MANIFEST.md`](../docs/MANIFEST.md). -**Date:** 2026-04-18 **Scope:** Sub-project 1 of the 2026 refresh. Covers: declarative component manifest, user-override layer, composable profiles, component dependency graph, `--dry-run`, per-component `uninstall` (also used for `--rollback-on-failure`), `setup doctor`, full migration of existing components. **Out of scope (deferred):** AI tooling installers and `.claude`/`.agents` seed configs (Sub-project 2). Cross-distro package-manager abstraction (future).