AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Promote Component

skill-lukedj78-dev-flow-promote-component · by lukedj78

Use to refactor a React/RN component up the colocation hierarchy (L0 → L1 → L2) when its usage spreads across pages. Two modes: (1) "scan candidates" — analyzes the entire codebase, counts usages of every component under app/**/_components/ (web) or components/<feature>/ (mobile — Expo Router has no app/_components/ convention), and reports a table of promotion candidates with the Rule of Three;…

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add skill-lukedj78-dev-flow-promote-component

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-lukedj78-dev-flow-promote-component)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
16d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Promote Component? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

promote-component — Rule of Three automation

Contract

See references/contracts.md (vendored from dev-flow). Key facts:

  • Reads /.workflow/meta.json#stack.framework (must be "next", "expo-rn", or "monorepo").
  • Reads meta.json#stack.route_groups (optional, helps detect the target level).
  • Modifies code in / (or /apps// for monorepo).
  • Does NOT modify meta.json#phase. Appends to meta.json#history.
  • Always idempotent: re-running the scan reports the same candidates; re-running a promote on an already-promoted component does nothing.

When this skill applies

  • User says "scan promotion candidates" / "scansiona candidati promozione" → run the scan.
  • User says "promote " / "promovi " → execute the move.
  • The user is reviewing the codebase after a feature lands and wants to clean up duplication.

Orchestrator does NOT route here automatically — invoked on demand.

Knowledge dependencies

  • composition-patterns-guide/SKILL.md — the 7 Vercel composition rules + our colocation rules.
  • references/colocation-rules.md — the canonical Rule of Three + L0/L1/L2 spec.

Web vs mobile targets (read this first)

Next.js App Router supports _-prefixed private folders — app//_components/ is a valid non-routable convention there. Expo Router does not: every file under app/ (aside from a short reserved list) becomes a real route, so app//_components/ would create a ghost route on mobile, not a private folder. [VERIFY] this against the installed expo-router version — there's an open upstream issue requesting an underscore-skip convention; until it ships, treat mobile app/ as routes-only.

Consequently this skill uses different scan/target paths per platform — see references/colocation-rules.md for the full model and rationale. Summary:

| | Web (stack.framework == "next", or apps/web in a monorepo) | Mobile (stack.framework == "expo-rn", or apps/mobile in a monorepo) | |---|---|---| | Candidate scan root | app/**/_components/*.tsx | components//*.tsx (excludes components/{ui,theme,shared}) | | L0 target | app//_components/.tsx | components//.tsx | | L1 target | app/(group)/_components/.tsx | same folder as L0 (no separate L1 path on mobile — see colocation-rules.md) | | L2 target | components/shared//.tsx | components/shared//.tsx (identical) |

Everything below is written generically ("the platform's _components/-or-components// root") — substitute per the table above. The scripts (scripts/scan_promotion.py, scripts/promote.py) branch on meta.json#stack.framework automatically.

Workflow — scan mode

Step 1 — Detect framework + cwd

Read meta.json#stack.framework:

  • "next" → cwd = project root, scan app/**/_components/.
  • "expo-rn" → cwd = project root, scan components// (excluding components/{ui,theme,shared}).
  • "monorepo" → scan apps/web/ with the web rules and apps/mobile/ with the mobile rules, separately. Print two tables.

Step 2 — Find every promotion candidate

Web:

find app -type d -name "_components" -exec ls -1 {} \;

For each .tsx file in _components/, record component name, source path (e.g., app/(app)/posts/_components/PostCard.tsx), and current level (L0: under a leaf route, L1: under app/(group)/_components/).

Mobile:

find components -mindepth 2 -maxdepth 2 -name "*.tsx" | grep -vE '/(ui|theme|shared)/'

For each match, record component name, source path (e.g., components/posts/PostCard.tsx), and which feature folder(s) hold a copy of that name (duplicates across feature folders are the mobile promotion signal — see Step 4).

Step 3 — Count usages

For every component, grep the codebase for imports referencing its file path or filename (both platforms):

grep -rln "from .*['\"].*PostCard['\"]" app/ components/ --include="*.tsx" --include="*.ts"

Count distinct import sites (deduplicate by file).

Step 4 — Compute suggestions per Rule of Three

Web:

| Usage count | Current level | Suggestion | |---|---|---| | 1 | L0 | OK — stays | | 2 | L0 | Tolerated duplicate — wait the 3rd | | 3+, all in same route group | L0 (in 2+ pages) | Promote to L1 (app/(group)/_components/) | | 3+, across different route groups | L0 or L1 | Promote to L2 (components/shared//) | | 2+, but on its way up | L1 → L2 | Promote to L2 |

Mobile (mobile has no separate L1 path — see colocation-rules.md):

| Copies across feature folders | Suggestion | |---|---| | 1 | OK — stays | | 2 | Tolerated duplicate — wait the 3rd | | 3+, reconcilable to one feature/domain | Merge duplicates into one components//.tsx | | 3+, spanning different business domains | Promote to L2 (components/shared//) |

Step 5 — Print the report

Promotion candidates in apps/web/ (next):

| Component                  | Usages | Current level | Suggestion                              |
|----------------------------|--------|---------------|------------------------------------------|
| PostCard                   | 3      | L0            | Promote to L1 — app/(app)/_components/   |
| UserAvatar                 | 4      | L0            | Promote to L2 — components/shared/user/  |
| BillingSummary             | 2      | L0            | Wait the 3rd use                         |
| PricingTable               | 5      | L0            | Promote to L2 — components/shared/billing/ |

Promotion candidates in apps/mobile/ (expo-rn):

| Component                  | Usages | Current level | Suggestion                                |
|----------------------------|--------|---------------|--------------------------------------------|
| PostCard                   | 3      | L0            | Promote to L2 — components/shared/post/    |
| SettingsRow                | 2      | L0            | Wait the 3rd use                           |

Ask the user: "Vuoi promuoverne alcuni? (Y/n, oppure dimmi quali)".

Workflow — promote mode

Step 1 — Locate the source file

Web: find the file matching ` under app/**/_components/. **Mobile**: find the file matching under components// (excluding components/{ui,theme,shared}`).

If multiple matches (e.g., two copies at L0):

  • The "canonical" copy is the older / most-complete one.
  • Diff the two; flag any divergence to the user for resolution.

Step 2 — Determine target level

If invoked without an explicit target, recompute from usage/copy distribution:

  • Web: same route group, 3+ usages → L1: app/(group)/_components/.tsx. Different groups, 3+ usages → L2: components/shared//.tsx.
  • Mobile: copies in 3+ feature folders reconcilable to one domain → merge into components//.tsx (no move, dedupe only). Copies spanning different business domains → L2: components/shared//.tsx.

Ask the user for `` if not obvious (either platform). If an explicit target is provided ("promote PostCard to L2 in components/shared/post/"), honor it.

Step 3 — Move the file

Web:

# L0 → L1 (same group)
git mv app/(app)/posts/_components/PostCard.tsx app/(app)/_components/PostCard.tsx

# L0 → L2 (cross-group)
mkdir -p components/shared/post
git mv app/(app)/posts/_components/PostCard.tsx components/shared/post/PostCard.tsx

Mobile (never touches app/ — components never live there):

# Dedupe (3rd use reconciled to one feature) — keep the canonical copy in place, remove the others
rm components/profile/PostCard.tsx   # duplicate removed, canonical stays at components/posts/PostCard.tsx

# L0 → L2 (cross-domain)
mkdir -p components/shared/post
git mv components/posts/PostCard.tsx components/shared/post/PostCard.tsx

If duplicates existed at L0 (the "2 copies" case), also rm them (both platforms).

Step 4 — Update all imports

Scan all .tsx / .ts files in app/ and components/, find imports referencing the OLD path or filename, rewrite to the NEW path. Applies identically on both platforms — the import-rewrite step never assumes a platform-specific path shape.

Pattern types:

  • Web: from "@/app/(app)/posts/_components/PostCard"from "@/components/shared/post/PostCard"
  • Mobile: from "@/components/posts/PostCard"from "@/components/shared/post/PostCard"
  • from "./PostCard" (siblings) → resolve to absolute, then rewrite
  • from "../PostCard" (parent) → idem

Use a TypeScript-aware import rewrite (e.g., ts-morph Python equivalent via jscodeshift or simple regex with care).

Step 5 — Verify with tsc

npx tsc --noEmit

Must pass. If it fails:

  1. Inspect the error: usually a path that wasn't rewritten.
  2. Fix it manually.
  3. Re-verify.

If still failing after 2 attempts, ROLLBACK the move (git restore) and report to the user.

Step 6 — Commit + history

git add -A
git commit -m "refactor: promote  from  to "

Append to meta.json#history:

{
  "skill": "promote-component",
  "ran_at": "",
  "inputs": {"component": "PostCard", "from": "L0 (3 sites)", "to": "L2", "domain": "post"},
  "outputs": {"new_path": "components/shared/post/PostCard.tsx", "imports_updated": 3}
}

Common anti-patterns (NEVER do)

  • ❌ Promote at the 2nd use — wait the 3rd. The premature abstraction is more expensive than the duplicate.
  • ❌ Move without rewriting imports — broken project.
  • ❌ Promote a compound component piece by piece — the whole compound moves together, always.
  • ❌ Use generic domain names (shared/common/, shared/misc/) — use the business domain.
  • ❌ Promote across route groups WITHOUT going to L2 — if 2+ groups use it, it MUST live in components/shared/.
  • ❌ Skip the tsc verification — silent broken imports propagate.

Updating meta.json (recommended pattern)

python3 .../dev-flow/scripts/update_meta.py  append-history \
    --skill 'promote-component' --inputs '{"component": ""}' --outputs '{"new_path": ""}'

Sources

  • Spec: docs/superpowers/specs/2026-06-06-folder-structure-refactor.md
  • Sandi Metz, "The Wrong Abstraction" (2016): https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction
  • "Rule of Three" pattern: documented in "The Pragmatic Programmer" + multiple refactoring books.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.