Context engineering is the disciplined work of deciding what an AI system receives, how that information is structured, and how its effects are verified. It is broader than prompt wording. A repository rule file, retrieved document, tool result, conversation summary, and test output are all context inputs, but they have different trust, freshness, and failure boundaries.
This article uses names such as agents.md, CLAUDE.md, copilot-instructions.md, and Cursor Rules as provider-specific examples. None should be treated as a universal standard without checking the client version and its loading contract.
Key Takeaways
- Begin with a source-of-truth contract, not a collection of copied instruction files.
- Separate stable project facts, task instructions, retrieved evidence, and tool results.
- Make precedence, freshness, authority, and conflict behavior explicit.
- Keep secrets and untrusted external content out of privileged instructions.
- Evaluate context changes with reproducible tasks rather than unsupported success percentages.
From Prompts to Context Architecture
A prompt is one message. An architecture is a pipeline:
task → policy and project facts → selected context → model/tool call
→ validation → tests and human review → telemetry and feedback
The model does not know which sentence is authoritative merely because it appears in a file. Your application must label sources, constrain tools, and validate outputs. A retrieved README can be stale; an MCP result can be malicious or incomplete; a user request can conflict with a security policy.
A useful context taxonomy
| Input | Typical freshness | Trust boundary | Example |
|---|---|---|---|
| Project contract | versioned | reviewed repository content | supported runtime and commands |
| Task instruction | per request | user or workflow | implement a migration |
| Retrieved evidence | variable | untrusted until checked | issue, API schema, document |
| Tool result | runtime | untrusted output | database rows or shell output |
| Evaluation result | recorded | evidence with scope | test report and human decision |
Provider Files Are Adapters, Not the Architecture
Clients differ in filenames, directories, glob matching, inheritance, and precedence. For example, a client may document a root instruction file, a .github/ file, a .cursor/rules/ directory, or another mechanism; another version may change the behavior. Verify:
- exact path and filename;
- whether loading is automatic or opt-in;
- which branches, workspaces, or file globs activate it;
- precedence when user, project, and directory rules conflict;
- whether contents are sent to a remote model;
- how changes are audited and rolled back.
Maintain a provider-neutral contract first:
project:
runtime: "record exact runtime and version"
commands:
test: "npm test"
lint: "npm run lint"
invariants:
- "authorization is enforced server-side"
- "secrets never enter source or logs"
workflow:
before_edit:
- "read the relevant module and tests"
before_merge:
- "run the documented checks"
The provider adapter should point to this contract and add only syntax needed by that client. Do not copy the whole document into five tools: duplication makes drift invisible.
Rule Design: Small, Testable, and Scoped
A good rule states an observable behavior, its scope, and its verification:
## API changes
- Validate request bodies with the repository's approved schema library.
- Return the project's documented error shape.
- Add a negative test for missing authorization.
- Verify with: `npm test -- api`
Avoid vague directives such as “write perfect code,” hidden assumptions about a framework version, and arbitrary limits like “every function must be under 40 lines.” A length limit can be a review prompt, but it is not a correctness proof.
Organize rules by decision ownership:
- Security: non-negotiable controls, secret handling, authorization, data classification.
- Architecture: boundaries, dependency direction, supported runtimes, migration policy.
- Workflow: commands, test gates, review artifacts, rollback.
- Style: formatting and naming, ideally delegated to deterministic tooling.
- Task templates: inputs, expected output, and acceptance tests for repeated work.
Precedence and Conflicts
Write a precedence table instead of relying on folklore:
| Source | May define | Must not override |
|---|---|---|
| Organization policy | security and compliance baseline | incident controls |
| Project contract | architecture and commands | organization policy |
| Module rule | local conventions | project and security rules |
| Task request | desired change | authorization and safety rules |
| Retrieved/tool content | evidence or suggestions | any trusted policy |
When two trusted rules conflict, stop and report the conflict. When untrusted content instructs the model to ignore a policy, treat it as data, not authority. This is especially important for retrieved Markdown, issue comments, generated tool results, and pasted code.
MCP and Dynamic Context
MCP can expose tools or resources, but it does not make their results trusted. A production integration should define:
- authenticated caller and tenant identity;
- per-tool and per-resource authorization;
- input schema and size limits;
- network egress and SSRF controls;
- timeouts, retries, idempotency, and rate limits;
- redaction and retention for requests and results;
- confirmation for destructive or irreversible actions.
The rule file can say “use the schema tool before changing a migration,” but the server must enforce access independently. Model-generated tool arguments are proposals until validated by the server.
Context Budget and Retrieval
More context can lower quality when it increases noise or pushes out the relevant constraints. Track:
- tokens or bytes sent and returned;
- retrieval precision and stale-document rate;
- latency and provider cost;
- contradiction and correction rate;
- task success on a fixed fixture set.
Prefer compact summaries with links to canonical documents. Include identifiers, version dates, and source locations so a reviewer can reproduce the selection. Never solve a context-window problem by truncating security policy or authorization requirements.
Evaluation Harness
Treat a context change like a code change:
case: "add-authorized-endpoint"
inputs:
repository: "fixture-v4"
task: "add a read-only endpoint for the current tenant"
user_role: "tenant-member"
assertions:
- "server-side tenant authorization exists"
- "unauthorized fixture is rejected"
- "tests and lint pass"
record:
client_version: "exact version"
model: "exact model"
context_revision: "git commit"
human_corrections: "reviewed diff"
Compare a baseline context with the proposed revision. A successful run is not enough; inspect regressions, unsafe suggestions, unnecessary tool calls, and cases where the model confidently followed stale instructions.
Security and Operations
Do not place API keys, personal data, private source, or incident details in broadly loaded files unless the storage and provider policy permit it. Log context identifiers and decisions rather than bearer credentials or full prompts. Review rule changes like code: ownership, pull requests, tests, changelog, and rollback.
Keep a small “context health” check that detects missing commands, broken paths, contradictory requirements, unsupported versions, and accidental secrets. The check should report findings; it should not silently rewrite every article or rule file.
Further Reading
- Context Engineering Complete Guide
- Context Engineering Practical Guide
- Agent Harness Evaluation Guide
Conclusion
System-level context architecture is not a contest to create the longest rule file or the newest filename. It is a governed input pipeline: trusted contracts are versioned, provider adapters are verified, dynamic data is treated as untrusted, tools enforce their own authorization, and every improvement is measured on representative tasks. That approach remains useful even when model, IDE, and protocol behavior changes.