# Vertical Feature Architecture Spec > **Source of truth.** Copied from `docs/superpowers/specs/2026-04-21-vertical-monorepo-refactor-design.md` for in-tree reference. Edits here should be backported to the design spec. --- # Vertical Feature Monorepo Refactor — Design Spec **Date:** 2026-04-21 **Status:** Approved for implementation planning **Supersedes (partially):** 2026-04-06-clean-architecture-monorepo-template-design.md **Source spec:** `monorepo-architecture-spec-detailed-v5.md` (v1 + addenda v3/v4/v5) --- ## 1. Goal Refactor the template from a horizontal Clean Architecture monorepo (single `packages/core`, single `packages/api`, etc.) into a vertical feature-package monorepo where business capabilities (`auth`, `blog`, `media`, `marketing-pages`, `navigation`) are the top-level organizing principle, supported by `core-*` foundation packages for non-business concerns. The refactor preserves Clean Architecture layering *inside* each feature (the existing rigor) while reorganizing *between* packages by business capability. --- ## 2. Current state (summary) - `packages/core` — all domains (auth, content) share one Clean Architecture layout with InversifyJS DI container - `packages/api` — single tRPC aggregator + per-domain routers - `packages/api-client` — React Query hooks + `ApiProvider` + `useTRPC` - `packages/cms-core` — Payload config + all collections (Users, Articles, Media, SiteSettings global) - `packages/cms-client` — dual-mode Payload client wrapper; defined but unused - `packages/ui` — atomic-design component library - `apps/web-next` (empty shell), `apps/web-tanstack` (empty shell), `apps/cms` (just stabilized), `apps/storybook` - Mock repositories only — no Payload-backed infrastructure - 9 Vitest unit tests under `packages/core/tests/unit/` - Extensive per-directory AGENTS.md; 5 ADRs; 2 guides; 6 dated superpower plans --- ## 3. Target state (summary) - Five `core-*` packages: `core-shared`, `core-cms`, `core-api`, `core-trpc`, `core-ui` - Five feature packages: `auth`, `blog`, `media`, `marketing-pages`, `navigation` - Two tooling packages renamed: `eslint-config` → `core-eslint`, `typescript-config` → `core-typescript` - Three apps unchanged in name: `apps/web-next`, `apps/web-tanstack`, `apps/cms` - Packages deleted: `packages/core`, `packages/api`, `packages/api-client`, `packages/cms-core`, `packages/cms-client`, `packages/ui` - Per-feature InversifyJS containers (no shared container) - Clean Architecture controllers retained inside each feature (`interface-adapters/controllers/`) - Spec's `adapters/` renamed to `integrations/` to avoid collision with `interface-adapters/` - Boundary enforcement via `eslint-plugin-boundaries` + `package.json` deps + `exports` maps + Turborepo tags - Playwright e2e set up from day one in `web-next` and `web-tanstack` --- ## 4. Decision log All decisions captured from the brainstorming conversation: | # | Decision | Rationale | |---|---|---| | 1 | **Big-bang migration** (not incremental) | Template has empty reference apps and no external consumers; incremental dual-maintenance is overhead without benefit | | 2 | **Feature scope:** `auth` + `blog` + `media` + `marketing-pages` + `navigation` (all real, none as empty skeletons) | Template value is in worked examples; reference app needs something to render; spec §15A.2 forbids empty folders | | 3 | **Keep InversifyJS** | User wants to preserve existing DI pattern rather than move to plain function injection | | 4 | **Per-feature DI containers** (not a shared container) | Each feature owns its own `Container`, symbols, `getInjection()`. Perfect vertical ownership; no composition package needed for DI; tests unbind/rebind their own container | | 5 | **`media` is a feature package**, not `core-media` | Application can live without media; it's a business capability per spec §3. Site-wide concerns (SiteSettings) fold into `marketing-pages`, not a separate `site` package | | 6 | **Keep all three apps** (`web-next`, `web-tanstack`, `cms`) with existing names | `web-tanstack` proves features are framework-agnostic; no rename avoids churn | | 7 | **Keep `interface-adapters/controllers/` layer** | Transport-agnostic controllers enable CLI/cron reuse; template should demonstrate growth room for presenters/gateways | | 8 | **Rename spec's `adapters/` → `integrations/`** | Avoids collision with Clean Architecture's `interface-adapters/`; captures spec's "role not implementation" intent equally well; bounded deviation from spec | | 9 | **Delete existing tests, rewrite fresh**; rewrite AGENTS.md, add ADRs, mark old ADRs superseded where relevant | DI pattern change + file layout change make porting more work than rewriting; ADRs preserve architectural history | | 10 | **Include `eslint-plugin-boundaries`** from day one | Spec §13A.7 explicitly requires three-layer enforcement; package.json deps + exports + lint rules | | 11 | **Playwright set up immediately** in `web-next` and `web-tanstack` | Not deferred; demonstrates framework portability end-to-end | | 12 | **Keep `articles` collection/entity naming** (not rename to `posts`) | Simpler migration; collapses CMS-doc vs domain distinction which is fine for a template | Deviations from source spec (document explicitly as new ADRs): - Keep InversifyJS (spec examples use plain function injection) - Keep controller layer between tRPC and use-case (spec goes tRPC→use-case direct) - Rename spec's `adapters/` to `integrations/` - Omit `core-payload-client` wrapper (aligned with spec §10) --- ## 5. Target package layout ``` repo/ apps/ web-next/ # Next.js 15 App Router (port 3000) app/ layout.tsx # from @repo/core-trpc/next trpc/[trpc]/route.ts # tRPC fetch adapter → @repo/core-api appRouter blog/[slug]/page.tsx about/page.tsx page.tsx # home — navigation + marketing-pages e2e/ playwright.config.ts blog-post.spec.ts marketing-page.spec.ts home-nav.spec.ts package.json next.config.mjs tsconfig.json turbo.json web-tanstack/ # TanStack Start (port 3002) ... # parallel tRPC wiring; own providers from @repo/core-trpc/tanstack e2e/ playwright.config.ts blog-post.spec.ts cms/ # Payload admin host (port 3001) app/(payload)/ # unchanged from current stabilized state package.json next.config.mjs tsconfig.json turbo.json storybook/ # unchanged; updates imports from @repo/ui → @repo/core-ui packages/ # ─── CORE (foundation, tagged "core") ─── core-shared/ # generic primitives (no business knowledge) core-cms/ # Payload composition only (aggregates feature cms exports) core-api/ # tRPC composition only (aggregates feature api exports) core-trpc/ # frontend tRPC platform (client, providers per framework) core-ui/ # design-system primitives (atoms/molecules/templates) # ─── FEATURES (business capabilities, tagged "feature") ─── auth/ # Users collection + sign-in/up/out blog/ # Articles collection + article use-cases media/ # Media collection + upload helpers marketing-pages/ # pages collection + SiteSettings global navigation/ # header global # ─── TOOLING (tagged "tooling") ─── core-eslint/ core-typescript/ docs/ architecture/ overview.md # rewritten dependency-flow.md # rewritten vertical-feature-spec.md # copy of source spec decisions/ adr-001 … adr-009 # five existing + four new (see §10) guides/ adding-a-feature.md # rewritten testing-strategy.md # rewritten superpowers/specs/ # this file + implementation plan CLAUDE.md AGENTS.md docker-compose.yml package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.base.json turbo.json ``` **Package count:** 3 apps + 5 core + 5 feature + 2 tooling = **15 packages** (was 12). --- ## 6. Feature package internal shape Canonical mature shape (e.g., `packages/blog/`): ``` packages/blog/ src/ entities/ article.ts # Zod schema + Article type article.test.ts errors.ts application/ repositories/ articles-repository.interface.ts # IArticlesRepository use-cases/ get-article.use-case.ts get-article.use-case.test.ts create-article.use-case.ts infrastructure/ repositories/ payload-articles.repository.ts # @injectable, calls getPayload({ config }) from core-cms mock-articles.repository.ts # @injectable, for tests payload-articles.repository.test.ts interface-adapters/ # Clean Arch grouping (controllers now; presenters/gateways later) controllers/ articles.controller.ts # Zod safeParse → InputParseError → use case articles.controller.test.ts di/ # feature-local InversifyJS container symbols.ts # BLOG_SYMBOLS module.ts # ContainerModule container.ts # blogContainer + getInjection() container.test.ts integrations/ # renamed from spec's adapters/ cms/ collections/ articles.ts # Payload CollectionConfig hooks/ after-post-change.ts # Payload lifecycle adapter → calls effects index.ts # exports: articles (for core-cms composition) api/ router.ts # tRPC procedures → controllers router.test.ts effects/ # only when needed revalidate-post.ts sync-post-search.ts jobs/ # only when needed publish-scheduled-posts.ts events/ # only when needed post-updated.ts ui/ query.ts # trpc.blog.articleBySlug.queryOptions(...) query.test.ts article-client.tsx article-client.test.tsx page.tsx index.ts # re-exports ui components + public types tests/ article-by-slug.feature.test.ts # cross-layer feature test package.json # exports: ".", "./cms", "./api" tsconfig.json turbo.json # tags: ["feature"] ``` Small-feature variant (e.g., `packages/navigation/`) omits folders without meaningful code per spec §15 / addendum v5 ("create folders only when needed"): ``` packages/navigation/ src/ entities/ nav.ts infrastructure/repositories/ payload-navigation.repository.ts di/ symbols.ts module.ts container.ts interface-adapters/controllers/ navigation.controller.ts integrations/ cms/ globals/ header.ts + index.ts api/ router.ts ui/ query.ts index.ts ``` No `application/use-cases/`, `effects/`, `jobs/`, `events/` unless the feature grows them. **Request flow:** ``` useQuery(articleQuery(slug)) ui/query.ts (typed tRPC client) ↓ tRPC router.articleBySlug integrations/api/router.ts ↓ .input(zod).query(...) articlesController.getBySlug(input) interface-adapters/controllers/ ↓ safeParse → delegate getArticleUseCase(slug) application/use-cases/ ↓ getInjection(BLOG_SYMBOLS.IArticlesRepository) PayloadArticlesRepository.getBySlug infrastructure/repositories/ (@injectable) ↓ getPayload({ config }) from @repo/core-cms Payload Local API → PostgreSQL ``` **DI placement rationale:** `di/` sits at feature root (not under `infrastructure/`) because the container wires `application/` interfaces to `infrastructure/` implementations — it has knowledge of both layers and is a sibling to them, not a sub-layer. --- ## 7. Core package responsibilities ### `core-shared/` Generic reusable primitives. Zero business knowledge. ``` src/ lib/ env.ts date.ts payload/ access/ is-admin.ts fields/ slug-field.ts seo-fields.ts blocks/ cta.ts hooks/ set-published-at.ts slugify-if-missing.ts index.ts trpc/ init.ts # initTRPC.create + router/publicProcedure context.ts # createTrpcContext + TrpcContext type index.ts ``` Exports: `.`, `./payload`, `./trpc/init`, `./trpc/context`. Forbidden: importing any feature package. ### `core-cms/` Payload composition only. ``` src/ payload.config.ts # imports feature /cms exports, composes buildConfig generated-types.ts # Payload type generator output index.ts # re-exports config as default ``` Exports: `.`, `./generated-types`. Allowed exception: may import `@repo//cms` subpath exports only. ### `core-api/` tRPC composition only. ``` src/ root.ts # aggregates feature routers → appRouter index.ts # re-exports appRouter + AppRouter type ``` Allowed exception: may import `@repo//api` subpath exports only. ### `core-trpc/` Frontend tRPC platform with framework-specific provider shims. ``` src/ client.ts # createTRPCReact() query-client.ts # makeQueryClient() providers/ next-provider.tsx # 'use client' — Next.js App Router pattern tanstack-provider.tsx # TanStack Start pattern index.ts ``` Exports: `.`, `./next`, `./tanstack`. Forbidden: importing any feature package. ### `core-ui/` Design-system primitives only. ``` src/ atoms/ button/ input/ label/ molecules/ form-field/ organisms/ (generic only — e.g., modal, tabs, navigation-menu) templates/ auth-layout/ dashboard-layout/ lib/ utils.ts index.ts ``` Generic organisms (Modal, Tabs, NavigationMenu, Command) live here. Feature-specific organisms (e.g., `ArticleCard`, `PricingSection`, `HeaderNavMenu`) live in the owning feature's `ui/`. Spec §6.5 boundary. Forbidden: importing any feature package. --- ## 8. Payload collection & global ownership | Current | → New location | Slug / type | Notes | |---|---|---|---| | `cms-core/src/collections/users/` | `packages/auth/src/integrations/cms/collections/users.ts` | `users` | Authenticated collection | | `cms-core/src/collections/articles/` | `packages/blog/src/integrations/cms/collections/articles.ts` | `articles` | Name preserved per decision #12 | | `cms-core/src/collections/media/` | `packages/media/src/integrations/cms/collections/media.ts` | `media` | Upload collection | | `cms-core/src/globals/site-settings/` | `packages/marketing-pages/src/integrations/cms/globals/site-settings.ts` | `site-settings` | Site-wide metadata | | (new) | `packages/marketing-pages/src/integrations/cms/collections/pages.ts` | `pages` | | | (new) | `packages/navigation/src/integrations/cms/globals/header.ts` | `header` | | Composition in `core-cms/src/payload.config.ts`: ```ts import { buildConfig } from 'payload' import { users } from '@repo/auth/cms' import { articles } from '@repo/blog/cms' import { pages, siteSettings } from '@repo/marketing-pages/cms' import { header } from '@repo/navigation/cms' import { media } from '@repo/media/cms' export default buildConfig({ collections: [users, articles, pages, media], globals: [header, siteSettings], typescript: { outputFile: new URL('./generated-types.ts', import.meta.url).pathname, declare: false, }, // db, admin config unchanged from current cms-core }) ``` **Hook routing policy:** - Generic hooks (e.g., `slugify-if-missing`, `set-published-at`) live in `core-shared/src/payload/hooks/` and are imported by any collection that needs them. - Business-specific hooks (e.g., "revalidate blog post page when published") live in the feature's `integrations/cms/hooks/`, which call the feature's `effects/` for reusable side effects. --- ## 9. Boundaries + enforcement ### 9.1 Five tags Package-level `turbo.json` tags (refined from earlier ADR-006's three-tag model): | Tag | Packages | |---|---| | `app` | `apps/web-next`, `apps/web-tanstack`, `apps/cms`, `apps/storybook` | | `core-composition` | `packages/core-api`, `core-cms`, `core-trpc` | | `core` | `packages/core-shared`, `core-ui` | | `feature` | `packages/auth`, `blog`, `media`, `marketing-pages`, `navigation` | | `tooling` | `packages/core-eslint`, `core-typescript` | Note: `core-trpc` is `core-composition` (not plain `core`) because it transitively reaches features through `core-api`'s `AppRouter` type. ### 9.2 Allowed dependency directions | Tag | May depend on | |---|---| | app | app, core, core-composition, feature, tooling | | core-composition | core, core-composition, feature, tooling | | core | core, core-composition, tooling | | feature | core, tooling | | tooling | tooling | ### 9.3 Composition exceptions - `core-cms` may import `@repo//cms` subpath exports only. - `core-api` may import `@repo//api` subpath exports only. - No other package may deviate from the five-tag rules. ### 9.4 Four enforcement layers 1. **`package.json` dependencies** — only allowed deps declared. 2. **`exports` maps** — feature packages expose `.`, `./cms`, `./api` only (no deep source paths). 3. **ESLint `eslint-plugin-boundaries`** (lint-time) — configured in `packages/core-eslint/` flat config: - Enforces the five-tag rules (same rules as Turbo boundaries) - File-specific exemptions via `// @boundaries-ignore` comments 4. **Turborepo `boundaries`** (build-graph time) — configured in root `turbo.json`: - Validates the entire workspace dependency graph, including transitive dependencies - Catches issues that lint-time checking misses (e.g., transitive feature reaches) - Run `pnpm turbo boundaries` to validate ### 9.5 Root `turbo.json` (unchanged concept) ```json { "tasks": { "build": { "dependsOn": ["^build"], "outputs": [".next/**", "dist/**"] }, "lint": { "dependsOn": ["^lint"] }, "typecheck": { "dependsOn": ["^typecheck"] }, "test": { "dependsOn": ["^build"] }, "test:e2e": { "dependsOn": ["^build"], "cache": false } } } ``` Tags govern architectural boundaries; `dependsOn: ["^build"]` governs task execution order — separate concerns per spec §13A.6. --- ## 10. Test placement + tooling ### 10.1 Placement | Scope | Location | Suffix | |---|---|---| | Entity / value-object | colocated | `*.test.ts` | | Use-case (with fake repo) | colocated | `*.test.ts` | | Controller (Zod validation) | colocated | `*.test.ts` | | Infrastructure repository | colocated | `*.test.ts` | | DI container bindings | colocated | `*.test.ts` | | React component | colocated | `*.test.tsx` | | Query helper | colocated | `*.test.ts` | | Core-shared primitive | colocated in `core-shared` | `*.test.ts` | | Feature-level cross-layer | `packages//tests/` | `*.feature.test.ts` | | Browser e2e | `apps//e2e/` | `*.spec.ts` | ### 10.2 Vitest - Each package has its own `vitest.config.ts`. - Shared base in `packages/core-typescript/vitest.base.ts`; packages extend it and pick `environment: 'jsdom' | 'node'` per need. - Turbo `test` task runs `vitest run` per package. ### 10.3 DI in tests (per-feature container) Each feature's tests import the feature's own container and rebind per test: ```ts import { blogContainer, BLOG_SYMBOLS } from '../../di/container' import { MockArticlesRepository } from '../../infrastructure/repositories/mock-articles.repository' beforeEach(() => { blogContainer.unbindAll() blogContainer.bind(BLOG_SYMBOLS.IArticlesRepository).to(MockArticlesRepository) }) ``` No shared `initializeContainer()` / `destroyContainer()`. ### 10.4 Starter test coverage (end of refactor) - `core-shared`: 3 tests (slug-field, set-published-at, is-admin) - `auth`: 6 tests (3 controllers + 3 use-cases) — replaces current auth unit tests - `blog`: 3 tests (2 use-cases + 1 feature test for `articleBySlug`) - `marketing-pages`, `navigation`, `media`: minimum one feature test each Total ~15 unit/integration tests + 4 e2e = replaces current 9 tests with full new layout. ### 10.5 Playwright (included from day one) - `apps/web-next/e2e/`: - `playwright.config.ts` — starts dev server on port 3000 via `webServer`, chromium only initially - `blog-post.spec.ts`, `marketing-page.spec.ts`, `home-nav.spec.ts` - `apps/web-tanstack/e2e/`: - Parallel config (port 3002) - `blog-post.spec.ts` (validates framework-agnostic feature claim) - `apps/cms/` — no e2e (Payload has its own admin tests) - Root script: `pnpm test:e2e` via Turbo - ESLint config adds `eslint-plugin-playwright` for e2e folders - Playwright's `globalSetup` verifies Postgres is running; fails fast with a helpful message otherwise --- ## 11. Docs + ADR strategy ### 11.1 Existing ADRs | File | Action | Notes | |---|---|---| | `adr-001-monorepo-tool.md` | Keep unchanged | Turborepo + pnpm still accurate | | `adr-002-di-framework.md` | Keep; append note | InversifyJS kept, but now per-feature containers | | `adr-003-cms-separation.md` | Mark v1 superseded, write v2 | New architecture splits `cms-core` into `core-cms` + feature-owned collections | | `adr-004-dual-mode-client.md` | Mark superseded | `cms-client` deleted per spec §10 | | `adr-005-atomic-design.md` | Keep; append scope note | Applies to `core-ui/` only | ### 11.2 New ADRs - `adr-006-vertical-feature-packages.md` — the main architectural pivot; references source spec - `adr-007-drop-cms-client-wrapper.md` — rationale for removing `packages/cms-client` - `adr-008-per-feature-di-containers.md` — why each feature owns its InversifyJS container - `adr-009-integrations-folder-naming.md` — why spec's `adapters/` is renamed `integrations/` ### 11.3 Rewritten docs - `docs/architecture/overview.md` — new diagram, new flow, vertical package organization - `docs/architecture/dependency-flow.md` — new graph, three-tag boundary model - `docs/architecture/vertical-feature-spec.md` — copy of source spec for offline reference - `docs/guides/adding-a-feature.md` — new recipe (small feature + mature feature, per addendum v5) - `docs/guides/testing-strategy.md` — new placement table ### 11.4 Deleted - `docs/superpowers/plans/*` — 6 stale plan files from previous architecture ### 11.5 AGENTS.md All rewritten: - Root `AGENTS.md` — new package map, new data flow, new rules, new boundary model - Per-core-package: responsibilities + forbidden imports (~60 lines each) - Per-feature-package: layer rules, addendum v5 folder-creation checklist, test placement - Per-layer inside features: local import rules, test patterns (short) - Per-app: purpose, imports, port, dev commands, e2e commands Root `CLAUDE.md` — updated "Read First" pointers, unchanged port table, added boundary-enforcement note. --- ## 12. Migration sequencing Big-bang refactor executed as 11 internal phases; each phase ends with a verification gate (`pnpm typecheck && pnpm test`) before proceeding. Commit per phase (or per feature within Phase 5) so `git bisect` works. | # | Phase | Key artifact | Gate | |---|---|---|---| | 1 | Scaffold core packages (empty shells) | `packages/core-shared/`, `core-cms/`, `core-api/`, `core-trpc/`, `core-ui/` with stubs | `pnpm install` + `pnpm typecheck` green | | 2 | Populate `core-shared` | Fields, blocks, access helpers, hooks, tRPC init/context | `pnpm test --filter @repo/core-shared` passes | | 3 | Populate `core-cms` stub **and repoint `apps/cms`** | `payload.config.ts` lifted from `cms-core` to `core-cms`; `collections: []`, `globals: []` initially; `apps/cms` updates its import from `@repo/cms-core` to `@repo/core-cms` | `pnpm dev --filter @repo/cms` boots admin UI; `pnpm generate:types` succeeds | | 4 | Migrate `blog` feature end-to-end (first vertical — proves pattern) | Full canonical shape; Articles collection; per-feature DI container; tRPC router; UI | `pnpm typecheck && pnpm test --filter @repo/blog` green | | 5 | Migrate remaining features: `auth`, `marketing-pages`, `navigation`, `media` | Each follows the blog template | Per-feature typecheck + tests + `core-cms` regenerates | | 6 | Populate `core-trpc` + wire apps | Client, per-framework providers; route handlers in `web-next` + `web-tanstack`; example pages | `pnpm dev` serves pages; tRPC returns Payload data | | 7 | Migrate `core-ui` | Move `packages/ui/` contents; relocate feature-shaped organisms into features; update Storybook imports | Storybook builds; `pnpm test` green | | 8 | Delete old packages | `core/`, `api/`, `api-client/`, `cms-core/`, `cms-client/`, `ui/` | `pnpm install && pnpm typecheck && pnpm test` green | | 9 | Boundary enforcement | Install `eslint-plugin-boundaries`; add package-level `turbo.json` tags; write lint rules | `pnpm lint` zero violations | | 10 | Playwright setup | Configs, initial specs in both frontends; root `test:e2e` script | `pnpm test:e2e` green | | 11 | Docs rewrite | Copy spec; rewrite overview, dependency-flow, guides; new ADRs; all AGENTS.md; delete stale plans | Human review | **Commit strategy:** one commit per phase. Phase 5 may be multiple commits (one per feature). Every commit builds + tests green. --- ## 13. Out of scope (deferred) - Real Payload integration tests with a test database (stub with mock repos; write real integration tests later) - Coverage reporting aggregation across packages (initial vitest setup per-package; aggregation is a follow-up) - Multi-browser Playwright matrix (chromium only initially; add firefox/webkit later) - Queue workers / CLI scripts (no `core-events` package yet; spec addendum v4's optional `core-events` stays deferred until a feature actually needs an event bus) - Payload subscriptions / realtime (spec addendum v4); no feature requires it yet - CMS app Next.js 15.5 + Payload 3.81 stabilization concerns (recently patched; monitor; no specific action in this refactor) --- ## 14. Success criteria - `pnpm install && pnpm typecheck && pnpm lint && pnpm test && pnpm build` all green - `pnpm test:e2e` green against running dev servers - `pnpm dev --filter @repo/web-next` serves a home page with navigation + marketing content + a blog index, and `/blog/[slug]` shows an article — all fed by tRPC → feature controllers → use-cases → Payload Local API - `pnpm dev --filter @repo/web-tanstack` renders the same blog post using the same feature packages - Storybook builds showing `core-ui` primitives - Any deep import (e.g., `import x from '@repo/blog/src/...'`) fails `pnpm lint` - Any cross-feature import fails `pnpm lint` - Root `AGENTS.md` and one-per-package AGENTS.md reflect the new architecture - 9 new ADRs (5 existing maintained/appended/superseded + 4 new) - Zero references to deleted packages anywhere in the codebase --- ## 15. Post-approval next step Invoke the `superpowers:writing-plans` skill to produce a detailed, executable implementation plan based on the 11-phase sequencing in §12. Each phase becomes a plan section with concrete file-by-file steps, verification commands, and commit-message templates.