# Spoon: Stabilize → Unify → Build — Implementation Plan Index > **For agentic workers:** Execute the phase plans **in order**. Each phase is a > standalone plan that ships working, tested software on its own. Use > `superpowers:subagent-driven-development` (fresh subagent per task, review > between tasks) or `superpowers:executing-plans` (batched with checkpoints). **Spec:** [`../specs/2026-07-10-spoon-stabilize-unify-build-design.md`](../specs/2026-07-10-spoon-stabilize-unify-build-design.md) **Design review:** Gib, 2026-07-10 (tenancy = owner + trusted friends; runtimes = Codex + OpenCode + Claude Code, all in the per-user box; all four feature tracks; ordering = stabilize → unify → build). ## Phases | # | Plan | Tasks | Scope | | - | ---- | ----- | ----- | | 1 | [phase1-stabilize](2026-07-10-spoon-phase1-stabilize.md) | 13 | Critical/High bug fixes on the current architecture: home-deletion data loss, box lifecycle races/leaks, symlink escape, job-lifecycle recovery (heartbeat/timeout/cancel), auto-sync gating, terminal sizing, workspace shell keying, not-found handling. | | 2 | [phase2-runtime-unification](2026-07-10-spoon-phase2-runtime-unification.md) | 12 | `AgentRuntime` adapter interface; Codex/OpenCode/Claude Code all exec into the box; delete the legacy per-job OpenCode container; runtime picker + queue-time validation; Fedora image + smoke; secrets hygiene. | | 3 | [phase3-dev-box-surface](2026-07-10-spoon-phase3-dev-box-surface.md) | 11 | `/machine` page (box status/lifecycle + full-page terminal + home file browser); user-scoped `/box/*` worker routes + HMAC tokens; persistent workspace terminal (survives tab switch); terminal QoL. | | 4 | [phase4-sync-correctness](2026-07-10-spoon-phase4-sync-correctness.md) | 12 | Correct head-SHA (branch ref, not truncated compare); stable maintenance-thread dedup; GitHub webhooks (push + installation lifecycle); Octokit retry/throttle + `rate_limited` status; bound unbounded queries; surface `needs_reauth`. | | 5 | [phase5-notifications-polish](2026-07-10-spoon-phase5-notifications-polish.md) | 15 | `notifications` + `notificationPreferences` tables, in-app bell, preference-gated UseSend email; polish sweep (skeletons, error handling, form re-sync, auth copy, workspace UX, a11y, dead-code removal); docs rewrite. | **Total: 63 tasks**, each ending in an independently testable, committed deliverable. ## Cross-phase dependencies - **Phase 1 → 2, 3.** Phases 2 and 3 consume the Phase-1 box-lifecycle API: `export type BoxHandle = { boxName: string; release: () => void }` and `acquireUserBox(args: { username; workdir; containerHome }) => Promise` (idempotent `release`, per-username mutex, `--init`, startup reconcile of `spoon-box-*`). Both later plans carry a fallback note for the pre-Phase-1 `Promise` + `releaseUserBox(username)` signature — **build Phase 1 first and the `BoxHandle` form is what lands.** - **Phase 1 → 5.** Phase 5's `agent_turn_finished` / `agent_needs_input` notifications emit at the job-status transitions that Phase 1 hardens (`updateStatus`, `applyMaintenanceDecision`). - **Phase 4 → 5.** Phase 5's `connection_needs_reauth` email emits where the Phase-4 webhook sets `gitConnections.status = needs_reauth`; Phase 5 Task 3 marks that emit point defensively if Phase 4 hasn't landed. - **Phase 4 depends on Phase 1's auto-sync gating** (`autoSyncEnabled` etc. land in Phase 1 Task 8) and layers head-SHA/dedup/webhooks on top. Phases 3 and 4 are otherwise independent and could be reordered or parallelized after Phases 1–2. The recommended sequential order matches the spec. ## Deliberate deferrals (documented by the plan authors) These are called out inline in the plans, not gaps: - **Phase 1:** `updateStatus` implements the terminal-state guard (the cancel-revert fix) rather than a full forward-only transition matrix — no illegal transition is otherwise exercised. Stale-job recovery **times out** rather than requeues (requeue-with-attempt-limit needs a new `claimAttempts` field — deferred). `requireAiLowRiskForSync` is scoped to Phase 4 (the AI-review→merge path it guards doesn't exist yet). - **Phase 2:** exact `opencode run` / `claude -p` flags and the `@anthropic-ai/claude-code` version pin are reconciled at implementation time via the extended `scripts/smoke-agent-container` (`--help` probes + `npm view`), since the live CLIs aren't available while planning. - **Phase 3:** dotfiles re-materialization for the `/box` surface is out of scope (the persistent home already carries dotfiles from prior job runs); box start only ensures a login-shell `.bash_profile`. Docker-touching code is verified by documented manual steps; only pure logic is unit-tested. - **Phase 4:** the webhook route test cannot assert the scheduled `'use node'` refresh ran in-process (convex-test VM limitation) — covered by the manual checklist. Octokit plugin versions may need a bump on `bun install`. - **Phase 5:** `(app)/error.tsx` + not-found handling lives in **Phase 1** (finding #14), not here. ## Testing Every task is test-first where a test is meaningful. Test surfaces: - **Worker** (`apps/agent-worker/tests/unit/`, vitest): box-registry mutex/handle semantics, path containment incl. symlinks, terminal resize-message parsing, runtime-adapter fixture-stream parsing. - **Backend** (`packages/backend/tests/unit/`, `convex-test`): claim validation/rollback, heartbeat-timeout cron, transition guard incl. cancel-vs-worker race, auto-sync gating matrix, maintenance-thread dedup, webhook signature verification, notification emit/preferences. - **Next** (`apps/next/tests/component`, jsdom + testing-library): terminal fit-on-fonts-ready + resize, workspace shell remount on job switch, form re-sync, not-found states, notification bell. - **Docker-touching worker code** (box `--init`, dockerode TTY exec, `/box` lifecycle) uses documented manual verification — needs a live daemon. ## How to run each phase ``` Subagent-driven (recommended): one fresh subagent per task, two-stage review between tasks. Inline: superpowers:executing-plans, batched with checkpoints. ``` Start with Phase 1, Task 1 (`cleanupOrphanedWorkspaces` layout-awareness) — it closes the highest-severity bug (a cleanup call deletes every user's home).