Context, not prompts. The missing piece in effective AI-assisted development
This article describes the initial release of Context Generator as a PHP library. Since publication, the tool has evolved significantly into a standalone CLI application with enhanced features and simpler installation. For the most up-to-date information and instructions, please read the updated article: Context, Not Prompts [2.0]: The Evolution. The new version includes a one-line installer, improved JSON configuration, and powerful new features that make it accessible to all developers, not just PHP users.
After using ChatGPT and Claude daily for the past year as part of my development workflow, I’ve learned one crucial lesson: context is everything. The quality of AI’s help directly depends on how much relevant information I feed it.
But managing that context quickly became my biggest headache. My approach evolved through several frustrating stages:
- The copy-paste nightmare: Initially, I’d just copy-paste files directly into the chat window. For small tasks, this was manageable, but it quickly became unwieldy for anything complex.
- Using Claude’s projects feature: When Claude introduced the ability to attach files, I started creating projects with relevant attached code files. This helped, but I still had to manually select which files to include each time.
- Manual context documents: Next, I began combining related files into single documents to reuse in different conversations. I’d spend evenings creating these context files, carefully formatting them so the AI could understand file boundaries.
- Multi-iteration headaches: When working on complex features that required multiple brainstorming sessions, I’d have to constantly update these context documents as my code evolved, manually combining files again and again.
- Primitive automation: I created a basic console command where I could paste directories and files that I wanted to combine. It was better than manual work, but still cumbersome.
I was spending more time managing context than actually coding. And this wasn’t a one-time issue — I write code constantly, and after every meaningful change, I’d need to rebuild my context again and again throughout the day.
- Make a change to the service class? Rebuild context!
- Add a new model property? Rebuild context!
- Refactor an interface? Rebuild context!
This endless cycle of context rebuilding was killing my productivity. Something had to change.
That’s why I built Context Generator, a PHP tool that automates collecting and formatting context from your codebase. It’s become an essential part of my workflow, and I want to share how it can transform yours too.
The context problem
As I watch new prompt engineers join our team, I see them struggling with the same challenges I faced at the beginning. Here’s what happens to them almost daily:
- They start a conversation with AI about writing a code
- They paste a few code snippets, trying to be efficient
- The AI gives a generic solution that doesn’t make sense
- They paste more code, trying to explain our project structure
- The AI gets confused about how files relate to each other
- They copy-paste even more files, add explanations, and lose track of what they’ve already shared
- By this point, they’ve spent 30+ minutes just trying to get the AI to understand our codebase
One developer recently told me:
I’m so disappointed with AI tools. I spent hours trying to get it to understand our codebase, and when it finally gave me a solution, it referenced classes we don’t even have. What a waste of time.
So, I released a package inside our private GitLab repository and taught them how to use it. And you know what happened?
The same developer who had called AI “useless” came to me a week later with a completely different attitude.
I just built an entire feature using Claude. OMG!
Others had similar experiences. Our team’s overall productivity jumped as they spent less time fighting with context management and more time leveraging AI for actual problem-solving.
How it solved my problem
The solution I built is simple but powerful: a tool that automatically collects code from specified files or directories, formats everything neatly, and generates a single document or multiple documents I can share with AI.
Here’s what a typical context configuration looks like:
<?php
use Butschster\ContextGenerator\Document;
use Butschster\ContextGenerator\DocumentRegistry;
use Butschster\ContextGenerator\Source\FileSource;
use Butschster\ContextGenerator\Source\TextSource;
return (new DocumentRegistry())
->register(
Document::create(
description: 'Auth System Refactoring',
outputPath: 'contexts/auth-refactoring.md',
)
->addSource(
// I can add custom explanations
new TextSource(
content: "# Auth System Refactoring\n\nI need to simplify our login flow and add support for social logins. The current system has too much duplicated code.",
description: 'Refactoring Goals',
),
// Add entire directories of code
new FileSource(
sourcePaths: __DIR__ . '/src/Auth',
description: 'Authentication Components',
filePattern: '*.php',
excludePatterns: ['tests'],
showTreeView: true,
),
// Or specific files
new FileSource(
sourcePaths: [
__DIR__ . '/src/Models/User.php',
__DIR__ . '/src/Services/EmailService.php',
],
description: 'Related Models and Services',
),
),
);
Then I run a simple command:
./vendor/bin/context-generator generate
And it creates a formatted file that includes:
- A directory tree showing the structure of my code
- All the specified files with clear boundaries and formatting
- My custom notes and questions
Now I can just attach this file to ChatGPT or Claude project and instantly have a productive conversation.
How to get started
If you want to try this tool in your own workflow, here’s how to get started:
Installation
composer require butschster/context-generator --dev
Basic Setup
Create a file named context.php
in your project root:
<?php
use Butschster\ContextGenerator\Document;
use Butschster\ContextGenerator\DocumentRegistry;
use Butschster\ContextGenerator\Source\FileSource;
use Butschster\ContextGenerator\Source\TextSource;
return (new DocumentRegistry())
->register(
Document::create(
description: 'My First Context',
outputPath: 'contexts/my-context.md',
)
->addSource(
new TextSource(
content: "# My Project\n\nThis is my project structure and key files.",
description: 'Project Overview',
),
new FileSource(
sourcePaths: __DIR__ . '/src',
description: 'Source Code',
filePattern: '*.php',
excludePatterns: ['tests', 'vendor'],
showTreeView: true,
),
),
);
Or if you prefer JSON create a file named context.json
in your project root:
{
"documents": [
{
"description": "My First Context",
"outputPath": "contexts/my-context.md",
"sources": [
{
"type": "text",
"description": "Project Overview",
"content": "# My Project\n\nThis is my project structure and key files."
},
{
"type": "file",
"description": "Source Code",
"sourcePaths": ["src"],
"filePattern": "*.php",
"excludePatterns": ["tests", "vendor"],
"showTreeView": true
}
]
}
]
}
Generate Context
Run the command:
./vendor/bin/context-generator generate
Your context file will be generated at the specified output path.
My tips for effective context
After a year of refining my approach, here are my top tips for creating effective context for AI:
Be specific about problems
Include a clear description of what you’re trying to achieve or fix. For example: “I need to refactor this authentication service to support both password and OAuth logins while maintaining backward compatibility with existing sessions.”
Include both interfaces and implementations
This helps AI understand both the contract and the actual code. Seeing UserRepositoryInterface
alongside a concrete DatabaseUserRepository
gives AI a complete picture of your architecture and design patterns.
Focus on interfaces and relevant DTOs
For large systems, sometimes you only need to include the interfaces and data transfer objects. This approach works well when you want AI to understand your domain model without getting lost in implementation details.
// Include contracts like this
interface PaymentGatewayInterface
{
public function processPayment(PaymentRequest $request): PaymentResponse;
}
// Along with the DTOs they use
class PaymentRequest
{
public function __construct(
public readonly string $transactionId,
public readonly float $amount,
public readonly string $currency,
// ...
) {}
}
Don’t include everything
Only add files relevant to your current task to avoid exceeding token limits. Remember AI assistants have around 150,000 tokens for both input and output combined. For a complex application, including your entire codebase could easily exceed this limit.
Add custom notes
Use TextSource
to explain non-obvious parts of your code or specific requirements.
For example: “This legacy payment processor must remain backward compatible with our on-premise system. Any changes must maintain the same method signatures and return types.”
Create task-focused contexts
Instead of organizing by feature, create contexts specifically tailored to the task at hand. For a cart checkout issue, include only cart, product, and payment-related files rather than the entire e-commerce system.
// context.php for checkout flow debugging
return (new DocumentRegistry())
->register(
Document::create(
description: 'Cart Checkout Flow',
outputPath: 'checkout-debugging.md',
)
->addSource(
new TextSource(
content: "# Checkout Bug Investigation\n\nUsers report seeing 'payment failed' errors when using American Express cards, though payments complete successfully.",
),
new FileSource(
sourcePaths: [
__DIR__ . '/src/Services/Cart',
__DIR__ . '/src/Services/Payment',
__DIR__ . '/src/Models/Order.php',
],
),
),
);
Update context as you progress
Regenerate context when you make significant changes to your code. This keeps AI in sync with your evolving solution, especially during multi-day refactoring projects.
What Next?
What if we had a service similar to Packagist, but dedicated to hosting and serving context files?
Let’s call it “ContextHub” for now.
This service would:
- Index context files from registered packages: When you publish a new version of your package, ContextHub automatically pulls your updated
context.json
. - Generate standardized context documents: The service would process these configurations and create optimized context files tailored for different AI assistants.
- Provide an API for development tools: Your IDE could fetch the context for any package you’re working with via a simple API call.
Imagine typing a command like:
context-hub get symfony/http-kernel laravel/framework
And immediately receiving a perfectly formatted context files.
The beauty of this approach is that package authors decide what matters. As the creator of a library, you know best which parts of your codebase are essential for understanding its usage. You might choose to include:
- Only public-facing interfaces and DTOs for a clean API-focused context
- Example usage patterns with explanations
- Key implementation details for advanced integration scenarios
- Architecture diagrams or explanations as text sources
For instance, a complex ORM package might provide several different context documents:
{
"documents": [
{
"description": "Basic Usage Guide",
"outputPath": "contexts/basic-usage.md",
"sources": [
{
"type": "file",
"description": "Core interfaces",
"sourcePaths": ["src/Entity", "src/Repository"]
}
]
},
{
"description": "Advanced Query Building",
"outputPath": "contexts/query-building.md",
"sources": [
{
"type": "file",
"description": "Query Builder Components",
"sourcePaths": ["src/QueryBuilder"]
}
]
}
]
}
This empowers library authors to carefully curate the context that best represents their package, focusing on what developers actually need to know rather than overwhelming them with implementation details. It’s about distilling expertise into focused, useful contexts — exactly what makes AI assistants most effective.
The Context Generator package you’re already using could evolve to become the foundation of this ecosystem.
Conclusion: Context changes everything!
After using Context Generator daily for months, I can’t imagine working with AI assistants without it. The quality of AI help has dramatically improved because I’m giving it complete, relevant context without the busy work.
What started as a simple tool to solve my personal frustration has become an essential part of my development workflow.
The relationship between context quality and AI output is so direct that I consider context management a core skill for the AI-assisted developer.
If you work with AI tools regularly, I highly recommend setting up a similar approach.
The developers who master context management today will be the ones who most effectively harness the power of AI assistance tomorrow.
In a world where AI is becoming an essential development partner, context isn’t just king — it’s the entire kingdom.