Workshop: AI-Assisted Development with Claude Code Agents¶
Goal: Learn how to use Claude Code agents to implement your assigned development tasks efficiently and with high quality.
Workshop Duration: 3 hours hands-on
Environment: This workshop uses Claude Code (CLI/VS Code extension), not Claude Desktop. All instructions assume you're using Claude Code in your terminal or IDE.
What You Have: Development tasks in documents/03-dev-tasks/ with detailed requirements, acceptance criteria, and technical notes.
What You'll Learn: How to translate those task cards into production-ready code using AI agents, Playwright MCP for testing, and useful MCP servers for enhanced development.
Prerequisites and Setup¶
Before starting this workshop, complete these setup steps.
1. Required Software¶
Ensure you have the following installed:
- Node.js 20+ - Download
- Git - Download
- Claude Code CLI or Claude Code VS Code Extension - Installation Guide
Verify installations:
2. Project Setup¶
Clone and setup the project:
# Navigate to your project directory
cd /path/to/your/project
# Install dependencies
npm install
# Install Playwright browsers
npx playwright install
3. Configure MCP Servers¶
MCP (Model Context Protocol) servers enhance Claude Code with additional capabilities.
Configuration Scopes: Claude Code supports three configuration scopes:
- Local (default): Private to you within the current project (
.claude/mcp.json) - Project: Shared with team via
.mcp.jsonin project root - User: Available across all your projects
For this workshop, we'll use Local scope (default) for security best practices. This keeps your API keys and tokens private and prevents accidentally committing sensitive credentials to the repository.
Method 1: Using CLI Commands (Recommended)¶
Add MCP servers using the claude mcp add command (uses local scope by default):
# Add Playwright MCP
claude mcp add playwright npx '@playwright/mcp@latest'
# Add Context7 MCP (for latest library docs)
claude mcp add --transport stdio context7 -- npx -y @context7/mcp-server
# Add GitHub MCP (requires personal access token)
claude mcp add --transport stdio github -- npx -y @modelcontextprotocol/server-github
This creates a .claude/mcp.json file in your project (local scope, private to you).
Method 2: Manual Configuration (Alternative)¶
Create or update .claude/mcp.json in your project (local scope):
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
},
"context7": {
"command": "npx",
"args": ["-y", "@context7/mcp-server"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "your_github_token_here"
}
}
}
}
Note: .claude/ directory is automatically ignored by git, keeping your tokens safe.
Note: Restart Claude Code after configuration changes.
MCP Servers Explained:
-
Playwright MCP
- Interactive browser testing and debugging
- Take screenshots
- Click elements
- Fill forms
- Check console errors
- Monitor network requests
-
Context7 MCP
- Access up-to-date library documentation
- Get latest Next.js docs
- Query React documentation
- Access framework guides
- Find API references
-
GitHub MCP
- Interact with GitHub repositories
- Create issues
- Search code
- List pull requests
- Get repository information
4. Setup GitHub Token (Optional but Recommended)¶
To use GitHub MCP, each developer must create their own personal access token.
Important: DO NOT share tokens between team members!
Why each developer needs their own token:
- Commits and actions are attributed to the correct person
- Audit trail shows who made which changes
- Individual token revocation without affecting the team
- GitHub tracks rate limits per token
- Security best practice (tokens are like passwords)
Create Your Personal Token:
- Go to GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
- Click "Generate new token (classic)"
- Give it a descriptive name: "Claude Code - [Your Name]"
- Select scopes:
repo,read:org,read:user - Set expiration: 90 days (recommended for security)
- Click "Generate token"
- Copy the token immediately (you won't see it again!)
Add Token to Your Configuration:
Option 1: Environment Variable (Recommended for security)
Add to your shell profile (~/.zshrc or ~/.bashrc):
Reload your shell:
The GitHub MCP server will automatically read the token from the environment variable.
Option 2: In Local .claude/mcp.json (Token in file - still secure)
Add to .claude/mcp.json:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "your_personal_token_here"
}
}
}
}
Security: The .claude/ directory is automatically ignored by git, so your tokens are safe and won't be accidentally committed.
5. Verify Setup¶
Check that everything is working:
# Start dev server
npm run dev
# In another terminal, verify Docker is running
docker ps
# In Claude Code, verify MCP servers are loaded
# Ask: "What MCP tools do I have access to?"
# You should see: browser tools, context7 docs, github tools
6. Access Your Development Tasks¶
Your tasks are located in:
documents/03-dev-tasks/
├── login-authentication-dev-tasks.md
├── dashboard-dev-tasks.md
├── documents-dev-tasks.md
├── messages-contact-dev-tasks.md
├── payments-dev-tasks.md
├── property-milestones-dev-tasks.md
└── ... (more task files)
Each file contains:
- Task summary table
- Detailed task cards with:
- User stories
- Descriptions
- Acceptance criteria
- Technical notes
- Dependencies
Your Daily Workflow (Simple 6-Step Process)¶
flowchart LR
A[1. Pick Task] --> B[2. Code]
B --> C[3. Test]
C --> D[4. Quality Check]
D --> E[5. Update Task]
E --> F[6. Commit]
style A fill:#4a90e2,stroke:#333,stroke-width:2px,color:#fff
style B fill:#7cb342,stroke:#333,stroke-width:2px,color:#fff
style C fill:#ffa726,stroke:#333,stroke-width:2px,color:#fff
style D fill:#ab47bc,stroke:#333,stroke-width:2px,color:#fff
style E fill:#29b6f6,stroke:#333,stroke-width:2px,color:#fff
style F fill:#66bb6a,stroke:#333,stroke-width:2px,color:#fff
Step 1: Pick Your Task (2 min)¶
Open your task file and find your assigned task:
# Example: You're assigned TASK-012 from login-authentication-dev-tasks.md
open documents/03-dev-tasks/login-authentication-dev-tasks.md
Step 2: Code It (Main work)¶
Use the right agent based on what the task needs.
Pro Tip: Use Context7 MCP for Latest Documentation
When you need up-to-date information about libraries or frameworks:
# Example: Need to know latest Next.js 15 Server Actions patterns
Use Context7 MCP to get latest Next.js Server Actions documentation
Question: What are the best practices for Server Actions in Next.js 15?
# Example: React 19 features
Use Context7 MCP to get React 19 documentation
Question: How to use the new useOptimistic hook in React 19?
# Example: Prisma latest features
Use Context7 MCP to get Prisma documentation
Question: What's the syntax for Prisma 5 JSON filtering?
Context7 MCP provides current documentation, eliminating outdated Stack Overflow answers.
Step 3: Test It (After coding)¶
Write tests for what you built
Step 4: Quality Check (Before commit)¶
Run code review, security, and performance checks
Step 5: Update Task (Mark complete)¶
Ask Claude Code to mark the task as completed in the dev-tasks file
Step 6: Commit (Final)¶
Commit with clear message referencing the task
Step 2: Code It - Which Agent to Use?¶
Look at your task's Role and Description to pick the right agent:
Quick Agent Selection Table¶
| Your Task Involves | Use This Agent | Example Prompt |
|---|---|---|
| Database schema, migrations | database |
Use database to implement TASK-002 |
| API endpoints, Server Actions, tRPC | backend-api |
Use backend-api to implement TASK-011 |
| UI components, forms, buttons | frontend-ui |
Use frontend-ui to implement TASK-012 |
| Next.js pages, layouts, routing | fullstack-nextjs |
Use fullstack-nextjs to implement TASK-023 |
| Complete feature (DB + API + UI) | /workflow-implement-fullstack |
/workflow-implement-fullstack then paste task |
| Authentication, security | security + backend-api |
Chain: security design → backend-api implement |
| Performance optimization | performance |
Use performance to implement TASK-044 |
Real Examples from Your Tasks¶
Example 1: Database Task (TASK-002)¶
Your Task Card Says:
TASK-002: Create Prisma schema for authentication
Role: Backend
Description: Design and implement Prisma schema with User, Account, Session models...
Acceptance Criteria:
- User model created with email, password, firstName, lastName
- Account model for OAuth provider data
- Proper indexes and relationships
What You Do:
First, use Context7 MCP to get latest Prisma and NextAuth.js patterns:
Use Context7 MCP to get latest Prisma and NextAuth.js documentation
Questions:
1. What's the recommended Prisma schema structure for NextAuth.js v5?
2. What are the latest Prisma indexing best practices for performance?
3. How to set up Prisma with NextAuth.js adapter in Next.js 15?
Then, implement with the database agent:
Use database to implement TASK-002 from documents/03-dev-tasks/login-authentication-dev-tasks.md
Based on latest documentation from Context7 MCP, create Prisma schema with these models:
1. User (email, password, firstName, lastName, profilePhoto, role)
2. Account (for OAuth - Google, Facebook)
3. Session (NextAuth.js session management)
4. VerificationToken (magic link authentication)
5. ActivationToken (account activation)
Include:
- Indexes on email fields and foreign keys (use latest Prisma indexing syntax)
- Unique constraints on email
- UserRole enum (BUYER, ADMIN, SUPPORT)
- Timestamps (createdAt, updatedAt)
- Prisma Adapter compatibility for NextAuth.js v5 (use latest adapter patterns)
Agent Response: Creates complete Prisma schema file with all models using latest best practices
Why Use Context7 MCP First?
- Ensures you're using latest Prisma 5 syntax
- Gets current NextAuth.js v5 adapter patterns
- Avoids deprecated methods
- Uses latest performance optimizations
Example 2: UI Component Task (TASK-012)¶
Your Task Card Says:
TASK-012: Build login page UI with email input
Role: Fullstack
Description: Create login page with email input form, loading states, OAuth buttons...
Dependencies: TASK-011 (email login server action must be done first)
Acceptance Criteria:
- Email input with validation
- Submit button with loading state
- Google and Facebook OAuth buttons
- Error message display
- Success message "Check your email"
What You Do:
First, check latest patterns with Context7 MCP:
Use Context7 MCP to get latest React and Next.js documentation
Questions:
1. What are the latest React 19 form handling patterns with useFormState?
2. How to properly implement Client Components with Server Actions in Next.js 15?
3. What are the current shadcn/ui form component best practices?
Then, implement with the frontend-ui agent:
Use frontend-ui to implement TASK-012 from documents/03-dev-tasks/login-authentication-dev-tasks.md
Create login page UI with:
1. Email input form with Zod validation
2. Submit button with loading spinner
3. OAuth buttons for Google and Facebook
4. Error message area (rate limit, invalid email)
5. Success message: "Check your email for magic link"
Technical requirements (based on latest Context7 MCP documentation):
- Use shadcn/ui components (Card, Input, Button) with latest patterns
- Client Component with React 19 useFormState hook
- Integrate with TASK-011 server action (already implemented)
- Responsive design (mobile and desktop)
- Accessibility (ARIA labels, keyboard navigation, announcements)
Agent Response: Creates login page component with all requirements using latest React 19 patterns
Context7 MCP Advantage:
- Gets latest React 19 hook usage (useFormState, useOptimistic)
- Current Next.js 15 Server Action integration patterns
- Latest shadcn/ui component APIs
- Up-to-date accessibility guidelines
Example 3: API/Backend Task (TASK-021)¶
Your Task Card Says:
TASK-021: Create getDashboardData server action
Role: Backend
Description: Create server action that fetches dashboard data from multiple sources...
Dependencies: TASK-013,TASK-014,TASK-015,TASK-016 (repositories must exist)
Acceptance Criteria:
- Fetch user profile data
- Fetch properties from SAP
- Fetch notifications from Salesforce
- Fetch messages
- Return aggregated dashboard data
What You Do:
Use backend-api to implement TASK-021 from documents/03-dev-tasks/dashboard-dev-tasks.md
Create getDashboardData server action that:
1. Fetches authenticated user profile
2. Queries properties from Property repository (SAP mock)
3. Queries notifications from Notification repository (Salesforce mock)
4. Queries messages from Message repository
5. Returns aggregated data for dashboard
Dependencies (already implemented):
- User repository (TASK-013)
- Property repository (TASK-014)
- Notification repository (TASK-015)
- Message repository (TASK-016)
Return type:
{
user: User,
properties: Property[],
notifications: Notification[],
messages: Message[]
}
Include error handling and proper TypeScript types.
Agent Response: Creates server action with all data fetching logic
Step 3: Test It¶
After coding, immediately write tests. Your task card often includes testing requirements.
Testing Tasks¶
Look for tasks like:
- TASK-037: Create unit tests for authentication services
- TASK-039: Implement E2E tests for login flows
- TASK-046: Write unit tests for repositories and use cases
Quick Testing Guide¶
For Unit Tests:
Use qa-tester to write unit tests for TASK-011
Test cases from acceptance criteria:
- Valid email creates verification token
- Invalid email returns error
- Rate limit enforced (3 attempts per 15 min)
- Token expires after 15 minutes
- Email is sent with correct magic link
For E2E Tests with Playwright:
Use qa-tester to write Playwright E2E tests for TASK-012
User flow to test:
1. Navigate to /login
2. Enter valid email
3. Click submit
4. See loading state
5. See success message "Check your email"
6. Try 4th attempt - see rate limit error
7. Try invalid email - see validation error
Use Comprehensive Testing Workflow:
/workflow-qa-e2e
Feature to test: Login flow (TASK-012 + TASK-011)
Include: Unit tests, integration tests, Playwright E2E tests
Playwright & Playwright MCP Integration¶
Playwright is our E2E testing framework. Playwright MCP allows Claude Code to interact with your browser for testing and debugging.
Note: This guide is for Claude Code (CLI/VS Code extension), not Claude Desktop. Playwright MCP is available as an npm package that can be easily added to Claude Code.
Setup Playwright (One-time)¶
Install Playwright:
Create Playwright config:
Configure for Next.js:
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
});
Setup Playwright MCP (One-time)¶
Playwright MCP allows Claude Code to control your browser for testing and debugging.
Note: Playwright MCP can be easily added to Claude Code using the claude mcp add command. The browser automation tools will be available through the mcp__playwright__browser_* functions.
Verify Playwright MCP is available:
# In Claude Code, check if browser tools are available by asking:
# "Do I have access to Playwright MCP browser tools?"
# You should see mcp__playwright__browser_navigate, browser_click, etc.
If Playwright MCP is not available, configure it using one of these methods:
Using CLI (Recommended):
Or manually add to .mcp.json in your project root:
Restart required - Restart Claude Code after configuration changes.
Troubleshooting:
- If browser tools aren't available, restart Claude Code after adding the MCP server
- Make sure you have Node.js installed (npx requires Node.js)
- You can verify the installation by checking available MCP tools in Claude Code
- If you encounter issues, you can still write Playwright tests manually - just won't have interactive MCP testing
Writing E2E Tests with Playwright¶
Method 1: Let Agent Write Tests (Recommended)¶
For simple flows:
Use qa-tester to write Playwright E2E test for login flow (TASK-012)
Test file: tests/e2e/login.spec.ts
Test scenarios:
1. User can see login page
2. User can enter email and submit
3. Loading state shows during submission
4. Success message appears after submit
5. Error shows for invalid email format
6. Rate limit message after 3 attempts
Use Playwright best practices:
- Page Object Model
- Data-testid selectors
- Proper waits (no arbitrary timeouts)
- Clear test descriptions
Agent creates:
// tests/e2e/login.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Login Flow', () => {
test('should display login page', async ({ page }) => {
await page.goto('/login');
await expect(page.getByRole('heading', { name: 'Login' })).toBeVisible();
await expect(page.getByLabel('Email')).toBeVisible();
});
test('should submit email and show success message', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('user@example.com');
await page.getByRole('button', { name: 'Continue' }).click();
// Loading state
await expect(page.getByRole('button', { name: 'Continue' })).toBeDisabled();
// Success message
await expect(page.getByText('Check your email')).toBeVisible();
});
test('should show error for invalid email', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('invalid-email');
await page.getByRole('button', { name: 'Continue' }).click();
await expect(page.getByText('Invalid email format')).toBeVisible();
});
});
Method 2: Interactive Testing with Playwright MCP¶
Use Playwright MCP to interactively test your app and let Claude see what's happening.
Start your app:
Tell Claude Code to test using MCP:
Use Playwright MCP to test the login page at http://localhost:3000/login
Steps to perform:
1. Navigate to login page
2. Take screenshot
3. Fill email input with "test@example.com"
4. Click submit button
5. Wait for success message
6. Take screenshot of result
Report any issues found
What Claude Code can do with Playwright MCP:
- Navigate to pages (
mcp__playwright__browser_navigate) - Take screenshots (
mcp__playwright__browser_take_screenshot) - Click elements (
mcp__playwright__browser_click) - Fill forms (
mcp__playwright__browser_type) - Check element visibility (
mcp__playwright__browser_snapshot) - Get console errors (
mcp__playwright__browser_console_messages) - Monitor network requests (
mcp__playwright__browser_network_requests)
Note: Claude Code will use these MCP tools automatically when you ask it to test with Playwright MCP.
Example - Debug a failing feature:
Use Playwright MCP to debug the login form
Context: Users report the submit button doesn't work
Please:
1. Navigate to http://localhost:3000/login
2. Take screenshot of initial state
3. Fill email with "test@example.com"
4. Click submit button
5. Check console for errors
6. Check network requests
7. Take screenshot after submission
8. Report what you found
Claude will interact with the browser and report:
I found the issue:
1. Submit button is clicked successfully
2. Console shows error: "validateEmail is not defined"
3. Network request to /api/auth/signin never fires
4. Form submission is blocked by JavaScript error
The issue is in components/auth/login-form.tsx line 23.
The validateEmail function is imported but not defined.
Playwright Best Practices¶
1. Use Data-testid for Stable Selectors¶
Add to your components:
// components/auth/login-form.tsx
export function LoginForm() {
return (
<form data-testid="login-form">
<input
type="email"
data-testid="email-input"
aria-label="Email"
/>
<button data-testid="submit-button" type="submit">
Continue
</button>
<div data-testid="error-message" role="alert">
{error}
</div>
</form>
);
}
Use in tests:
await page.getByTestId('email-input').fill('test@example.com');
await page.getByTestId('submit-button').click();
await expect(page.getByTestId('error-message')).toHaveText('Invalid email');
2. Page Object Model¶
Create page objects for reusability:
// tests/e2e/pages/login.page.ts
import { Page } from '@playwright/test';
export class LoginPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto('/login');
}
async fillEmail(email: string) {
await this.page.getByTestId('email-input').fill(email);
}
async submit() {
await this.page.getByTestId('submit-button').click();
}
async expectSuccessMessage() {
await this.page.getByText('Check your email').waitFor();
}
async expectError(message: string) {
await this.page.getByTestId('error-message').waitFor();
await this.page.getByText(message).waitFor();
}
}
Use in tests:
import { LoginPage } from './pages/login.page';
test('successful login', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.fillEmail('test@example.com');
await loginPage.submit();
await loginPage.expectSuccessMessage();
});
3. Fixtures for Test Data¶
Create fixtures:
// tests/e2e/fixtures.ts
import { test as base } from '@playwright/test';
export const test = base.extend({
testUser: async ({}, use) => {
const user = {
email: 'test@example.com',
firstName: 'Test',
lastName: 'User',
};
await use(user);
},
});
Use in tests:
import { test } from './fixtures';
test('login with test user', async ({ page, testUser }) => {
await page.goto('/login');
await page.getByLabel('Email').fill(testUser.email);
// ...
});
Common Playwright Testing Patterns¶
Pattern 1: Testing Forms¶
test('contact form validation', async ({ page }) => {
await page.goto('/contact');
// Test empty submission
await page.getByTestId('submit-button').click();
await expect(page.getByText('Email is required')).toBeVisible();
// Test invalid email
await page.getByLabel('Email').fill('invalid');
await page.getByTestId('submit-button').click();
await expect(page.getByText('Invalid email format')).toBeVisible();
// Test successful submission
await page.getByLabel('Email').fill('test@example.com');
await page.getByLabel('Message').fill('Test message');
await page.getByTestId('submit-button').click();
await expect(page.getByText('Message sent successfully')).toBeVisible();
});
Pattern 2: Testing Authentication¶
test.describe('authenticated user', () => {
test.use({
storageState: 'tests/e2e/.auth/user.json', // Reuse auth state
});
test('can access dashboard', async ({ page }) => {
await page.goto('/dashboard');
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
});
Pattern 3: Testing API Interactions¶
test('dashboard loads data', async ({ page }) => {
// Mock API response
await page.route('**/api/dashboard', async (route) => {
await route.fulfill({
status: 200,
body: JSON.stringify({
user: { name: 'Test User' },
properties: [{ id: 1, name: 'Property 1' }],
}),
});
});
await page.goto('/dashboard');
await expect(page.getByText('Test User')).toBeVisible();
await expect(page.getByText('Property 1')).toBeVisible();
});
Pattern 4: Testing Responsive Design¶
test('mobile navigation', async ({ page }) => {
// Set mobile viewport
await page.setViewportSize({ width: 375, height: 667 });
await page.goto('/');
// Hamburger menu should be visible on mobile
await expect(page.getByTestId('hamburger-menu')).toBeVisible();
// Click hamburger to open menu
await page.getByTestId('hamburger-menu').click();
await expect(page.getByRole('navigation')).toBeVisible();
});
Running Playwright Tests¶
Run all tests:
Run specific test file:
Run in headed mode (see browser):
Run in debug mode:
Run in UI mode (interactive):
View test report:
Playwright MCP Commands Reference¶
When using Playwright MCP through Claude, you can ask Claude to:
Navigation:
- "Navigate to http://localhost:3000/login"
- "Go to the dashboard page"
- "Click the back button"
Interaction:
- "Click the submit button"
- "Fill the email input with test@example.com"
- "Select 'Option 1' from the dropdown"
- "Check the terms checkbox"
Verification:
- "Take a screenshot"
- "Check if error message is visible"
- "Get the page title"
- "Check console for errors"
- "List all network requests"
Debugging:
- "Find all buttons on the page"
- "Get the text of the error message"
- "Check if the form is disabled"
- "Take screenshot of the login form only"
Example: Using Playwright MCP for Task Testing¶
Your task: TASK-039 (Implement E2E tests for login flows)
Step 1: Manual exploration with MCP
Use Playwright MCP to explore the login flow
Start the app (npm run dev should be running)
Please test this flow:
1. Go to http://localhost:3000/login
2. Take screenshot of initial state
3. Try submitting empty form - what happens?
4. Try invalid email - what happens?
5. Try valid email - what happens?
6. Take screenshots at each step
7. Check console for any errors
Report what you observe so I can write proper tests
Step 2: Write tests based on observations
Use qa-tester to write Playwright tests for TASK-039
Based on the manual testing with MCP, write comprehensive E2E tests for:
1. Empty form submission shows validation errors
2. Invalid email shows error message
3. Valid email shows success message
4. Rate limiting after 3 attempts
5. OAuth buttons are clickable and redirect properly
Use the Page Object Model pattern.
Troubleshooting Playwright¶
Problem: Tests timeout
// Increase timeout for slow operations
test('slow operation', async ({ page }) => {
test.setTimeout(60000); // 60 seconds
await page.goto('/dashboard');
// ...
});
Problem: Element not found
// Use proper waits
await page.getByTestId('submit-button').waitFor({ state: 'visible' });
await page.getByTestId('submit-button').click();
Problem: Flaky tests
// Use auto-waiting instead of arbitrary timeouts
// ❌ Bad
await page.waitForTimeout(3000);
// ✅ Good
await expect(page.getByText('Success')).toBeVisible();
Problem: Test works locally but fails in CI
// Use CI-specific configuration
export default defineConfig({
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
use: {
trace: 'on-first-retry',
video: 'retain-on-failure',
},
});
Step 4: Quality Check (3 Checks)¶
Before committing, run these 3 checks to ensure production quality:
Check 1: Code Review (15 min)¶
/workflow-review-code
Files implemented:
- [List files you created/modified]
Task reference: TASK-XXX from documents/03-dev-tasks/[feature]-dev-tasks.md
What it checks:
- Code quality and TypeScript types
- Error handling
- Best practices
- Accessibility
- Performance issues
Action: Fix any issues found, then re-run review until clean
Check 2: Security Audit (15 min)¶
/workflow-review-security
Task: TASK-XXX (authentication/data handling/API)
Focus: OWASP Top 10, input validation, authentication security
Critical for tasks involving:
- Authentication (login, signup, OAuth)
- User input (forms, search)
- Data storage (database operations)
- API endpoints (server actions, tRPC)
- File uploads
Action: Fix security issues immediately - security is non-negotiable
Check 3: Performance Check (10 min)¶
/workflow-review-performance
Feature: [What you built]
Check: Load time, bundle size, Core Web Vitals
Important for tasks involving:
- UI components (bundle size)
- Dashboard/pages (load time)
- API calls (response time)
- Database queries (N+1 queries)
Action: Apply optimizations suggested
Step 5: Commit¶
After all quality checks pass, commit your work and update the task status.
Before Committing: Update Task Status¶
IMPORTANT: Ask Claude Code to update the task markdown file to mark it as complete:
Please update documents/03-dev-tasks/[feature]-dev-tasks.md
Mark TASK-XXX as completed by:
1. Adding a ✅ emoji or [COMPLETED] tag to the task title
2. Adding completion date
3. Adding any implementation notes or deviations from original plan
Example:
### TASK-012: Build login page UI with email input ✅
- **Status**: Completed on 2024-01-15
- **Implemented by**: [Your Name]
- **Notes**: Used shadcn/ui instead of custom components for faster development
This keeps the task file updated for the team and tracks progress.
Option 1: Commit with Git Commands (Traditional)¶
git add .
git commit -m "feat: [brief description from task title]
Implemented TASK-XXX: [Full task title]
Changes:
- [What you created/modified]
- [Key technical decisions]
- [Dependencies used]
Testing:
- [X] Unit tests passing
- [X] E2E tests passing
- [X] Code review clean
- [X] Security audit passed
- [X] Performance optimized
Task: TASK-XXX
File: documents/03-dev-tasks/[feature]-dev-tasks.md
Dependencies: [List dependency tasks if any]
"
Option 2: Commit with GitHub MCP (Recommended)¶
Use GitHub MCP to create commits and optionally create issues or PRs directly from Claude Code:
Use GitHub MCP to commit my changes
Commit details:
- Type: feat
- Task: TASK-012 - Build login page UI with email input
- Summary: Implement login page with magic link authentication
Changes:
- Created app/(auth)/login/page.tsx with login layout
- Created components/auth/login-form.tsx with email validation
- Integrated with TASK-011 server action
- Added OAuth buttons for Google and Facebook
- Implemented loading states and error handling
Testing completed:
- 8 unit tests passing
- 6 E2E tests passing
- Code review clean
- Security audit passed
- Performance optimized
Please create the commit and push to current branch.
GitHub MCP Benefits:
- Automatically formats commit messages
- Can create GitHub issues for follow-up tasks
- Can open draft PRs for review
- Links commits to issues automatically
Create Issue from Task:
Use GitHub MCP to create an issue for follow-up work
Title: Add password reset flow to login page
Body:
Based on TASK-012 implementation, we should add password reset functionality.
Requirements:
- "Forgot password?" link on login page
- Email-based reset flow
- Token expiration (15 minutes)
- Rate limiting (3 attempts per hour)
Related to: TASK-012
Dependencies: TASK-010 (magic link service)
Labels: enhancement, authentication
Real Commit Example¶
git commit -m "feat: implement login page with magic link authentication
Implemented TASK-012: Build login page UI with email input
Changes:
- Created app/(auth)/login/page.tsx with login layout
- Created components/auth/login-form.tsx with email validation
- Integrated with TASK-011 server action
- Added OAuth buttons for Google and Facebook
- Implemented loading states and error handling
- Added success message 'Check your email for magic link'
Technical decisions:
- Used Client Component for form state management
- shadcn/ui Card, Input, Button components
- Zod schema for email validation
- useFormState hook for server action integration
Testing:
- [X] 8 unit tests passing (login-form.test.tsx)
- [X] 6 E2E tests passing (login.spec.ts)
- [X] Code review clean (no issues)
- [X] Security audit passed (input validation, CSRF)
- [X] Performance optimized (LCP 1.2s, bundle size OK)
Task: TASK-012
File: documents/03-dev-tasks/login-authentication-dev-tasks.md
Dependencies: TASK-011 (email login server action)
"
Hands-On Exercise (Workshop Activity)¶
Exercise 1: Implement a Simple Task (45 min)¶
Pick a task: TASK-001 (Setup Neon DB PostgreSQL database)
-
Read the task (5 min)
- Open:
documents/03-dev-tasks/login-authentication-dev-tasks.md - Find TASK-001
- Read: User Story, Description, Acceptance Criteria, Technical Notes
- Open:
-
Implement (15 min)
-
Quality Check (15 min)
-
Commit (10 min)
git commit -m "feat: setup Neon DB PostgreSQL database Implemented TASK-001: Setup Neon DB PostgreSQL database Changes: - Created Neon DB project with PostgreSQL 16 - Configured connection pooling - Added DATABASE_URL and DIRECT_DATABASE_URL to .env.local - Separated dev and production environments - Tested connection from Next.js app Testing: - [X] Database connection successful - [X] Security review passed (env vars in .gitignore) Task: TASK-001 File: documents/03-dev-tasks/login-authentication-dev-tasks.md Dependencies: None "
Exercise 2: Implement a Full Feature Task (90 min)¶
Pick a task: TASK-012 (Build login page UI)
Follow all 5 steps:
- Read task - Understand requirements
- Code - Use
frontend-uiagent - Test - Use
qa-testeragent - Quality - Run 3 checks (code, security, performance)
- Commit - Clear commit message
Challenge: Complete in under 90 minutes (task estimate is 6 hours, but AI speeds you up!)
Exercise 3: Complex Task with Dependencies (60 min)¶
Pick a task: TASK-020 (Create getDashboardData use case)
Key learning: Check dependencies first!
-
Check dependencies (5 min)
- Task says: "Dependencies: TASK-013,TASK-014,TASK-015,TASK-016"
- Verify these are done (repositories exist)
-
Implement (30 min)
-
Test integration (15 min)
-
Quality + Commit (10 min)
Exercise 4: Interactive Testing with Playwright MCP (45 min)¶
Pick a task: TASK-039 (Implement E2E tests for login flows)
Key learning: Use Playwright MCP for exploration before writing tests
Prerequisites:
- Login feature already implemented (TASK-012)
- App running (
npm run dev) - Playwright MCP configured
Step 1: Manual exploration (15 min)
Use Playwright MCP to explore and test the login flow at http://localhost:3000/login
Please perform these actions and report findings:
1. Navigate to login page
2. Take screenshot of initial state
3. Try submitting empty form
4. Take screenshot of validation errors
5. Fill email with "invalid-email"
6. Submit and take screenshot
7. Fill email with "test@example.com"
8. Submit and take screenshot of success
9. Check console for any errors
10. List all network requests made
For each step, describe what you see and any issues.
Step 2: Debug any issues found (10 min)
If MCP found issues:
Use Playwright MCP to debug [specific issue]
Context: [Issue description from Step 1]
Please:
- Take detailed screenshots
- Check console errors
- Monitor network requests
- Identify root cause
Then fix the issue with appropriate agent:
Step 3: Write automated tests (15 min)
Use qa-tester to write Playwright E2E tests for TASK-039
Based on the manual testing with Playwright MCP, write tests for:
1. Login page displays correctly (screenshot showed: X, Y, Z)
2. Empty form shows validation errors (observed: "Email is required")
3. Invalid email shows error (observed: "Invalid email format")
4. Valid email shows success message (observed: "Check your email for magic link")
5. Rate limiting after 3 attempts (need to test)
Use Page Object Model pattern with data-testid selectors.
Create tests/e2e/login.spec.ts
Step 4: Run tests and verify (5 min)
# Run the Playwright tests
npx playwright test tests/e2e/login.spec.ts --headed
# If tests fail, debug with MCP again
Use Playwright MCP to debug failing test: [test name]
Bonus Challenge: Test OAuth buttons
Use Playwright MCP to test OAuth flow
1. Click Google OAuth button
2. Check redirect URL
3. Verify correct OAuth parameters
4. Take screenshot
Report findings.
Agent Cheat Sheet¶
Most Common Agents You'll Use¶
| Agent | When to Use | Command Format |
|---|---|---|
database |
Prisma schemas, migrations | Use database to implement TASK-XXX |
backend-api |
Server Actions, tRPC, APIs | Use backend-api to implement TASK-XXX |
frontend-ui |
Components, forms, UI | Use frontend-ui to implement TASK-XXX |
fullstack-nextjs |
Pages, layouts, routing | Use fullstack-nextjs to implement TASK-XXX |
qa-tester |
Unit/E2E/Playwright tests | Use qa-tester to write tests for TASK-XXX |
| Playwright MCP | Interactive browser testing | Use Playwright MCP to test [feature] |
security |
Security review | /workflow-review-security |
performance |
Performance optimization | /workflow-review-performance |
code-reviewer |
Code quality check | /workflow-review-code |
Playwright MCP Special Commands¶
Interactive Testing & Debugging:
Use Playwright MCP to test the login page- Test features interactivelyUse Playwright MCP to debug [feature]- Debug issues with screenshots and console logsUse Playwright MCP to take screenshots of [page]- Visual verificationUse Playwright MCP to check console errors on [page]- Find JavaScript errorsUse Playwright MCP to monitor network requests on [page]- Debug API calls
The "Always Paste Your Task" Pattern¶
Best practice: Always paste the full task when prompting agents
Use [agent-name] to implement TASK-XXX from documents/03-dev-tasks/[feature]-dev-tasks.md
[Paste full task details including:]
- User Story
- Description
- Acceptance Criteria
- Technical Notes
[Add any additional context like:]
- Dependencies status (done/not done)
- Technical stack decisions
- Special requirements
Why? The agent gets complete context and builds exactly what's in the acceptance criteria.
Best Practices¶
✅ DO¶
-
Read the full task before prompting the agent
- User Story (why)
- Description (what)
- Acceptance Criteria (checklist)
- Technical Notes (how)
-
Check dependencies first
- Don't start TASK-012 if TASK-011 isn't done
- Ask team: "Is TASK-011 completed?"
-
Copy-paste task details into agent prompts
- Don't paraphrase or summarize
- Agent needs full context
-
Test immediately after coding
- While task context is fresh
- Easier to debug
-
Run all 3 quality checks before committing
- Code review
- Security
- Performance
-
Reference task in commits
Task: TASK-XXXFile: documents/03-dev-tasks/...
❌ DON'T¶
-
Don't skip quality checks
- "I'll fix it later" = technical debt
- Takes 30 min now, 3 hours later
-
Don't commit without tests
- No tests = production bugs
- Tests save debugging time
-
Don't ignore dependencies
- Building TASK-020 before TASK-013-016 = wasted work
- Check dependencies are done first
-
Don't vague prompts
- ❌ "Build login page"
- ✅ "Implement TASK-012 with all acceptance criteria"
-
Don't skip acceptance criteria
- Every checkbox in acceptance criteria must be done
- Agent helps you complete ALL criteria
Troubleshooting¶
Problem: "Agent doesn't understand what I need"¶
Solution: Paste the full task from the markdown file
Use backend-api to implement TASK-011
[Copy entire task section from markdown, including:]
- User Story: As a user, I want to...
- Description: ...
- Acceptance Criteria:
- [ ] ...
- Technical Notes: ...
Problem: "My task depends on other tasks not done yet"¶
Solution:
- Ask team which tasks are done
- Only pick tasks where all dependencies are complete
- If blocked, pick a different task with no dependencies or completed dependencies
Problem: "Quality check found issues"¶
Solution: Fix and re-check
/workflow-review-code
# Finds 5 issues
Use [appropriate-agent] to fix these issues:
1. [Issue 1 description]
2. [Issue 2 description]
...
# After fixing
/workflow-review-code
# Should be clean now
Problem: "Agent created something different from acceptance criteria"¶
Solution: Be more specific and reference acceptance criteria explicitly
Use frontend-ui to implement login form
IMPORTANT: Must meet ALL acceptance criteria from TASK-012:
- [ ] Email input with validation
- [ ] Submit button with loading state
- [ ] Google OAuth button
- [ ] Facebook OAuth button
- [ ] Error message display
- [ ] Success message "Check your email"
Each checkbox must be completed. Do not skip any.
Quick Reference: Your First Day¶
Morning (Setup)¶
# 1. Verify Playwright MCP is available in Claude Code
# In Claude Code, you can ask: "Do I have browser testing tools?"
# Should see mcp__playwright__browser_* functions available
# 2. Install Playwright in your project (if not done)
npm install -D @playwright/test
npx playwright install
# 3. Start your dev server
npm run dev
# 4. Open your task file in Claude Code
# Navigate to documents/03-dev-tasks/[your-feature]-dev-tasks.md
# 5. Find tasks with no dependencies
# Look for: Dependencies: None
# 6. Pick your first task
# Criteria: High priority + No dependencies + Matches your skill
Working on Task (Repeat for each task)¶
# 1. Read task thoroughly (5 min)
# 2. Research with Context7 MCP (5 min) - Get latest documentation
Use Context7 MCP to get latest [framework] documentation
# Questions: Latest patterns, best practices, API changes
# 3. Code with agent (30-120 min depending on task)
Use [agent] to implement TASK-XXX
# Use insights from Context7 MCP research
# 4. Test with Playwright MCP first (10 min) - Interactive exploration
Use Playwright MCP to test [feature] at http://localhost:3000/[page]
# Take screenshots, check console, verify behavior
# 5. Write automated tests (20 min)
Use qa-tester to write Playwright tests for TASK-XXX based on MCP findings
# 6. Quality checks (30 min)
/workflow-review-code
/workflow-review-security
/workflow-review-performance
# 7. Update task status (2 min)
# Ask Claude Code to mark task as completed in dev-tasks file
# 8. Commit with GitHub MCP (5 min) - Recommended
Use GitHub MCP to commit my changes
# Or use traditional git commands
End of Day (Review)¶
# Check what you completed today
git log --oneline --since="today"
# Update team on progress
# Mark completed tasks in project tracker
Playwright MCP Debugging Scenarios¶
Common debugging scenarios using Playwright MCP:
Scenario 1: Button Click Not Working¶
Use Playwright MCP to debug submit button issue
Context: Users report submit button does nothing
Steps:
1. Navigate to http://localhost:3000/login
2. Take screenshot
3. Click submit button with data-testid="submit-button"
4. Check console for JavaScript errors
5. Monitor network requests
6. Report findings
Scenario 2: Form Validation Not Showing¶
Use Playwright MCP to debug form validation
Context: Error messages not appearing
Steps:
1. Go to login page
2. Submit empty form
3. Take screenshot
4. Check if error elements exist in DOM
5. Check console for errors
6. Report what's missing
Scenario 3: Responsive Design Issues¶
Use Playwright MCP to test mobile responsiveness
Context: Dashboard looks broken on mobile
Steps:
1. Resize browser to 375x667 (mobile)
2. Navigate to http://localhost:3000/dashboard
3. Take screenshot
4. Check if hamburger menu is visible
5. Try clicking menu items
6. Take screenshots of any layout issues
7. Resize to 1920x1080 (desktop)
8. Compare layout differences
Scenario 4: API Call Failing¶
Use Playwright MCP to debug API call
Context: Dashboard not loading data
Steps:
1. Navigate to http://localhost:3000/dashboard
2. Monitor network requests
3. Check for failed API calls
4. Check console for errors
5. Take screenshot of empty state
6. Report API endpoint, status code, error message
Scenario 5: OAuth Redirect Issue¶
Use Playwright MCP to test Google OAuth flow
Context: OAuth button not redirecting correctly
Steps:
1. Go to login page
2. Click Google OAuth button
3. Check redirect URL
4. Check URL parameters (client_id, redirect_uri, etc.)
5. Take screenshot
6. Report redirect destination and parameters
Summary¶
The 6-Step Workflow:
- Pick Task - Open task file, read full task
- Code It - Use right agent with full task context
- Test It - Write tests immediately (use Playwright MCP for exploration!)
- Quality Check - Code review + Security + Performance
- Update Task - Mark task as completed in dev-tasks file
- Commit - Clear message referencing task
Key Success Factors:
- Always paste the FULL task details to agents
- Check dependencies before starting
- Complete ALL acceptance criteria
- Use Playwright MCP for interactive testing and debugging
- Use Context7 MCP for latest library documentation
- Use GitHub MCP for repository interactions
- Update task status before committing
- Run quality checks before committing
- Reference task number in commits
MCP Servers Enhance Your Workflow:
- Playwright MCP - Visual debugging with screenshots and console logs
- Context7 MCP - Access latest Next.js, React, and library documentation
- GitHub MCP - Create issues, search code, manage PRs without leaving Claude Code
Time Expectations:
- Simple tasks (4h estimate): ~2-3 hours with AI
- Medium tasks (6-8h estimate): ~3-5 hours with AI
- Complex tasks (10-12h estimate): ~5-7 hours with AI
AI speeds you up ~40-50%, Playwright MCP makes debugging 10x faster, and Context7 MCP eliminates documentation hunting.
Next Steps¶
- Start with Exercise 1 in this workshop
- Practice the 5-step workflow on 2-3 tasks
- Read Best Practices Guide for advanced tips
- Explore Workflow Commands for complex features
Ready? Open documents/03-dev-tasks/ and pick your first task!