Role & Context Setting
Learning Outcomes
- Explain why role-setting changes AI output quality for code tasks
- Write effective role descriptions that prime the AI for specific expertise
- Distinguish between project context and task context
- Decide what information to include and what to omit
- Apply the "expert in X" pattern for domain-specific code generation
Lesson Plan
| Segment | Duration | Topic |
|---|---|---|
| Intro | 3 min | Why role and context change everything |
| Explain | 8 min | How role-setting works under the hood |
| Demo | 8 min | Same task, different roles — comparing outputs |
| Explain | 10 min | Context: what to include and what to omit |
| Demo | 8 min | Project vs task context in practice |
| Practice | 6 min | Write role+context for your own project |
| Wrap-up | 2 min | Key takeaways, preview next lesson |
Before You Begin
Pre-work:
- Complete Lesson 1 (Anatomy of a Good Prompt)
- Have a real project open that you'd like to generate code for
- Think about: what would a specialist in your tech stack know?
Shopping List:
- Any AI coding tool (Claude Code, Cursor, or Codex CLI)
- A project with at least 3-4 files to provide as context
- Your prompts folder for saving experiments
When you assign a role to an AI, you're not just being polite or playing pretend. You're activating a specific subset of the model's knowledge and aligning its output style with that expertise.
Consider the difference:
No role:
Write a function to process a refund.
AI might produce: a generic, textbook-style function that works but lacks real-world considerations.
With role:
You are a senior backend engineer who has run payment systems in
production. You're cautious about edge cases and always consider
duplicate requests, partial failures, and currency rounding.
Write a function to process a refund.
AI now produces: a function that uses an idempotency key so a retried request cannot refund twice, handles a failed downstream call without leaving the refund half-done, and works in integer minor units rather than floating-point amounts.
Why does this work?
The role tells the AI:
- What knowledge to prioritise — production patterns over generic patterns
- What quality bar to aim for — senior engineer, not tutorial-level
- What concerns to anticipate — failure modes, not just the happy path
- What style to use — production-quality, defensive code
Not all role descriptions are equally useful. Here's how to write ones that actually change the output:
Formula: You are a [seniority] [specialisation] who [relevant experience/values].
Effective roles for different tasks:
For API design:
You are a senior API architect who designs RESTful services used by
millions of users. You prioritise backward compatibility, clear error
messages, and consistent naming conventions.
For frontend components:
You are a frontend developer who specialises in accessible, performant
React applications. You follow WAI-ARIA guidelines and always consider
screen reader users and keyboard navigation.
For database work:
You are a database performance engineer. You think in terms of query
plans, index coverage, and N+1 problems. You always consider how
queries will perform at 100x the current data volume.
For testing:
You are a QA engineer who writes tests that catch real bugs, not just
tests that increase coverage numbers. You focus on edge cases,
boundary conditions, and integration points where things break.
What makes a role description effective:
- Specificity — "senior TypeScript developer" beats "developer"
- Values — what they care about ("prioritises readability")
- Experience — what they've seen ("has worked on large-scale systems")
- Anti-patterns — what they avoid ("never uses any without a type guard")
Roles to avoid:
- Too vague: "You are a good programmer" (meaningless)
- Too narrow: "You are a developer who only uses for loops" (constraining in unhelpful ways)
- Contradictory: "You are a security expert who prioritises speed over safety" (undermines the role)
Context is the background information AI needs to produce relevant code. Too little context produces generic code; too much buries the actual task.
Always include:
- Tech stack — language, framework, major libraries
We're using Python 3.11, FastAPI, SQLAlchemy 2.0, and PostgreSQL.
- Relevant constraints — patterns your team follows
We use repository pattern for data access. All routes return Pydantic models.
- What exists already — code the new code must integrate with
The User model already has: id, email, created_at, is_active fields.
The auth middleware sets request.state.user on authenticated routes.
- What "done" looks like — how you'll know it's correct
The endpoint should return the same shape as GET /users/{id} but with
the additional "preferences" field populated.
Often omit:
- Irrelevant project history ("We used to use MongoDB but migrated last year")
- Team dynamics ("My team lead prefers...")
- Obvious information ("Python is a programming language that...")
- Entire files when only a few lines are relevant
The "would a new team member need this?" test:
Imagine a skilled developer joining your team for one day to do this task. What would you tell them in a 2-minute briefing? That's your context.
Good context:
"We have a FastAPI app with SQLAlchemy. Routes are in /routes, models in /models.
We use dependency injection for database sessions. Here's the existing user model
and the route it needs to integrate with: [paste relevant code]"
Bad context:
"Our company started in 2018 and we've gone through three framework migrations.
The current stack is FastAPI but some legacy endpoints still use Flask.
Our team has 8 developers across 2 time zones..." [continues for 500 words
before getting to the actual task]
There are two layers of context, and they serve different purposes:
Project context — stable facts about your codebase that apply to many tasks:
- Tech stack and versions
- Architectural patterns (MVC, repository pattern, etc.)
- Coding standards (naming conventions, file structure)
- Key dependencies and how they're used
- Testing framework and conventions
Task context — specific information needed for this one request:
- The file(s) you're modifying
- The specific function or endpoint involved
- The bug you're seeing or feature you're building
- Related code that the new code must work with
How to use them:
For tools that support system prompts or rules files (CLAUDE.md, .cursorrules, codex instructions), put project context there. It applies to every interaction:
# Project Context (in rules file)
- TypeScript strict mode, no "any" types
- React 18 with hooks only, no class components
- Tests use Vitest, not Jest
- API responses follow JSON:API spec
- All dates stored as ISO 8601 UTC strings
Then in each prompt, you only need task context:
# Task Context (in your prompt)
I'm adding a "last login" feature to the user profile page.
The API endpoint GET /users/me already returns a lastLoginAt field.
The ProfileCard component currently shows: name, email, avatar.
Add the last login timestamp to ProfileCard, formatted as relative time
(e.g., "3 hours ago"). Use the existing formatRelativeTime utility
from src/utils/dates.ts.
This separation means your prompts stay short and focused while the AI still has all the background it needs.
One of the most versatile patterns for code generation is asking for domain-specific expertise. This pattern combines role and context into a focused directive.
The pattern:
As an expert in [specific domain], [task] while considering [domain-specific concerns].
Examples:
Performance optimisation:
As an expert in JavaScript runtime performance, review this function
and optimise it for execution speed. Consider: V8 hidden classes,
garbage collection pressure, megamorphic call sites, and whether
any operations can be moved outside the hot path.
[paste function]
Accessibility:
As an expert in web accessibility (WCAG 2.1 AA), review this form
component and fix any accessibility issues. Consider: keyboard
navigation order, screen reader announcements, error association
with fields, and colour contrast ratios.
[paste component]
Database modelling:
As an expert in relational database design for multi-tenant SaaS
applications, design the schema for a notification system. Consider:
tenant isolation, query patterns for "unread count" and "recent
notifications", soft delete for audit trail, and scaling to
millions of notifications per tenant.
Correctness review:
As an expert in login and session handling, review this sign-in
flow for correctness. Consider: input validation, session expiry,
what the user sees when sign-in fails, and settings that differ
between environments.
[paste sign-in code]
Why this pattern works so well:
- It names the specific domain, activating specialised knowledge
- It explicitly lists what to "consider," preventing shallow analysis
- It's concise — one sentence sets up the entire framing
- It's adaptable to any domain you need
Combining with context:
As an expert in GraphQL schema design for e-commerce systems:
Context: We have an existing REST API with Product, Category, and
Inventory services. We're adding a GraphQL gateway as a BFF
(backend-for-frontend) layer. The mobile app needs to fetch a product
with its category, current stock level, and the 3 most recent reviews
in a single request.
Design the GraphQL schema types and resolvers for this use case.
Use DataLoader to prevent N+1 queries to the underlying REST services.
Practice exercise: Pick your current project and write three "expert in X" prompts for tasks you commonly do. Save them to your prompts/library folder.
Questions & Answers
Key Takeaways
- Roles activate specialised knowledge — a security engineer role produces fundamentally different code than a generic developer role.
- Effective roles have three parts — seniority, specialisation, and values/experience.
- Context should pass the "new team member" test — include what a skilled developer would need to know for a one-day task.
- Separate project context from task context — put stable facts in rules files, variable facts in prompts.
- The "expert in X" pattern is your Swiss army knife — it combines role and context into one powerful framing.
Next Steps: In Lesson 3 — Step-by-Step Instructions, we'll learn how to break complex tasks into numbered sequences that guide AI through multi-part implementations.