/architecture-frontend
Check for frontend architecture pattern violations
$ npx -y skills add dcouple/Pane --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/architecture-frontend
Context preview
What this command does when you run it.
Check for frontend architecture pattern violations
Command definition
architecture-frontend.mdallowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git show:*), Bash(git rev-parse:*), Bash(git branch:*), Read, Grep, Glob, TodoWrite
description: Check for frontend architecture pattern violations
/review:architecture-frontend - Frontend Architecture Checker
You are reviewing code changes for violations of **frontend architecture patterns**.
The Principles
Thin Pages + Orchestration Hooks
Pages should be JSX composition only. All business logic, state management, and event handlers live in orchestration hooks (e.g., `usePageName`).
Underscore-Prefix Locality
- `_components/` - Components used only by this page/feature
- `_hooks/` - Hooks used only by this page/feature
- `_types/` - Types used only by this page/feature
- `_providers/` - Providers used only by this page/feature
- `_utils/` - Utilities used only by this page/feature
**Shared code (2+ features) goes in `src/components/`, `src/hooks/`, etc.**
TanStack Query Patterns
- Query keys must include ALL dependencies
- Mutations must invalidate related queries on success
- Use `enabled` option for conditional queries
- Never call hooks conditionally
Hooks Never Return JSX
Hooks return data and functions only. Components render JSX.
Phase 1: Gather Context
# Get current branch
git rev-parse --abbrev-ref HEAD
# Get changed files (frontend only)
git diff main...HEAD --name-only | grep "apps/webapp"
# Get full diff for frontend
git diff main...HEAD -- "apps/webapp/"
Read the frontend patterns:
- `apps/webapp/CLAUDE.md` - Complete frontend architecture
- `apps/webapp/src/hooks/CLAUDE.md` - Hook patterns, TanStack Query
- `apps/webapp/src/components/CLAUDE.md` - Component patterns
- `CLAUDE.md` - Import conventions
Phase 2: Check Frontend Patterns
2.1 Page Pattern
For each page file (`page.tsx`) changed:
**Check for thin composition:**
// CORRECT - Thin page
'use client';
export default function FeedPage() {
const { items, isLoading, handleRefresh } = useFeedPage();
if (isLoading) return <LoadingSpinner />;
return (
<PageLayout>
<FeedList items={items} onRefresh={handleRefresh} />
</PageLayout>
);
}
// WRONG - Fat page with logic
'use client';
export default function FeedPage() {
const [items, setItems] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetch('/api/feed')
.then(res => res.json())
.then(data => {
setItems(data);
setIsLoading(false);
});
}, []);
const handleRefresh = async () => {
// 20 lines of logic...
};
return <div>...</div>;
}**Check for 'use client' directive:**
- Most interactive pages need it
- Flag if missing when using hooks/state
**Study exemplar:** `apps/webapp/src/app/(protected)/workspaces/[workspaceId]/feed/page.tsx`
2.2 Orchestration Hook Pattern
For orchestration hooks (`usePage.ts`, `useFeature.ts`):
**Check for proper structure:**
// CORRECT
export function useFeedPage() {
// 1. Data hooks
const { data: items, isLoading } = useFeed();
// 2. State
const [filter, setFilter] = useState('all');
// 3. Mutations
const { mutate: refreshFeed } = useRefreshFeed();
// 4. Handlers
const handleRefresh = useCallback(() => {
refreshFeed();
}, [refreshFeed]);
// 5. Return object (NEVER JSX)
return {
items,
isLoading,
filter,
setFilter,
handleRefresh,
};
}
// WRONG - Returns JSX
export function useFeedPage() {
// ...
return <div>This is wrong</div>;
}**Study exemplar:** `apps/webapp/src/app/(protected)/workspaces/[workspaceId]/archive/useArchivePage.ts`
2.3 Underscore-Prefix Locality
**Check file locations:**
app/workspaces/[id]/feed/
page.tsx
_components/ # Local to feed page
FeedList.tsx
FeedItem.tsx
_hooks/ # Local to feed page
useFeedPage.ts
src/components/ # Shared across features
Button.tsx
Modal.tsx
src/hooks/ # Shared across features
useFeed.ts**Flag violations:**
- Shared component in `_components/` (used by 2+ features)
- Local component in `src/components/` (used by only 1 feature)
- Underscore folders in `src/` directory
2.4 TanStack Query Patterns
**Check query keys:**
// CORRECT - All dependencies in key
const { data } = useQuery({
queryKey: ['feed', workspaceId, filter],
queryFn: () => fetchFeed(workspaceId, filter),
});
// WRONG - Missing dependency
const { data } = useQuery({
queryKey: ['feed'],
queryFn: () => fetchFeed(workspaceId, filter),
});**Check mutation invalidation:**
// CORRECT - Invalidates related queries
const { mutate } = useMutation({
mutationFn: createItem,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['feed'] });
},
});
// WRONG - No invalidation
const { mutate } = useMutation({
mutationFn: createItem,
});**Check conditional queries:**
// CORRECT - Use enabled option
const { data } = useQuery({
queryKey: ['item', itemId],
queryFn: () => fetchItem(itemId),
enabled: !!itemId,
});
// WRONG - Conditional hook call
if (itemId) {
const { data } = useQuery(...);
}2.5 Hook Return Values
**Check that hooks never return JSX:**
// CORRECT
export function useModal() {
const [isOpen, setIsOpen] = useState(false);
return { isOpen, open: () => setIsOpen(true), close: () => setIsOpen(false) };
}
// WRONG
export function useModal() {
const [isOpen, setIsOpen] = useState(false);
return isOpen ? <Modal /> : null; // Never do this
}Phase 3: Generate Report
# Frontend Architecture Report
**Branch:** {branch}
**Status:** {PASS | WARN | FAIL}
## Summary
{One sentence assessment of frontend architecture compliance}
## Patterns Checked
- [x] Thin pages (JSX only)
- [x] Orchestration hooks
- [x] Underscore-prefix locality
- [x] TanStack Query patterns
- [x] Hooks return dRead more
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git show:*), Bash(git rev-parse:*), Bash(git branch:*), Read, Grep, Glob, TodoWrite description: Check for frontend architecture pattern violations
/review:architecture-frontend - Frontend Architecture Checker
You are reviewing code changes for violations of **frontend architecture patterns**.
The Principles
Thin Pages + Orchestration Hooks
Pages should be JSX composition only. All business logic, state management, and event handlers live in orchestration hooks (e.g., `usePageName`).
Underscore-Prefix Locality
- `_components/` - Components used only by this page/feature
- `_hooks/` - Hooks used only by this page/feature
- `_types/` - Types used only by this page/feature
- `_providers/` - Providers used only by this page/feature
- `_utils/` - Utilities used only by this page/feature
**Shared code (2+ features) goes in `src/components/`, `src/hooks/`, etc.**
TanStack Query Patterns
- Query keys must include ALL dependencies
- Mutations must invalidate related queries on success
- Use `enabled` option for conditional queries
- Never call hooks conditionally
Hooks Never Return JSX
Hooks return data and functions only. Components render JSX.
Phase 1: Gather Context
# Get current branch git rev-parse --abbrev-ref HEAD # Get changed files (frontend only) git diff main...HEAD --name-only | grep "apps/webapp" # Get full diff for frontend git diff main...HEAD -- "apps/webapp/"
Read the frontend patterns:
- `apps/webapp/CLAUDE.md` - Complete frontend architecture
- `apps/webapp/src/hooks/CLAUDE.md` - Hook patterns, TanStack Query
- `apps/webapp/src/components/CLAUDE.md` - Component patterns
- `CLAUDE.md` - Import conventions
Phase 2: Check Frontend Patterns
2.1 Page Pattern
For each page file (`page.tsx`) changed:
**Check for thin composition:**
// CORRECT - Thin page
'use client';
export default function FeedPage() {
const { items, isLoading, handleRefresh } = useFeedPage();
if (isLoading) return <LoadingSpinner />;
return (
<PageLayout>
<FeedList items={items} onRefresh={handleRefresh} />
</PageLayout>
);
}
// WRONG - Fat page with logic
'use client';
export default function FeedPage() {
const [items, setItems] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetch('/api/feed')
.then(res => res.json())
.then(data => {
setItems(data);
setIsLoading(false);
});
}, []);
const handleRefresh = async () => {
// 20 lines of logic...
};
return <div>...</div>;
}**Check for 'use client' directive:**
- Most interactive pages need it
- Flag if missing when using hooks/state
**Study exemplar:** `apps/webapp/src/app/(protected)/workspaces/[workspaceId]/feed/page.tsx`
2.2 Orchestration Hook Pattern
For orchestration hooks (`usePage.ts`, `useFeature.ts`):
**Check for proper structure:**
// CORRECT
export function useFeedPage() {
// 1. Data hooks
const { data: items, isLoading } = useFeed();
// 2. State
const [filter, setFilter] = useState('all');
// 3. Mutations
const { mutate: refreshFeed } = useRefreshFeed();
// 4. Handlers
const handleRefresh = useCallback(() => {
refreshFeed();
}, [refreshFeed]);
// 5. Return object (NEVER JSX)
return {
items,
isLoading,
filter,
setFilter,
handleRefresh,
};
}
// WRONG - Returns JSX
export function useFeedPage() {
// ...
return <div>This is wrong</div>;
}**Study exemplar:** `apps/webapp/src/app/(protected)/workspaces/[workspaceId]/archive/useArchivePage.ts`
2.3 Underscore-Prefix Locality
**Check file locations:**
app/workspaces/[id]/feed/
page.tsx
_components/ # Local to feed page
FeedList.tsx
FeedItem.tsx
_hooks/ # Local to feed page
useFeedPage.ts
src/components/ # Shared across features
Button.tsx
Modal.tsx
src/hooks/ # Shared across features
useFeed.ts**Flag violations:**
- Shared component in `_components/` (used by 2+ features)
- Local component in `src/components/` (used by only 1 feature)
- Underscore folders in `src/` directory
2.4 TanStack Query Patterns
**Check query keys:**
// CORRECT - All dependencies in key
const { data } = useQuery({
queryKey: ['feed', workspaceId, filter],
queryFn: () => fetchFeed(workspaceId, filter),
});
// WRONG - Missing dependency
const { data } = useQuery({
queryKey: ['feed'],
queryFn: () => fetchFeed(workspaceId, filter),
});**Check mutation invalidation:**
// CORRECT - Invalidates related queries
const { mutate } = useMutation({
mutationFn: createItem,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['feed'] });
},
});
// WRONG - No invalidation
const { mutate } = useMutation({
mutationFn: createItem,
});**Check conditional queries:**
// CORRECT - Use enabled option
const { data } = useQuery({
queryKey: ['item', itemId],
queryFn: () => fetchItem(itemId),
enabled: !!itemId,
});
// WRONG - Conditional hook call
if (itemId) {
const { data } = useQuery(...);
}2.5 Hook Return Values
**Check that hooks never return JSX:**
// CORRECT
export function useModal() {
const [isOpen, setIsOpen] = useState(false);
return { isOpen, open: () => setIsOpen(true), close: () => setIsOpen(false) };
}
// WRONG
export function useModal() {
const [isOpen, setIsOpen] = useState(false);
return isOpen ? <Modal /> : null; // Never do this
}Phase 3: Generate Report
# Frontend Architecture Report
**Branch:** {branch}
**Status:** {PASS | WARN | FAIL}
## Summary
{One sentence assessment of frontend architecture compliance}
## Patterns Checked
- [x] Thin pages (JSX only)
- [x] Orchestration hooks
- [x] Underscore-prefix locality
- [x] TanStack Query patterns
- [x] Hooks return dRepo: dcouple/Pane
Other commands on pane.
- /commit
Create git commits with user approval and no Claude attribution
Open command - /create_plan
You are tasked with creating detailed implementation plans through an interactive, iterative process. You should be skeptical, thorough, and work collaboratively with the user to produce high-quality technical specifications.
Open command - /describe_pr
Generate comprehensive PR descriptions following repository templates
Open command - /implement_plan
You are tasked with implementing an approved technical plan from `thoughts/shared/plans/`. These plans contain phases with specific changes and success criteria.
Open command - /iterate_plan
Iterate on existing implementation plans with thorough research and updates
Open command - /research_codebase
You are tasked with conducting comprehensive research across the codebase to answer user questions. You will spawn one or more parallel sub-agents to perform your reserach.
Open command

