Prompt Engineering: The Art of Communicating with Claude
The quality of Claude's output depends directly on the quality of your prompts. Prompt engineering isn't just writing requests: it's a skill that combines clear communication, technical understanding, and structured thinking. In this article, we'll explore advanced techniques to get predictable, high-quality results from Claude Code.
Claude Code represents a significant evolution in AI-assisted development, offering extended context windows, agentic capabilities, and persistent project understanding. Mastering prompt engineering unlocks the full potential of this powerful assistant.
Series Overview
| # | Article | Focus |
|---|---|---|
| 1 | Foundation and Mindset | Setup and mindset |
| 2 | Ideation and Requirements | From idea to MVP |
| 3 | Backend Architecture | API and database |
| 4 | Frontend Structure | UI and components |
| 5 | Context and Setup | CLAUDE.md and project context |
| 6 | You are here - Prompt Engineering | Advanced prompts and agents |
| 7 | Testing and Quality | Unit, integration, E2E |
| 8 | Documentation | README, API docs, ADR |
| 9 | Deploy and DevOps | Docker, CI/CD |
| 10 | Evolution | Scalability and maintenance |
Why Prompt Engineering is Essential
The difference between a mediocre prompt and an excellent one can mean hours of work saved or wasted. A well-structured prompt:
Benefits of Prompt Engineering
- Precision: Targeted responses instead of generic code
- Consistency: Output coherent with project conventions
- Efficiency: Fewer iterations to reach the result
- Reproducibility: Same prompts, same quality results
- Automation: Reusable templates for common tasks
- Context Retention: Claude maintains understanding across sessions
Anatomy of an Effective Prompt
A well-structured prompt follows a predictable pattern. Here are the fundamental components:
+-------------+-----------------------------------------------+
| ROLE | Who Claude should be (role, expertise) |
+-------------+-----------------------------------------------+
| CONTEXT | Project background, stack, architecture |
+-------------+-----------------------------------------------+
| TASK | What it should do SPECIFICALLY |
+-------------+-----------------------------------------------+
| CONSTRAINTS| Limitations, NON-FUNCTIONAL requirements |
+-------------+-----------------------------------------------+
| OUTPUT | Desired response format |
+-------------+-----------------------------------------------+
| EXAMPLES | Expected input/output examples (optional) |
+-------------+-----------------------------------------------+
Component Details
1. ROLE - Define the Expertise
The role isn't just a title: it defines the expertise level, knowledge domain, and communication style.
// Too generic
ROLE: You are a developer.
// Specific and contextual
ROLE: You are a senior TypeScript developer with 10+ years of experience
in building scalable Node.js APIs. You follow Clean Architecture principles
and prioritize maintainability over clever solutions. You are security-conscious
and always consider edge cases.
2. CONTEXT - The Project Background
The more context you provide, the more aligned the output will be with your project. Claude Code excels when it understands the full picture.
CONTEXT:
- Project: E-commerce platform for handmade products
- Stack: Node.js 20 + Express 5 + TypeScript 5.3
- Database: PostgreSQL 16 with Prisma ORM
- Architecture: Clean Architecture (Controller - Service - Repository)
- Auth: JWT with refresh tokens, OAuth2 for social login
- Current phase: MVP development, 2 developers
- Existing patterns: We use class-validator for DTOs, custom error classes
- API style: RESTful with JSON:API specification
- Testing: Jest for unit tests, Supertest for integration
3. TASK - The Specific Objective
Describe WHAT it should do, not HOW. Let Claude propose the implementation.
TASK:
Create a ProductService class that handles:
1. Create product (validate price > 0, name unique per seller)
2. Get all products with pagination and filtering (by category, price range)
3. Get product by ID or slug
4. Update product (only owner can update)
5. Soft delete product (mark as inactive, don't remove from DB)
6. Get seller's products with statistics (total views, favorites count)
4. CONSTRAINTS - Non-Functional Requirements
Here you define rules that the code MUST follow, regardless of implementation.
CONSTRAINTS:
- Use dependency injection (constructor injection)
- All methods must be async
- Throw custom errors: ValidationError, NotFoundError, ForbiddenError
- Never expose internal IDs (use UUIDs or slugs in responses)
- Include JSDoc comments for all public methods
- Follow existing naming conventions (camelCase methods, PascalCase classes)
- Don't use 'any' type - always use specific types or generics
- Logging: use structured logging with correlation IDs
- All database operations must be within transactions where appropriate
5. OUTPUT - The Response Format
Specify exactly how you want to receive the response.
OUTPUT FORMAT:
- Single TypeScript file
- Export the class as default
- Include all necessary imports at the top
- Add interface definition for the service (IProductService)
- Group methods logically (CRUD operations, then queries, then statistics)
- After the code, provide a brief explanation of key design decisions
- Include example usage in comments
Complete Example: Professional Prompt
Here's an example that combines all components for Claude Code:
ROLE: You are a senior TypeScript developer specialized in e-commerce systems.
You have deep knowledge of payment processing, inventory management, and
order fulfillment workflows. You write clean, testable code.
CONTEXT:
- Project: Handmade marketplace (like Etsy)
- Stack: Node.js 20 + Express 5 + TypeScript 5.3 + Prisma
- Architecture: Clean Architecture with DDD patterns
- We already have: UserService, ProductService, PaymentGateway interface
- Order statuses: pending - paid - processing - shipped - delivered (or cancelled)
- Payment: Stripe integration via PaymentGateway interface
- This is for an MVP but should be designed for scale
TASK:
Create an OrderService that handles the complete order lifecycle:
1. Create order from cart (validate stock, calculate totals with tax)
2. Process payment (use PaymentGateway, handle failures gracefully)
3. Update order status (with status machine validation)
4. Cancel order (refund if paid, restore stock)
5. Get order history for user (with pagination)
6. Get order details (include items, shipping, payment info)
CONSTRAINTS:
- Use transactions for operations that modify multiple tables
- Implement optimistic locking to prevent race conditions on stock
- All monetary calculations must use integer cents (not floats)
- Status transitions must be validated (can't go from 'delivered' to 'pending')
- Emit events for status changes (OrderPaid, OrderShipped, OrderCancelled)
- Never expose payment details in responses (mask card numbers)
- Include retry logic for payment processing (max 3 attempts)
- Handle partial failures gracefully (rollback on error)
OUTPUT FORMAT:
- Complete TypeScript file with all imports
- IOrderService interface first
- OrderService class implementing the interface
- Include a STATUS_TRANSITIONS constant defining valid transitions
- Add JSDoc with @throws annotations
- After code: list potential edge cases that tests should cover
Long and Structured Prompts
Claude Code handles long prompts exceptionally well thanks to its extended context window. Don't be afraid to provide comprehensive information.
Multi-Section Prompt Template
===============================================================
PROJECT OVERVIEW
===============================================================
Project: TaskFlow - SaaS task management for freelancers
Phase: MVP (3 months to launch)
Team: 2 developers (1 fullstack, 1 frontend)
===============================================================
TECHNICAL STACK
===============================================================
Backend:
- Runtime: Node.js 20 LTS
- Framework: Express 5
- Language: TypeScript 5.3 (strict mode)
- ORM: Prisma 5.x
- Database: PostgreSQL 16
- Cache: Redis 7
- Queue: BullMQ
Frontend:
- Framework: Angular 17
- Styling: Tailwind CSS
- State: Angular Signals
- Testing: Jest + Playwright
===============================================================
ARCHITECTURE PATTERNS
===============================================================
- Clean Architecture (Entities - Use Cases - Controllers)
- Repository Pattern for data access
- Dependency Injection throughout
- Event-driven for cross-domain communication
- CQRS for complex read operations
===============================================================
EXISTING CODE CONVENTIONS
===============================================================
Naming:
- Files: kebab-case (user-service.ts)
- Classes: PascalCase (UserService)
- Methods: camelCase (createUser)
- Constants: UPPER_SNAKE_CASE (MAX_RETRY_COUNT)
- Interfaces: PascalCase with I prefix (IUserService)
Error Handling:
- Custom error classes extending BaseError
- Error codes: CATEGORY_SPECIFIC_ERROR (e.g., USER_NOT_FOUND)
- Always include context in error messages
Logging:
- Use Pino logger
- Always include correlationId
- Structured JSON format
===============================================================
CURRENT TASK
===============================================================
[Describe your specific task here]
===============================================================
EXPECTED OUTPUT
===============================================================
[Define the format and content of the response]
Multi-Step Prompts
For complex tasks, divide the work into logical steps. This approach produces better results because it allows you to validate and refine each step before proceeding.
Multi-Step Workflow
| Step | Prompt | Output | Review Before Next |
|---|---|---|---|
| 1 | "Define interfaces and types for this feature" | Contracts | Validate API shape |
| 2 | "Implement the base class structure with DI" | Scaffold | Check dependencies |
| 3 | "Implement createOrder with validation" | Core logic | Review business rules |
| 4 | "Add payment processing with retry" | Integration | Error handling |
| 5 | "Add the state machine for statuses" | Transitions | Edge cases |
| 6 | "Add comprehensive error handling" | Robustness | Coverage |
| 7 | "Generate unit tests for all paths" | Tests | Coverage report |
Step 1 of 7: Define the contracts
I'm building an OrderService for an e-commerce platform.
Before implementing, let's define the interfaces and types.
Define:
1. IOrderService interface with method signatures
2. Order entity type (all fields needed)
3. CreateOrderDto (input validation)
4. OrderResponseDto (what we return to clients)
5. OrderStatus enum with all states
6. OrderEvent types for status changes
Use our existing patterns:
- DTOs use class-validator decorators
- Entities have id, createdAt, updatedAt
- Money amounts in cents (integers)
After you provide these, I'll review before Step 2.
Review Prompts
Code review is one of Claude's strongest capabilities. Structure review requests to get actionable, prioritized feedback.
Review this code comprehensively:
```typescript
[PASTE CODE HERE]
```
ANALYZE FROM THESE PERSPECTIVES:
1. SECURITY (Critical)
- Injection vulnerabilities (SQL, XSS, Command)
- Authentication/Authorization issues
- Sensitive data exposure
- Input validation gaps
- OWASP Top 10 concerns
2. CORRECTNESS (High)
- Logic errors
- Edge cases not handled
- Race conditions
- Null/undefined handling
- Error handling gaps
3. PERFORMANCE (Medium)
- N+1 queries
- Memory leaks
- Unnecessary computations
- Missing caching opportunities
- Blocking operations in async code
4. MAINTAINABILITY (Medium)
- Code complexity (cyclomatic)
- Naming clarity
- Single responsibility violations
- Missing documentation
- Tight coupling
5. TESTABILITY (Medium)
- Untestable code patterns
- Hard-coded dependencies
- Side effects in constructors
- Missing test coverage areas
OUTPUT FORMAT:
For each issue found:
- Severity: CRITICAL / HIGH / MEDIUM / LOW
- Location: Line number or function name
- Issue: What's wrong
- Impact: Why it matters
- Fix: Code example of the solution
- Related: Links to documentation or best practices
Prioritize by: Severity first, then by ease of fix.
Architectural Validation Prompts
Use Claude to validate architectural decisions before implementation. This catches issues early when they're cheap to fix.
Validate this architectural decision:
DECISION: Implement event-driven architecture for order processing
CONTEXT:
- Current: Synchronous request-response for all operations
- Problem: Order processing blocks API for 3-5 seconds
- Scale: 1000 orders/day now, target 50,000/day in 12 months
- Team: 2 developers, moderate distributed systems experience
PROPOSED ARCHITECTURE:
```
[API] -> [Order Queue] -> [Order Worker]
| |
v v
[Redis] [PostgreSQL]
|
v
[Notification Queue] -> [Email Worker]
```
EVALUATE:
1. Does this solve the stated problem?
2. Is it appropriate for our scale (current and future)?
3. What complexity does it add?
4. What failure modes should we consider?
5. What monitoring/observability is needed?
6. Is there a simpler alternative?
PROVIDE:
- Overall recommendation: GO / NO-GO / CONDITIONAL
- Pros and cons table
- Risk assessment
- Implementation complexity estimate
- Alternative approaches if NO-GO
- Prerequisites before implementation
- Migration strategy from current architecture
Reusable Prompt Templates
Create a library of reusable prompts for common tasks. Save them in your
CLAUDE.md file or in a prompts/ folder in your repository.
Template: Generate Complete CRUD
Generate complete CRUD operations for [ENTITY_NAME].
ENTITY FIELDS:
[List each field with:]
- name: type (constraints)
EXAMPLE:
- id: UUID (auto-generated)
- title: string (required, 3-200 chars)
- description: string (optional, max 5000)
- status: enum [draft, published, archived]
- createdAt: datetime (auto)
- updatedAt: datetime (auto)
- authorId: UUID (required, foreign key to users)
GENERATE:
1. Prisma schema model
2. Entity class with TypeScript types
3. DTOs (Create, Update, Response, ListQuery)
4. Repository interface and implementation
5. Service with business logic
6. Controller with REST endpoints
7. Unit tests for service (happy path + edge cases)
8. Integration tests for controller
FOLLOW THESE PATTERNS:
[Reference your CLAUDE.md or paste existing code example]
ENDPOINTS TO CREATE:
- POST /api/v1/[entities] - Create
- GET /api/v1/[entities] - List (paginated, filterable)
- GET /api/v1/[entities]/:id - Get by ID
- PATCH /api/v1/[entities]/:id - Update
- DELETE /api/v1/[entities]/:id - Soft delete
Include OpenAPI annotations for each endpoint.
Template: Debug Assistance
I need help debugging an issue.
ERROR MESSAGE:
```
[PASTE EXACT ERROR MESSAGE]
```
STACK TRACE (if available):
```
[PASTE STACK TRACE]
```
CONTEXT:
- File: [filename and path]
- Function/Method: [name]
- What I'm trying to do: [brief description]
- When it happens: [trigger conditions]
- Frequency: [always / sometimes / random]
- Recent changes: [what changed before this started]
- What I've already tried: [list attempts]
RELEVANT CODE:
```typescript
[PASTE CODE - include enough context, typically 50-100 lines]
```
RELATED CONFIGURATION (if relevant):
```
[PASTE CONFIG FILES]
```
ENVIRONMENT:
- Node version: [x.x.x]
- OS: [Linux/Mac/Windows]
- Database: [PostgreSQL x.x]
- Other relevant versions: [...]
HELP ME:
1. Understand WHY this error is happening
2. Identify the ROOT CAUSE (not just symptoms)
3. Provide a FIX with explanation
4. Suggest how to PREVENT similar issues
5. Recommend tests to add for this case
Template: Refactoring
Refactor this code while maintaining identical external behavior:
CURRENT CODE:
```typescript
[PASTE CODE]
```
CURRENT TESTS (must continue to pass):
```typescript
[PASTE EXISTING TESTS]
```
REFACTORING GOALS (prioritized):
1. [Primary goal - e.g., "Reduce cyclomatic complexity"]
2. [Secondary goal - e.g., "Improve testability"]
3. [Tertiary goal - e.g., "Better naming"]
CODE SMELLS TO ADDRESS:
- [Specific smell, e.g., "Method too long - 80 lines"]
- [Specific smell, e.g., "Too many parameters - 7"]
- [Specific smell, e.g., "Nested conditionals - 4 levels deep"]
CONSTRAINTS:
- MUST keep the same public interface (method signatures)
- MUST NOT break existing tests
- MUST NOT change external behavior
- SHOULD be reviewable in one PR (not too many changes)
- SHOULD not require changes to calling code
OUTPUT:
1. Refactored code
2. BEFORE/AFTER comparison (key changes)
3. List of changes with reasoning for each
4. New tests needed (if any)
5. RISK ASSESSMENT of the refactoring
6. Rollback plan if issues arise
Simulated Agents with Persistent Prompts
You can configure Claude to act as a specialized agent with consistent behavior across your development session. Define these in your CLAUDE.md file.
## Security Reviewer Agent
When I ask you to review code for security, adopt this persona:
IDENTITY:
- Role: Senior Security Engineer (CISSP, 10+ years experience)
- Expertise: OWASP Top 10, secure coding, penetration testing
- Mindset: Assume all input is malicious until proven safe
REVIEW CHECKLIST:
Always check for:
1. Injection (SQL, NoSQL, Command, XPath, LDAP)
2. Broken Authentication
3. Sensitive Data Exposure
4. XML External Entities (XXE)
5. Broken Access Control
6. Security Misconfiguration
7. Cross-Site Scripting (XSS)
8. Insecure Deserialization
9. Using Components with Known Vulnerabilities
10. Insufficient Logging and Monitoring
OUTPUT FORMAT:
- Start with overall risk level: CRITICAL / HIGH / MEDIUM / LOW / SECURE
- List vulnerabilities in severity order
- For each: Location, Issue, Attack Vector, Remediation, Priority
- End with: "Immediate Actions Required" (if any)
NEVER:
- Dismiss a potential vulnerability as "unlikely"
- Assume validation happens elsewhere
- Trust any external input
- Accept "it's just internal" as a reason to skip security
## Performance Optimizer Agent
When I ask you to optimize performance, adopt this persona:
IDENTITY:
- Role: Performance Engineer
- Expertise: Database optimization, caching, profiling, load testing
- Mindset: Measure first, optimize second, verify third
ANALYSIS FRAMEWORK:
1. Identify bottlenecks (don't guess, look for evidence)
2. Quantify impact (milliseconds saved, memory reduced)
3. Consider trade-offs (complexity vs. performance)
4. Prioritize by ROI (biggest impact, least effort)
CHECK FOR:
- N+1 queries
- Missing indexes
- Unoptimized queries (SELECT *, no LIMIT)
- Memory leaks
- Synchronous blocking operations
- Missing caching opportunities
- Unnecessary data transformations
- Large payload sizes
- Connection pool exhaustion
OUTPUT FORMAT:
1. Current performance profile (estimated)
2. Identified bottlenecks (ordered by impact)
3. Recommendations with expected improvement
4. Trade-offs for each recommendation
5. Suggested metrics to track
6. Before/after code examples
RULES:
- Always profile before optimizing
- Premature optimization is the root of all evil
- Simple is usually faster than clever
- Memory and CPU are different trade-offs
Few-Shot Prompting
Provide examples of input/output to guide Claude's style and format. This is especially effective for maintaining consistency.
I need DTOs for a new entity following our existing patterns.
EXAMPLE OF OUR DTO STYLE:
```typescript
// Input DTO - for creating/updating
export class CreateUserDto {{ '{' }}
@IsString()
@MinLength(2)
@MaxLength(100)
name: string;
@IsEmail()
email: string;
@IsStrongPassword()
password: string;
{{ '}' }}
// Response DTO - what we return to clients
export class UserResponseDto {{ '{' }}
id: string;
name: string;
email: string;
createdAt: Date;
// Never include sensitive fields like password
static fromEntity(user: User): UserResponseDto {{ '{' }}
return {{ '{' }}
id: user.id,
name: user.name,
email: user.email,
createdAt: user.createdAt,
{{ '}' }};
{{ '}' }}
{{ '}' }}
```
NOW CREATE DTOs FOR:
Entity: Product
Fields:
- name (string, 3-200 chars, required)
- description (string, optional, max 5000)
- price (number, cents, min 100 = $1.00, required)
- categoryId (uuid, required)
- images (array of URLs, 1-10 items, required)
- tags (array of strings, optional, max 20)
Follow the exact same patterns shown above.
Negative Prompting
Specify what you DON'T want to avoid undesired output. Claude Code responds well to explicit exclusions.
Without Negative Prompting
Create a UserService with CRUD operations.
// Output might include:
// - console.log instead of logger
// - any types
// - Password in plain text in logs
// - SQL injection vulnerabilities
// - No error handling
With Negative Prompting
Create a UserService with CRUD operations.
DO NOT:
- Use console.log (use injected logger)
- Use 'any' type anywhere
- Log sensitive data (passwords, tokens)
- Use string concatenation for queries
- Return password in any response
- Use synchronous operations
- Ignore error handling
- Skip input validation
Role Stacking
Combine multiple expertise areas for more comprehensive output. This is powerful for getting multi-perspective feedback.
ROLES: You are simultaneously:
1. A senior security engineer who has worked on PCI-DSS compliant systems
2. A performance optimization specialist with experience in high-traffic APIs
3. A code reviewer focused on maintainability and clean architecture
4. A QA engineer thinking about edge cases and testability
Review this authentication service from all four perspectives.
[PASTE CODE]
For each role, provide:
- Issues found (severity: critical/high/medium/low)
- Specific line references
- Recommended fixes with code examples
- Potential risks if not addressed
Then synthesize:
- Overall assessment
- Prioritized action items
- Estimated effort to address all issues
Best Practices for Effective Prompts
Common Mistakes
- Vague prompts: "Make me an API"
- Too much irrelevant context
- No style examples
- Asking for everything in one prompt
- Ignoring errors and repeating
- Not specifying constraints
- Expecting it to guess conventions
- Not verifying generated code
- No CLAUDE.md file
Best Practices
- Be specific about what, how, why
- Provide only relevant context
- Include examples of your style
- Use multi-step for complex tasks
- Analyze errors and refine prompt
- Define clear constraints
- Show your existing conventions
- ALWAYS verify before using
- Maintain comprehensive CLAUDE.md
Pre-Prompt Checklist
Before Sending a Prompt
- Have I defined a specific role?
- Have I provided sufficient project context?
- Is the task specific and measurable?
- Have I listed non-functional constraints?
- Have I specified the output format?
- Have I included examples if necessary?
- Is the prompt clear but not unnecessarily long?
- Have I specified what NOT to do?
- Is my CLAUDE.md up to date?
Claude Code-Specific Tips
Claude Code has unique capabilities that you can leverage with the right prompts.
Leveraging Claude Code's Strengths
| Capability | How to Leverage | Example Prompt |
|---|---|---|
| Extended Context | Provide full files, not snippets | "Here's the complete service file..." |
| Project Understanding | Reference existing code by path | "Follow the pattern in src/services/user.service.ts" |
| Multi-File Awareness | Ask for changes across files | "Update the service, controller, and tests together" |
| Agentic Execution | Request complete implementations | "Implement this feature end-to-end, including tests" |
| Tool Integration | Ask it to run commands | "Run the tests and fix any failures" |
Conclusion and Next Steps
Prompt engineering is a fundamental skill for maximizing Claude Code's capabilities. It's not just about writing requests, but about structuring thought so that AI can understand and respond effectively.
With Claude Code's extended context and agentic capabilities, well-crafted prompts become even more powerful. Invest time in creating templates, maintaining your CLAUDE.md file, and refining your prompting techniques.
In the next article we'll see how to use Claude Code for testing and code quality: from generating unit tests to edge case coverage, from guided refactoring to assisted debugging.
Key Points to Remember
- Structure: ROLE + CONTEXT + TASK + CONSTRAINTS + OUTPUT
- Multi-Step: Divide complex tasks into logical steps
- Examples: Use few-shot prompting to define style
- Negative: Explicitly specify what NOT to do
- Role Stacking: Combine perspectives for comprehensive review
- Templates: Create a reusable library of prompts
- CLAUDE.md: Maintain project context documentation
- Verification: Always validate generated output







