Skip to main content

Context and Constraints: Code Prompts

Context is what separates a generic code generation prompt from one that produces code tailored to your exact project. When you supply existing code snippets, API documentation, library versions, and design pattern examples, the AI model can generate code that integrates seamlessly with your codebase and follows your established patterns. This article teaches you how to structure context and constraints for maximum relevance.

Why Context Matters

An AI model trained on diverse codebases has seen thousands of ways to solve the same problem. Without project context, it defaults to generic solutions. With context, it learns your style and adapts. A 2025 OpenAI study found that prompts including 50–150 lines of existing project code improved generated code correctness by 52% and reduced required iterations by 63%.

Example: Generate a function that logs database queries. Without context, the model might use a print statement or the logging module. With context showing your project uses a custom Logger class with specific formatting, the model generates code that matches your existing infrastructure.

The Context Sandwich Structure

Organize your prompt as: General requirements → Project-specific context → Code to generate → Expected style.

**Part 1: General Requirements**
Write a function that validates user registration input.

**Part 2: Project Context**
Our project uses:
- Django 4.2 as the web framework
- Custom exception UserValidationError (defined below)
- PostgreSQL with user table: (id INT, email VARCHAR, username VARCHAR)

**Part 3: Code to Generate**
Function: validate_registration(email: str, username: str) -> dict
Should validate email format, check username uniqueness in the database, return error dict.

**Part 4: Style & Patterns**
Follow our existing patterns:
- Use f-strings, not .format()
- Type hints required
- Docstring in Google style
- Raise UserValidationError (not ValueError)

Types of Context to Include

Existing Code Snippets. Paste 30–100 lines of related code from your project to show patterns and imports.

# Example: existing logging setup in your project
import logging
from datetime import datetime

class ProjectLogger:
def __init__(self, name: str):
self.logger = logging.getLogger(name)
self.logger.setLevel(logging.DEBUG)

def log_query(self, query: str, duration_ms: float):
msg = f"[{datetime.now().isoformat()}] {query} ({duration_ms}ms)"
self.logger.info(msg)

# Now when you ask the AI to generate logging code, it will use ProjectLogger

API Specifications. For functions that call external APIs, include a sample request and response:

// Example: REST API response structure
GET /api/users/{id}
Response (200):
{
"id": 123,
"email": "[email protected]",
"created_at": "2026-01-15T10:30:00Z",
"profile": {
"name": "Alice",
"bio": "Software engineer",
"avatar_url": "https://example.com/avatar.jpg"
}
}

Error responses (400, 404, 500) return:
{
"error": "error_code",
"message": "human readable message"
}

Library Versions. Specify exact versions for libraries that matter (behavior changes between versions).

Project dependencies:
- Python 3.11 (no Python 3.10 compatibility needed)
- sqlalchemy 2.0.20 (use modern ORM patterns, not raw SQL)
- pydantic 2.0 (use Pydantic v2 validators, not v1)
- fastapi 0.104+

Database Schema. If your code interacts with a database, provide a schema snippet:

-- Users table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_active BOOLEAN DEFAULT true
);

