Most developers treat AI coding tools like a smarter autocomplete. You type a comment, you get a suggestion, you hit tab to accept. Honestly, that's maybe 10% of what these tools are actually capable of.
For the last several months I've been building a workflow around Claude Code that goes a lot deeper than autocomplete. It's a mix of three things: a custom project config that teaches Claude my team's architecture patterns, custom slash commands that handle multi-step engineering workflows, and MCP integrations that wire Claude into the infrastructure we already use every day.
The payoff has been real. Scaffolding a new feature with the right folder structure, Zod schemas, API routes, hooks, and tests used to eat up about two hours of my day. Now it takes roughly five minutes, and it follows our conventions every single time.
How the pieces fit together:
┌───────────┐
│ Developer │
└─────┬─────┘
│ natural language
▼
┌──────────────┐
│ Claude Code │
└──────┬───────┘
│
├─ reads ─────► CLAUDE.md (architecture rules)
├─ runs ──────► Slash Commands (scaffold, audit, review)
└─ connects ──► MCP Servers (Figma, Slack, GitHub)
│
▼
┌───────────────────┐
│ Generated Code │ ◄─ all three feed in here,
│ │ following team conventions
└───────────────────┘
Here's exactly how I set it up.
CLAUDE.md: Teaching Claude Your Architecture
Every project I work on gets a CLAUDE.md file at the root. I think of it as documentation that both humans and AI will actually read. When Claude Code starts a session it loads this file and treats it as instructions for how to behave inside your codebase.
This is a simplified version of the one I use:
# Project: Analytics Dashboard
## Architecture Overview
- Next.js 15 App Router with TypeScript strict mode
- BFF pattern: API routes orchestrate backend services
- Zod schemas define all I/O boundaries
- React Query for server state, Zustand for client state
- TailwindCSS for styling, no CSS-in-JS
## Folder Structure Convention
src/
├── app/ # Next.js routes and API handlers
├── components/
│ ├── ui/ # Reusable primitives (Button, Card, Skeleton)
│ └── features/ # Feature-specific components
├── hooks/ # Custom React hooks
├── lib/ # Utilities, formatters, validators
├── types/ # Zod schemas + inferred TypeScript types
└── data/ # Mock data and seed generators
## Rules
- NEVER use `as` type assertions for API responses, always use Zod.parse
- NEVER put server data in Zustand, use React Query
- ALL new API routes must validate with Zod before returning data
- Feature components must NOT import from other feature folders
- Use dynamic imports for heavy chart libraries (Highcharts)
## Naming Conventions
- Components: PascalCase (MetricCard.tsx)
- Hooks: camelCase with 'use' prefix (useRealtimeMetrics.ts)
- Types: PascalCase, co-located with Zod schemas
- API routes: kebab-case folders (api/analytics/route.ts)
## Tech Stack Details
- Highcharts 12.x (auto-init ESM, no manual module registration)
- Zod 3.x (use .issues not .errors for error access)
- React Query v5 (TanStack Query)
It looks like ordinary documentation, but the effect is bigger than you'd expect. One command reads it and produces a whole feature:
┌──────────────────────────┐
│ You type: │
│ /scaffold-feature │
│ user-retention │
└──────────────┬───────────┘
│ reads config
▼
┌──────────────────────────┐
│ Claude reads CLAUDE.md │
└──────────────┬───────────┘
│ generates
├──────────► types/retention.ts (Zod schemas)
├──────────► api/retention/route.ts (BFF + Zod)
├──────────► hooks/useRetention.ts (React Query)
└──────────► components/features/retention/ (UI + Skeleton)
When I tell Claude "scaffold a new analytics feature for user retention," here's what comes back:
- The correct folder structure under
components/features/retention/ - Zod schemas in
types/retention.tswith proper inferred types - A React Query hook in
hooks/useRetentionData.tswith Zod parsing in the queryFn - An API route in
app/api/retention/route.tswith Zod validation - Components with dynamic chart imports and skeleton loaders
All of it follows our conventions, and I don't have to go back and fix anything by hand. To me that's the line between "AI that writes code" and "AI that writes code the way your team writes code."
Custom Slash Commands: Multi-Step Workflows in One Command
Slash commands are reusable prompts you trigger by typing them. Each one lives as a Markdown file in .claude/commands/, so once that folder is committed to the repo, the whole team has the same commands. I've written one for each of the workflows I repeat most often.
A quick note on naming, because it trips people up. Claude Code also has a separate feature called Skills, which Claude reaches for on its own when it spots a task that matches. The only real difference is who pulls the trigger: a Skill fires automatically when Claude decides it's relevant, while a slash command fires when you type it. For the workflows below I want explicit, on-demand control over exactly when they run, so I use slash commands. If you'd rather Claude invoke one of these on its own, the same Markdown can be packaged as a Skill instead.
Command: Scaffold a New Feature
# /scaffold-feature
When the user says "scaffold [feature-name]", create the following:
1. Types file: `src/types/[feature-name].ts`
- Define Zod schemas for the API response
- Export inferred TypeScript types
- Include a response schema with discriminated union (success/error)
2. API route: `src/app/api/[feature-name]/route.ts`
- GET handler that returns mock data
- Zod validation before response
- Proper error handling with typed error responses
3. React Query hook: `src/hooks/use[FeatureName].ts`
- queryFn that fetches from the API route
- Zod parsing in the queryFn (validate before caching)
- Proper queryKey hierarchy: ['[feature-name]', ...params]
4. Component: `src/components/features/[feature-name]/[FeatureName].tsx`
- Client component using the hook
- Loading skeleton while data loads
- Error state handling
5. Barrel export: `src/components/features/[feature-name]/index.ts`
Follow all conventions from CLAUDE.md. Use existing UI components from
src/components/ui/ where applicable.
So when I type /scaffold-feature user-retention, Claude generates five files that are architecturally correct, use the right patterns, and match our naming. There's no copy-pasting from a sibling feature, and nobody forgets the Zod validation along the way.
Command: Performance Audit
# /perf-audit
Analyze the current page/component for performance issues:
1. Check for missing dynamic imports on heavy dependencies
2. Look for components that should be wrapped in React.memo
3. Identify React Query hooks missing staleTime configuration
4. Find Highcharts options not wrapped in useMemo
5. Check for layout components that cause unnecessary re-renders
6. Verify error boundaries exist at route level
7. Check for proper Suspense boundaries around lazy components
Report findings as a checklist with file paths and specific fixes.
Command: Pre-PR Review
# /pre-review
Before I create a PR, review my changes for:
1. Architecture violations:
- Server data in Zustand instead of React Query
- Cross-feature imports (feature A importing from feature B internals)
- `as` type assertions on API responses (should use Zod)
- Business logic in components (should be in hooks or utils)
2. Performance issues:
- Missing lazy loading for heavy components
- Missing memoization on expensive computations
- React Query hooks without staleTime
- Unnecessary re-renders from unstable references
3. Convention violations:
- File naming doesn't match conventions
- Missing Zod schemas for new API routes
- Missing error boundaries for new routes
- Missing loading states
Flag each issue with severity: [BLOCK] must fix, [WARN] should fix, [NOTE] nice to fix.
This catches the kinds of things a linter never will: architectural drift, state management tiers getting crossed, and conventions slowly slipping over time.
Project Initialization: The Full Setup
When I kick off a brand new project, I have a command that stands up the entire development environment for me:
# /init-project
Initialize a new Next.js project with the team's standard setup:
1. Create Next.js app with: TypeScript, TailwindCSS, ESLint, App Router, src/ directory
2. Install dependencies: zod, @tanstack/react-query, zustand, highcharts, highcharts-react-official
3. Create folder structure matching CLAUDE.md conventions
4. Set up path aliases in tsconfig.json
5. Create base Zod utility: src/lib/validate.ts (validateResponse function)
6. Create base formatting utils: src/lib/format.ts
7. Create Skeleton components: src/components/ui/Skeleton.tsx
8. Create QueryProvider wrapper: src/providers/QueryProvider.tsx
9. Set up ESLint import rules for feature boundaries
10. Create CLAUDE.md with the standard project config
11. Verify the build passes
The result should be a clean, building project with all conventions baked in from the start.
Rather than burning 30 minutes on boilerplate every time, I run one command and end up with a project that's already wired with our architecture patterns, validation utilities, and folder conventions.
MCP Servers: Connecting Claude to Your Infrastructure
MCP (Model Context Protocol) servers let Claude reach out to external tools. The three I lean on most:
Figma MCP. Claude can read design specs straight out of Figma files. When I'm building a new component, I point it at the Figma node and it produces code that matches the design while reusing our existing UI components.
Slack MCP. Claude can pull in channel messages for context. If a bug got reported in a Slack thread, I hand Claude the thread and it picks up the report, the back-and-forth discussion, and whatever related context is buried in there.
GitHub MCP. Claude can read PRs, issues, and reviews. Before it starts writing, it can scan related issues and earlier PRs to understand what's already been tried.
The underlying idea is simple. Pretty much every tool your team touches daily can become context for Claude, and the more context it has, the closer its output lands to how your team actually works.
How This Changes Daily Development
Here's what a typical feature session looks like for me now:
Me: /scaffold-feature user-retention
Claude: [creates 5 files with correct types, API route, hook, component, barrel export]
Me: The retention chart should show weekly cohorts with drilldown by acquisition channel
Claude: [updates the component with Highcharts config, adds drilldown series,
uses dynamic import, wraps options in useMemo, adds skeleton loader]
Me: /pre-review
Claude: [reviews all changes]
- [NOTE] Consider adding staleTime: 60000 to useRetentionData,
retention data doesn't change every second
- [WARN] Missing error boundary in the retention route, add error.tsx
- All other checks pass
Me: [fixes the two items, creates PR]
That's about 15 minutes for a feature that used to cost me two-plus hours of scaffolding, wiring, and manual review.
What This Means for Senior Engineers
AI-augmented development doesn't replace architectural thinking. If anything it leans on it harder.
A senior engineer's job is still to make the calls that matter: which patterns to reach for, where to draw boundaries, which tradeoffs are worth it. AI just speeds up the execution of those calls once you've made them.
That's why I'd argue the commands you build are basically your architectural judgment written down. A scaffolding command captures your architecture decisions. A pre-review command captures your code review standards. A CLAUDE.md file captures your team's conventions.
And that's where the leverage actually lives. You make a decision once, encode it as a command or a config, and from then on it applies consistently to every feature. No more "the senior never got around to reviewing that PR" or "the new dev didn't realize we use Zod for API responses."
Getting Started
If you want to give this a shot, here's the order I'd recommend:
Start with CLAUDE.md. Write up your project's architecture overview, your folder conventions, and your non-negotiable rules. This step alone makes Claude noticeably more useful.
Pick your three most repetitive workflows. The ones you find yourself doing every week. Write a command for each of those first.
Keep each command focused. One command, one workflow. Resist the urge to build a single mega-command that tries to do everything. Small, composable commands that each do one thing well will serve you better.
Iterate. Your first CLAUDE.md is going to have gaps. Every time Claude produces something that misses your conventions, go update the config. It compounds over time.
Share it with your team. CLAUDE.md and your commands live in the repo, so everyone gets the same conventions and the same workflows for free.
The engineers who'll get the most out of the next few years aren't the ones who type the fastest. They're the ones who can teach these tools their standards and scale their own judgment across the whole codebase.
Start with the CLAUDE.md. The rest tends to follow on its own.
Top comments (0)