Context Engineering
Context engineering provides AI agents with rich, structured external reference materials to improve reasoning and decision-making.
1. Overview
Context engineering is the practice of providing AI agents with "the right information, at the right time, in the right format." For autonomous development agents, this means gathering external documentation, API specifications, examples, and best practices before agent execution.
The VendirContextAdvisor
implements the "Select Context" strategy using vendir to declaratively fetch external content into the agent’s workspace.
2. Why Context Engineering?
Most agent failures are context failures, not model failures. Agents make better decisions when they have access to:
-
Framework documentation - Understanding APIs and patterns
-
API specifications - Correct usage of external services
-
Best practices - Industry-standard approaches
-
Examples - Real-world usage patterns
Without proper context, agents may:
-
Hallucinate non-existent APIs
-
Use deprecated patterns
-
Miss important conventions
-
Make suboptimal architectural decisions
3. Context Engineering vs RAG
A fundamental shift is happening in AI systems: direct context engineering is replacing traditional RAG (Retrieval-Augmented Generation) with vector stores for many agent workflows.
3.1. The Shift from Vector Search to File Access
Traditional LLM applications use vector stores and embedding-based similarity search. Agent systems are shifting to direct file access and navigation.
3.1.1. Sources Supporting This Shift
1. Anthropic Engineering Blog
In Building Agents with the Claude Agent SDK, Anthropic explains:
Rather than relying on vector similarity search, agents can directly access codebases, search files with grep, and navigate directory structures—providing more precise and reliable context than approximate embeddings.
2. Latent Space Podcast with LangChain
Harrison Chase (founder of LangChain) discusses how file-based context is replacing traditional semantic search for agent workflows in this podcast: Latent Space: Context Engineering
The observation from LangChain—a framework that pioneered vector-based RAG—validates this architectural shift toward direct file access for agents. |
3.2. Why Context > RAG for Agents
Aspect | Traditional RAG | Context Engineering |
---|---|---|
Retrieval |
Vector similarity search |
Direct file access + grep |
Accuracy |
Approximate (embeddings) |
Exact (string matching) |
Recall |
Top-k results (~80-90%) |
Perfect (grep finds all matches) |
Complexity |
Vector DB + embeddings + chunking |
File system operations |
Agent Fit |
Static retrieval |
Dynamic navigation |
Latency |
Embedding + vector search |
Native OS operations (faster) |
Infrastructure |
Vector database, embedding API |
File system only |
3.3. Example: Testing Spring Data JPA
Traditional RAG Approach:
// ❌ Complex: Vector store + embeddings + chunking
VectorStore vectorStore = new PgVectorStore(...);
// Embed all documentation
List<Document> docs = loadSpringDocs();
vectorStore.add(docs);
// Query with similarity search
List<Document> results = vectorStore.similaritySearch(
SearchRequest.query("How to test Spring Data JPA repositories?")
.withTopK(5)
.withSimilarityThreshold(0.8)
);
// Hope the right docs are in top-5...
// Might get generic testing docs, might miss @DataJpaTest specifics
Context Engineering Approach:
// ✅ Simple: Agent explores directly
AgentClientResponse response = agentClientBuilder
.goal("Write tests for UserRepository using Spring Data JPA best practices")
.workingDirectory(projectRoot)
.advisors(
VendirContextAdvisor.builder()
.vendirConfigPath("vendir-spring-boot.yml")
.build()
)
.call();
// Agent dynamically:
// 1. grep -r "@DataJpaTest" docs/
// 2. Find test examples in fetched Spring Boot repo
// 3. Read UserRepository.java to understand entity
// 4. Navigate to Spring Data JPA testing docs
// 5. Write tests following discovered patterns
3.4. Benefits of Context Engineering
3.4.1. Perfect Recall
grep
finds all matches, not approximate top-k:
# Agent can do this:
$ grep -r "OAuth2" docs/
# Finds EVERY occurrence
# vs Vector search top-5 (might miss important results)
3.4.2. Dynamic Navigation
Agents can follow references:
1. Find "@Configuration" classes
2. Notice import for OAuth2ClientConfig
3. Navigate to OAuth2ClientConfig.java
4. Read implementation details
5. Follow to examples
Vector search: Static top-k results
Agent: Dynamic navigation following code references
3.4.3. No Embedding Overhead
Traditional RAG:
1. Chunk documents
2. Generate embeddings (API calls + cost)
3. Store in vector DB
4. Query with embeddings (more API calls)
5. Post-process results
Context Engineering:
1. Give agent file access
2. Agent uses grep/find (instant, free)
3.4.4. Simpler Architecture
Traditional RAG Stack:
┌─────────────────┐
│ Application │
└────────┬────────┘
│
┌────────▼────────┐
│ Vector Store │
│ (Postgres + │
│ pgvector) │
└────────┬────────┘
│
┌────────▼────────┐
│ Embedding API │
│ (OpenAI/etc) │
└─────────────────┘
Context Engineering Stack:
┌─────────────────┐
│ Application │
└────────┬────────┘
│
┌────────▼────────┐
│ File System │
└─────────────────┘
(That's it!)
3.5. When RAG Still Makes Sense
Context engineering doesn’t replace RAG everywhere:
Use Context Engineering When:
-
✅ Working with codebases (files have structure)
-
✅ Need exact file/directory navigation
-
✅ Agent can explore dynamically
-
✅ Documents have references (imports, links)
-
✅ Precision is critical (no false positives)
Use RAG When:
-
✅ Searching across massive unstructured corpora
-
✅ Need semantic similarity (not exact match)
-
✅ Content doesn’t have file/code structure
-
✅ One-shot retrieval (no navigation needed)
-
✅ User queries are semantic ("find documents about…")
3.6. Context Engineering in Practice
VendirContextAdvisor implements context engineering by fetching relevant documentation into the agent’s workspace:
// Fetch Spring Security documentation
VendirContextAdvisor advisor = VendirContextAdvisor.builder()
.vendirConfigPath("vendir.yml")
.build();
AgentClientResponse response = agentClientBuilder
.goal("Implement OAuth2 login following Spring Security best practices")
.advisors(advisor)
.call();
// Agent has direct file access to:
// - Spring Security reference docs
// - Code examples
// - Configuration templates
// - Migration guides
// Agent can grep, navigate, read—no vector store needed
4. VendirContextAdvisor
The VendirContextAdvisor
automatically gathers external context before agent execution using vendir configuration files.
4.1. Basic Usage
// Create vendir configuration
Path vendirConfig = createVendirConfig(); // vendir.yml
// Create advisor
VendirContextAdvisor advisor = VendirContextAdvisor.builder()
.vendirConfigPath(vendirConfig)
.contextDirectory(".agent-context/vendir")
.build();
// Register with AgentClient
AgentClient client = AgentClient.builder(agentModel)
.defaultAdvisor(advisor)
.build();
// Execute - context is gathered automatically before agent runs
AgentClientResponse response = client.run(
"Implement Spring Boot actuator health endpoint following best practices"
);
4.2. Vendir Configuration
Create a vendir.yml
file specifying what external content to fetch:
apiVersion: vendir.k14s.io/v1alpha1
kind: Config
directories:
- path: vendor
contents:
# Clone entire repository
- path: spring-guide
git:
url: https://github.com/spring-guides/gs-rest-service
ref: main
depth: 1 # Shallow clone for efficiency
# Fetch specific paths
- path: spring-boot-docs
git:
url: https://github.com/spring-projects/spring-boot
ref: v3.3.0
depth: 1
includePaths:
- README.adoc
# HTTP source
- path: api-specs
http:
url: https://example.com/api-spec.yaml
For complete vendir configuration options, see the official vendir documentation.
5. Configuration Options
5.1. Context Directory
Specify where context files are placed:
VendirContextAdvisor advisor = VendirContextAdvisor.builder()
.vendirConfigPath("vendir.yml")
.contextDirectory(".agent-context/vendir") // Default
.build();
Context files are placed in {workingDirectory}/.agent-context/vendir/vendor/
.
5.2. Timeout
Configure how long vendir has to fetch content:
VendirContextAdvisor advisor = VendirContextAdvisor.builder()
.vendirConfigPath("vendir.yml")
.timeout(300) // 5 minutes (default)
.build();
6. Context Metadata
The advisor adds metadata to request/response contexts for observability:
AgentClientResponse response = client.run("Some goal");
// Check if context was gathered successfully
Boolean success = (Boolean) response.context().get("vendir.context.success");
String contextPath = (String) response.context().get("vendir.context.path");
String output = (String) response.context().get("vendir.context.output");
if (!success) {
String error = (String) response.context().get("vendir.context.error");
logger.warn("Context gathering failed: {}", error);
}
7. Examples
7.1. Clone Entire Repository
apiVersion: vendir.k14s.io/v1alpha1
kind: Config
directories:
- path: vendor
contents:
- path: spring-guide
git:
url: https://github.com/spring-guides/gs-rest-service
ref: main
depth: 1
VendirContextAdvisor advisor = VendirContextAdvisor.builder()
.vendirConfigPath("vendir.yml")
.build();
AgentClient client = AgentClient.builder(agentModel)
.defaultAdvisor(advisor)
.build();
client.run("Based on the Spring guide, create a similar REST service for products");
8. Spring Boot Integration
Register as a Spring bean for automatic configuration:
@Configuration
public class ContextEngineeringConfig {
@Bean
public VendirContextAdvisor vendirContextAdvisor() {
return VendirContextAdvisor.builder()
.vendirConfigPath("context/vendir.yml")
.contextDirectory(".agent-context")
.timeout(300)
.autoCleanup(false)
.build();
}
@Bean
public AgentClient agentClient(
AgentModel agentModel,
VendirContextAdvisor contextAdvisor) {
return AgentClient.builder(agentModel)
.defaultAdvisor(contextAdvisor)
.build();
}
}
9. Error Handling
The advisor handles failures gracefully:
-
Vendir not installed - Logs error, agent continues without context
-
Network failures - Logs error, agent continues without context
-
Invalid configuration - Logs error, agent continues without context
-
Timeout - Logs error, agent continues without context
Failures are recorded in the context for observability:
AgentClientResponse response = client.run("Some goal");
if (!(Boolean) response.context().get("vendir.context.success")) {
String error = (String) response.context().get("vendir.context.error");
// Handle degraded execution
}
10. Tips
-
Use
depth: 1
for faster shallow clones -
Use
includePaths
to fetch only relevant files -
Keep
autoCleanup: false
during development to inspect gathered context -
Adjust timeout based on repository size
11. Related Concepts
-
Agent Advisors - Complete advisor pattern documentation
-
AgentClient - High-level client API
-
Judge Concept - Post-execution validation
Context engineering transforms autonomous agents from isolated tools into context-aware developers that understand and respect external APIs, frameworks, and best practices.