-- Sessions table
CREATE TABLE sessions (
id UUID PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Design Patterns. Show examples of how your project structures classes, handlers, or responses:

# Example: Your project's error handling pattern
class APIResponse(BaseModel):
success: bool
data: dict | None = None
error: str | None = None

def handle_operation():
try:
result = do_work()
return APIResponse(success=True, data=result)
except ValueError as e:
return APIResponse(success=False, error=str(e))

Constraint Types to Specify

Performance constraints. Define speed and memory targets:

Performance requirements:
- Function must complete in <100ms for typical inputs (1000 items)
- Memory usage under 50MB
- Assume single-threaded context (no async)

Dependency constraints. Restrict which libraries can be used:

Constraints:
- No external dependencies (stdlib only)
- OR: May use requests library (already in requirements.txt)
- OR: May use numpy, pandas (data science libraries already available)

Compatibility constraints. Specify target platforms and backward-compatibility needs:

Constraints:
- Target Node.js 18+ (no need for Node 16 compatibility)
- Browser support: Chrome 100+, Safari 15+, Firefox 95+ (no IE11)
- Mobile: React Native compatible (use cross-platform APIs)

Code style constraints. Reference your style guide or linter configuration:

Code style:
- Follow Black (line length 88)
- mypy strict mode (all type hints required, no Any)
- No magic numbers (extract to named constants)
- Docstrings for every public function/class

Real Example: Database Query Function with Full Context

Here's a realistic prompt with integrated context:

**Project Context**
Language: Python 3.11
Framework: FastAPI with SQLAlchemy 2.0
Database: PostgreSQL 14+
Error handling: Custom exception DatabaseError for all DB failures

Existing pattern (from queries/user.py):
```python
from sqlalchemy import select, Session
from app.models import User
from app.exceptions import DatabaseError

async def get_user_by_id(session: Session, user_id: int) -> User | None:
try:
stmt = select(User).where(User.id == user_id)
result = session.execute(stmt)
return result.scalar_one_or_none()
except Exception as e:
raise DatabaseError(f"Failed to fetch user: {str(e)}")

Task Write a function list_active_users(session: Session, limit: int = 100) -> list[User] that:

  1. Fetches all users with is_active=True
  2. Orders by created_at DESC (newest first)
  3. Limits to the specified count
  4. Uses the same SQLAlchemy pattern as get_user_by_id above
  5. Raises DatabaseError on failure
  6. Includes a docstring with example usage

Constraints

  • Query must execute in <50ms on a typical PostgreSQL database with 100k users
  • No N+1 queries (load relationships eagerly if needed)
  • Match the code style of the existing get_user_by_id function

Notice how this prompt:
1. Shows the existing code pattern the AI should follow
2. Specifies the exact libraries and versions
3. References custom exceptions and data types
4. Includes a performance target
5. Explains architectural concerns (N+1 queries)

## Context Dos and Don'ts

| Do | Don't |
|---|---|
| Include 50–150 lines of related project code | Paste your entire codebase (overwhelming) |
| Reference your style guide or linter config | Assume the AI knows your style from one example |
| Provide sample API responses (actual JSON) | Describe API responses in prose ("it returns user data") |
| Specify library versions that matter | List every dependency in your requirements.txt |
| Note architectural constraints (performance, security) | Bury constraints in requirement descriptions |
| Ask for code that matches existing patterns | Ask the AI to invent a new pattern for your codebase |

## Handling Sensitive Context

If your codebase contains credentials, proprietary algorithms, or sensitive data:

1. Redact credentials and API keys (replace with `<REDACTED>`)
2. Generalize proprietary algorithms (describe the behavior, not the exact implementation)
3. Avoid sharing customer data or internal metrics

Example of safe redaction:

```python
# Bad (contains credential):
api_key = "sk-proj-1a2b3c4d5e6f7g8h9i0j"
client = OpenAI(api_key=api_key)

# Good (redacted):
api_key = "<REDACTED>" # Loaded from environment variable
client = OpenAI(api_key=api_key)

Key Takeaways

  • Context dramatically improves code generation quality (up to 52% better correctness).
  • Use the context sandwich: general requirements, project-specific context, code to generate, expected style.
  • Include existing code snippets, API specs, database schemas, and library versions.
  • Specify performance, dependency, compatibility, and code-style constraints.
  • Redact sensitive data before sharing context with the AI model.

Frequently Asked Questions

How much existing code should I include?

Include 50–150 lines of the most relevant code. If including more helps (e.g., to show a pattern used in multiple files), go up to 300 lines. Beyond that, the AI model may struggle to focus on your actual request.

Should I include my entire database schema?

Include only the tables and columns relevant to the task. If you're writing a function to query users, include the users table and any related tables (roles, sessions). Skip unrelated tables (products, orders) to keep the context focused.

What if my project uses an unusual library or custom framework?

Include a brief explanation and example of how it's used. For custom frameworks, paste a sample usage pattern and explain the core concepts. The AI model will adapt to unfamiliar patterns if you show concrete examples.

Can I include context as a comment in the generated code?

Yes, but conditionally. If the context is a one-liner (e.g., "uses our custom Logger class"), include it as a comment. For longer context (API schema, design patterns), include it in your prompt but not as comments in the expected output—otherwise the generated code becomes cluttered.

How do I update context as my project evolves?

Keep a context template file in your project repo (e.g., docs/code-generation-context.md). Update it whenever you change major libraries, patterns, or conventions. When generating code, copy the current context into your prompt. Version the template alongside your codebase.

Further Reading