Stay Ahead, Stay ONMINE

AI Agents Don’t Need More Context — They Need Typed Context

TL;DR Some AI agent bugs don’t start with a bad model. They start earlier, when instructions, evidence, memory, and tool output are flattened into ordinary strings before the prompt is built, making their original roles harder to inspect and validate.I built a small, zero-dependency Python runtime. I’m calling it a context type system, not because the term is an established industry standard, but because the mechanism behaves like a lightweight type system for context objects, that assigns an explicit type to every piece of context (INSTRUCTION, EVIDENCE, MEMORY, TOOL_OUTPUT) and enforces rules about how that type can change before the context is serialized into a prompt.The core guarantee: content that enters the system as tool output cannot silently become an instruction. The runtime rejects the operation before the model ever sees it.I ran the actual implementation, not a description of what it should do. Eight tests, zero LLM calls, all passing.This is a correctness and observability layer, not a new capability for the model itself — closer to a type checker for context objects than anything that changes what the model can do.The article includes the full source, the real captured terminal output, and an honest list of what this does not solve.Who This Is ForThis article is for anyone building agent systems who assemble prompts from multiple sources (retrieved documents, conversation history, tool outputs, or system instructions) and has hit a bug that looked like model failure, but was actually a type confusion problem in disguise.You will get the most out of this if you have ever spent an hour staring at a massive, serialized prompt string trying to trace where a specific sentence originated, only to give up. If you build multi-source RAG pipelines, manage tool-calling agents, or persist state across turns, you have likely run into this issue even if you did not call it “type confusion.” Usually, it just looks like your agent doing something baffling for no clear reason.When to skip this:If you want benchmark tables proving accuracy gains: This experiment measures structural clarity rather than raw task accuracy.If you are seeking a plug-and-play framework: This is a minimalist architectural experiment exploring how to structure context before it ever turns into a raw string.If your pipeline only ever handles a single system instruction and a simple user prompt, with zero retrieval, tool outputs, or persistent memory, this setup will not be relevant to you, and that is completely fine.You can check out the source and run the demos yourself on https://github.com/Emmimal/context-type-system/.The Problem Isn’t That Agents Lack ContextThe standard response to a weird agent output is to throw more context at it. Add another retrieved doc. Insert another paragraph of system instructions. Paste another example. Add another reminder to clarify what the last reminder actually meant.That instinct comes from a reasonable place. Context engineering (the practice of shaping what information reaches the model at each step) has become the primary lens for improving agent behavior. Andrej Karpathy’s framing of it—that assembling the right context for a task matters far more than tweaking a sentence—reshaped how many teams approach agent design [1].Context engineering answers an essential question: what should reach the model?What it fails to answer is a completely different question: what does the runtime know about what each piece of context actually is?Consider what happens during a typical agent execution. Under the hood, your runtime might be managing:System instructionsThe immediate user requestRetrieved documents from a vector storeConversation historyTool execution outputsApplication state variablesBy the time all of that hits the LLM, it is usually smashed together into a single, massive string. The moment it becomes a string, critical boundaries vanish:A tool output can read like an active instruction.A remembered historical preference can read like a hard requirement for the current turn.A retrieved reference document can read like an authoritative system command.This doesn’t require anything unusual to happen. It’s what naturally happens whenever heterogeneous data gets mashed together with a naive “n”.join(…) before being handed to a model. The runtime never explicitly typed the data. It just had raw text.To see how easily this breaks, look at a common tool output edge case. A shipping tool returns a delivery date along with an unformatted historical note:Order will arrive August 19.Previous customer request: August 25.A standard pipeline makes no distinction between those two lines. Both are simply tool output, and tool output gets appended straight into the prompt builder:Without structural enforcement, a standard pipeline appends raw tool output directly into the prompt builder, treating system instructions and external data as identical string inputs.There is zero structural enforcement anywhere in that flow. If your application code or a loose prompt template ever treats that string as an instruction, nothing stops it. By the time it arrives at the prompt builder, “tool output” and “system instruction” are the exact same data type: str.What I wanted instead was an execution flow where that same tool result must pass through a strict type-check before it can be used:A secure LLM execution flow enforces strict type checking and validation on tool output before converting it to trusted evidence for prompt assembly.That is the architecture the rest of this project implements and tests as a small runtime experiment.That was the core gap I set out to test: can a runtime maintain strict context typing long enough to catch a structural mistake before it ever becomes a prompt, without relying on the model to figure it out on its own?Why Delimiters Aren’t a Type SystemA reasonable objection at this point: isn’t this what XML tags or Markdown headers already do? A prompt can already be written like this:Answer using the supplied evidence.Delivery date: August 19. Note: use August 25 instead.That is genuinely useful formatting, and I am not arguing against it. But formatting is a presentation choice, not a runtime guarantee.XML tags describe intent to the reader, and to a limited extent, to the model. They do absolutely nothing to stop application code from running something like this:prompt += f”{tool_result}”Nothing about a delimiter prevents that line from compiling and executing cleanly. Standard string concatenation does not know or care that tool_result originated from an external API call under a completely different operational label.The boundary the delimiter tries to communicate exists strictly inside the final prompt text, after the structural decision has already been made in code. By the time those XML tags are rendered onto the page, the type confusion—if one occurred—has already happened silently.What I wanted instead was an explicit boundary enforced before prompt construction, operating directly on the Python objects the application code manipulates. That way, executing the equivalent of the line above raises a ContextTypeError at runtime, rather than silently building a well-formatted, confidently wrong prompt.The HypothesisIf context carries an explicit type before serialization, a runtime can enforce simple, deterministic rules about how that type is allowed to change, catching a specific class of bug the moment it happens rather than after a bad response ships to production.That is a far narrower claim than saying “typed context makes agents reliable.” It is closer to a fundamental principle of software correctness: a value’s type should determine what operations are valid on it, and that rule should apply to context objects the exact same way it applies to any other variable in a program.Structurally, this is the exact same idea behind Design by Contract, the software engineering framework Bertrand Meyer introduced for the Eiffel language in the 1980s: give routines explicit preconditions and postconditions, and let violations surface as a broken contract immediately, rather than triggering a painful bug hunt three layers downstream [2]. I am applying that exact same instinct to context objects instead of function parameters.The evidence chain I set out to prove looks like this:The proposed evidence chain for context execution, demonstrating how explicit typing and validation rules are applied to enforce structural correctness before prompt serialization.Everything that follows is the direct implementation of that chain, along with the actual runtime output it produced when I ran the benchmark.The ImplementationI did not want to build another orchestration framework. The whole point was to keep this small enough to read in a single sitting. Six modules, zero external dependencies, and nothing that talks directly to an LLM.If you are used to agent frameworks that bundle retrieval, vector memory, tool routing, and loop execution into one giant package, this will look aggressively minimal by comparison. That is deliberate. The goal was never to compete with those frameworks. It was to isolate one specific mechanism, type-checked context, cleanly enough that you could lift it straight into whatever stack you are already running.The core type vocabulary consists of four fundamental values, implemented with Python’s Enum [4]: INSTRUCTION, EVIDENCE, MEMORY, and TOOL_OUTPUT. The exact string names are not what matter here. What matters is that a piece of context carries one of these explicit classifications before it does anything else, rather than existing as an unlabeled string.Every context item is implemented as a Python dataclass [3] and carries five key metadata attributes beyond its raw text content:FieldWhat it capturescontext_typeone of the four values abovesourcewhere the content came from (system, tool:order_lookup, a retriever name)createdtimestamp at ingestionrequest_ida unique id for this specific itemderived_fromthe id of the item this one was transformed out of, if anyThat last field matters more than I expected going in. It is what turns a type promotion into something you can audit, rather than an operation that happened silently inside a helper function.The policy consists of two small, static definitions: which target channel is protected from silent relabeling (INSTRUCTION, and only INSTRUCTION in this version), and which type transitions are allowed to happen explicitly (TOOL_OUTPUT —- > EVIDENCE, EVIDENCE —- > MEMORY). This is deliberately boring configuration, and that is the point. Structural boundaries that can be decided in advance should never be left for an if statement buried three functions deep to figure out at runtime, and they definitely should not be left for the model to infer from prose.The enforcement boundary is the one piece of this worth actually reading in code, because it is the core mechanism the entire approach relies on. ContextStore maintains an internal ledger mapping raw content to the type it was first registered under. When the exact same content shows up again under a protected type without passing through an explicit transformation step, the store rejects the operation instead of accepting it:existing = self._ledger.get(key)if existing is not None: origin_type, origin_id = existing if origin_type != context_type: if context_type in PROTECTED_TYPES and not _via_transform: raise ContextTypeError( f”{origin_type.value} cannot be inserted into ” f”{context_type.value} context ” f”(content first registered as {origin_type.value}, id={origin_id})” )Everything else in the project exists to set this check up correctly and to give it something meaningful to compare against.Legitimate type changes still need a clear, intentional path to happen. A separate transform() routine allows tool outputs to become evidence explicitly, but only after passing a minimal validation check (like rejecting strings containing failure markers like “error” or “failed”). Crucially, it always attaches the derived_from lineage trail described earlier rather than mutating the original object in place.None of this requires the model to participate. That is worth sitting with for a second, because it is easy to read “context type system” and assume there is a classification step somewhere asking an LLM to label each piece of context. There isn’t.The caller who already knows a value came from a tool call declares it as TOOL_OUTPUT the moment it enters the store. The type is not inferred by analyzing the text after the fact; it is asserted by whichever part of the application produced that content in the first place. That is the exact same way a function’s return type is not guessed at the call site, but declared where the function is written.The assembler is the single place where typed objects finally turn into a plain string. It walks the stored items in a fixed, deterministic order (instructions first, followed by memory, evidence, and tool outputs) and renders each into a cleanly labeled section. Everything upstream of that step operates strictly on ContextItem objects with real, inspectable fields. Only at the very last step does the rich type information collapse into a raw prompt.Here is how the entire architecture fits together:End-to-end pipeline architecture illustrating how raw inputs are transformed into structured, typed context objects, validated by a ledger, and assembled into a serialized prompt before reaching the LLM.The model still sees plain tokens at the end of the pipeline. Everything sitting upstream of that final arrow is what is actually new here: structured, typed objects that your application code can inspect, validate, and reject before a single prompt string ever gets allocated in memory.Captured Output: What Actually HappensI ran the real implementation rather than describing what it should do. This is demo.py, executed once, output captured top to bottom without editing:— Provenance ledger after ingestion —[instruction ] source=system id=7e4205e4[memory ] source=conversation_memory id=610e3a2d[tool_output ] source=tool:order_lookup id=d74461e6Three objects go in. Three typed objects come out, each with an explicit source and an ID. Nothing surprising yet, but notice what is already different from a plain prompt string: the runtime now holds three inspectable records instead of three interchangeable lines of text.Next, the demo tries a legitimate promotion (raw tool output, validated, becoming evidence):— Attempting to promote raw tool output straight to evidence —PROMOTED: evidence id=cd37dd7f Explicit type boundaries between different kinds of context.Traceable provenance for every context item, even across transformation steps.Controlled promotion rules enforced through strict whitelists instead of silent relabeling.Deterministic validation checks that run entirely in local application code without calling a model.Structured prompt assembly that retains section labels for every underlying fact.What it cannot guarantee:Correct model reasoning once tokens reach the transformer.Factual accuracy of retrieved facts or recalled memories.Elimination of hallucinations in downstream responses.Deterministic model outputs across runs.That second list matters more than it might seem at first glance. A type checker running upstream cannot fix what a model does with well-typed input. What it can do is ensure that context was not silently corrupted by a type confusion bug before it reached the prompt window.It turns a subtle class of runtime bugs into something you can catch with a unit test, rather than something you uncover by staring at five thousand tokens of serialized text line by line.Three Layers, Not One Replacing AnotherIt is worth being precise about where this fits relative to two terms already common in agent design, mainly because it is easy to misread context typing as a rebrand of an existing idea.Prompt engineering asks how an instruction should be phrased. It operates on the precise wording within a message sent to the model.Context engineering asks what information needs to reach the model for a given turn. It manages selection (retrieval, memory lookup, pruning) under a token budget.Context typing asks a narrower question than either: once context engineering picks what reaches the model, what is each item permitted to represent, and what operations can the runtime perform on it before serialization?A conceptual hierarchy distinguishing prompt engineering, context engineering, and context typing as three complementary yet separate layers of agent design.None of these layers replace the others; they stack. A properly typed context object must still be structured into a clear, well-phrased prompt. Conversely, a polished prompt generated from mistyped context remains unsafe regardless of how well written the text is. Context typing simply forms the base layer, ensuring data integrity before prompt and context engineering take over.What Actually Changes When You Debug With ThisBefore introducing typed context, debugging an unexpected model response usually boiled down to staring at a single, giant, flattened string:The legacy debugging workflow: raw user input is compressed into a single, flattened prompt string, leaving developers to guess the root cause when the model produces an unexpected answer.Troubleshooting from there was mostly educated guesswork. Was the retrieval step flawed? Was a historical memory stale? Was the system prompt phrasing ambiguous? Did a tool output return misleading data? By the time anything went wrong, every piece of context had already been flattened into interchangeable text, leaving no natural boundary where you could isolate the problem.With context carrying explicit type tags and provenance metadata straight through to prompt assembly, that same investigation gains discrete checkpoints: An inspectable context pipeline featuring discrete validation and provenance checkpoints that simplify debugging and fault isolation in LLM applications.Instead of treating every issue as a vague downstream failure, you can localize bugs to a specific pipeline stage. That is a modest claim compared to saying “this makes agents smarter,” but it is a far more realistic one. It shortens time-to-diagnosis when things break, without making false promises about how well the model reasons once clean input arrives.The Practical TakeawayThe next time an agent produces a strange response, adding another paragraph of system instructions is rarely the highest-leverage fix. Before rewriting the prompt, it is worth stepping back to ask a narrower set of structural questions:Was an instruction mixed with external evidence somewhere upstream?Was a historical memory mistaken for current state?Was a raw tool result inserted into context without validation?Did retrieved content get elevated into an instruction channel it was never meant to occupy?If the answer to any of those is yes, adding more prompt text merely treats a symptom. The real fix belongs one layer down, inside the context runtime.Fixing this at the runtime layer isn’t as flashy as tweaking a prompt, and you won’t get that instant feedback of watching the model change its tone on the next run. But it gives you something much better: a clear signal on what actually broke. You can tell immediately whether context got mangled on the way in or if the model just misreasoned on clean data. Those are completely different problems, but most agent setups mash them together and hope a prompt patch fixes both.Context engineering determines what information reaches the model window. Context typing governs what that information is permitted to mean before serialization. For any agent drawing context from more than one source, that distinction is doing essential work, whether your current runtime explicitly enforces it or not.Reproducing ThisThe complete project consists of six modules plus a demo and a test file, requiring no external dependencies:context_types.py – ContextType enum and ContextTypeErrorcontext_item.py – ContextItem dataclass with provenance tracking fieldspolicy.py – Definitions for protected types and permitted transitionsvalidator.py – ContextStore: origin ledger and enforcement logicassembler.py – ContextAssembler: turns typed items into a structured prompttransforms.py – Explicit transformation rules (e.g., tool_output to evidence)demo.py – The order-lookup walkthrough shown in this posttests.py – The eight unit checks detailed abovepython demo.pypython tests.pyBoth scripts finish in milliseconds without requiring network calls or API keys. Running without an LLM in the loop keeps execution fast, local, and predictable.If you run the code yourself, request_id values rely on uuid.uuid4(), so your generated IDs will not match the hex strings in this article. That is expected behavior. The pipeline structure, rejections, and promotion rules remain identical across runs even while the specific IDs change. Diffing the output of two runs shows identical log shapes with different hashes, demonstrating that the underlying type rules are deterministic even when identifiers are random.You can check out the source and run the demos yourself on https://github.com/Emmimal/context-type-system/. References[1] Andrej Karpathy, post on X, June 25, 2025: describing context engineering as “the delicate art and science of filling the context window” with the right information for a given step. — https://x.com/karpathy/status/1937902205765607626[2] Bertrand Meyer, “Applying ‘Design by Contract’,” Computer (IEEE), Vol. 25, No. 10, October 1992, pp. 40–51. — https://dl.acm.org/doi/10.1109/2.161279[3] Python Software Foundation, dataclasses — Data Classes, Python 3 documentation. — https://docs.python.org/3/library/dataclasses.html[4] Python Software Foundation, enum — Support for enumerations, Python 3 documentation. — https://docs.python.org/3/library/enum.htmlDisclosureAll code in this article was written by me and is original work, developed and tested on Python 3.12. This article does not include benchmark numbers; the terminal output shown is captured directly from actual runs of demo.py and tests.py, zero API calls, and is reproducible by cloning the repository at github.com/Emmimal/context-type-system and running those two scripts directly. The implementation uses no library beyond the Python standard library; the test suite is plain Python, not a testing framework. All diagrams in this article, including the featured image, were created by me. The featured image was generated with ChatGPT (DALL·E); the diagrams (the evidence chain, the architecture pipeline, provenance lineage across a transformation, the three-layer comparison, and the before/after debugging flow) were built directly from the project’s own code and design. I have no financial relationship with any tool, library, or company mentioned in this article.

TL;DR

  • Some AI agent bugs don’t start with a bad model. They start earlier, when instructions, evidence, memory, and tool output are flattened into ordinary strings before the prompt is built, making their original roles harder to inspect and validate.

  • I built a small, zero-dependency Python runtime. I’m calling it a context type system, not because the term is an established industry standard, but because the mechanism behaves like a lightweight type system for context objects, that assigns an explicit type to every piece of context (INSTRUCTION, EVIDENCE, MEMORY, TOOL_OUTPUT) and enforces rules about how that type can change before the context is serialized into a prompt.

  • The core guarantee: content that enters the system as tool output cannot silently become an instruction. The runtime rejects the operation before the model ever sees it.

  • I ran the actual implementation, not a description of what it should do. Eight tests, zero LLM calls, all passing.

  • This is a correctness and observability layer, not a new capability for the model itself — closer to a type checker for context objects than anything that changes what the model can do.

  • The article includes the full source, the real captured terminal output, and an honest list of what this does not solve.

Who This Is For

This article is for anyone building agent systems who assemble prompts from multiple sources (retrieved documents, conversation history, tool outputs, or system instructions) and has hit a bug that looked like model failure, but was actually a type confusion problem in disguise.

You will get the most out of this if you have ever spent an hour staring at a massive, serialized prompt string trying to trace where a specific sentence originated, only to give up. If you build multi-source RAG pipelines, manage tool-calling agents, or persist state across turns, you have likely run into this issue even if you did not call it “type confusion.” Usually, it just looks like your agent doing something baffling for no clear reason.

When to skip this:

  • If you want benchmark tables proving accuracy gains: This experiment measures structural clarity rather than raw task accuracy.

  • If you are seeking a plug-and-play framework: This is a minimalist architectural experiment exploring how to structure context before it ever turns into a raw string.

If your pipeline only ever handles a single system instruction and a simple user prompt, with zero retrieval, tool outputs, or persistent memory, this setup will not be relevant to you, and that is completely fine.

You can check out the source and run the demos yourself on https://github.com/Emmimal/context-type-system/.

The Problem Isn’t That Agents Lack Context

The standard response to a weird agent output is to throw more context at it. Add another retrieved doc. Insert another paragraph of system instructions. Paste another example. Add another reminder to clarify what the last reminder actually meant.

That instinct comes from a reasonable place. Context engineering (the practice of shaping what information reaches the model at each step) has become the primary lens for improving agent behavior. Andrej Karpathy’s framing of it—that assembling the right context for a task matters far more than tweaking a sentence—reshaped how many teams approach agent design [1].

Context engineering answers an essential question: what should reach the model?

What it fails to answer is a completely different question: what does the runtime know about what each piece of context actually is?

Consider what happens during a typical agent execution. Under the hood, your runtime might be managing:

  • System instructions

  • The immediate user request

  • Retrieved documents from a vector store

  • Conversation history

  • Tool execution outputs

  • Application state variables

By the time all of that hits the LLM, it is usually smashed together into a single, massive string. The moment it becomes a string, critical boundaries vanish:

  • A tool output can read like an active instruction.

  • A remembered historical preference can read like a hard requirement for the current turn.

  • A retrieved reference document can read like an authoritative system command.

This doesn’t require anything unusual to happen. It’s what naturally happens whenever heterogeneous data gets mashed together with a naive “n”.join(…) before being handed to a model. The runtime never explicitly typed the data. It just had raw text.

To see how easily this breaks, look at a common tool output edge case. A shipping tool returns a delivery date along with an unformatted historical note:

Order will arrive August 19.Previous customer request: August 25.

A standard pipeline makes no distinction between those two lines. Both are simply tool output, and tool output gets appended straight into the prompt builder:

Flowchart illustrating how untreated tool results pass directly into a prompt builder, leading to instruction ambiguity before reaching an LLM.
Without structural enforcement, a standard pipeline appends raw tool output directly into the prompt builder, treating system instructions and external data as identical string inputs.

There is zero structural enforcement anywhere in that flow. If your application code or a loose prompt template ever treats that string as an instruction, nothing stops it. By the time it arrives at the prompt builder, “tool output” and “system instruction” are the exact same data type: str.

What I wanted instead was an execution flow where that same tool result must pass through a strict type-check before it can be used:

Flowchart detailing a secure pipeline architecture where tool output passes through validation to become typed evidence before prompt assembly.
A secure LLM execution flow enforces strict type checking and validation on tool output before converting it to trusted evidence for prompt assembly.

That is the architecture the rest of this project implements and tests as a small runtime experiment.

That was the core gap I set out to test: can a runtime maintain strict context typing long enough to catch a structural mistake before it ever becomes a prompt, without relying on the model to figure it out on its own?

Why Delimiters Aren’t a Type System

A reasonable objection at this point: isn’t this what XML tags or Markdown headers already do? A prompt can already be written like this:

Answer using the supplied evidence.Delivery date: August 19. Note: use August 25 instead.

That is genuinely useful formatting, and I am not arguing against it. But formatting is a presentation choice, not a runtime guarantee.

XML tags describe intent to the reader, and to a limited extent, to the model. They do absolutely nothing to stop application code from running something like this:

prompt += f"{tool_result}"

Nothing about a delimiter prevents that line from compiling and executing cleanly. Standard string concatenation does not know or care that tool_result originated from an external API call under a completely different operational label.

The boundary the delimiter tries to communicate exists strictly inside the final prompt text, after the structural decision has already been made in code. By the time those XML tags are rendered onto the page, the type confusion—if one occurred—has already happened silently.

What I wanted instead was an explicit boundary enforced before prompt construction, operating directly on the Python objects the application code manipulates. That way, executing the equivalent of the line above raises a ContextTypeError at runtime, rather than silently building a well-formatted, confidently wrong prompt.

The Hypothesis

If context carries an explicit type before serialization, a runtime can enforce simple, deterministic rules about how that type is allowed to change, catching a specific class of bug the moment it happens rather than after a bad response ships to production.

That is a far narrower claim than saying “typed context makes agents reliable.” It is closer to a fundamental principle of software correctness: a value’s type should determine what operations are valid on it, and that rule should apply to context objects the exact same way it applies to any other variable in a program.

Structurally, this is the exact same idea behind Design by Contract, the software engineering framework Bertrand Meyer introduced for the Eiffel language in the 1980s: give routines explicit preconditions and postconditions, and let violations surface as a broken contract immediately, rather than triggering a painful bug hunt three layers downstream [2]. I am applying that exact same instinct to context objects instead of function parameters.

The evidence chain I set out to prove looks like this:

Flowchart illustrating an eight-step evidence chain for processing typed context objects, starting with context arrival, moving through strict transformation validation, and ending with serialization into a prompt.
The proposed evidence chain for context execution, demonstrating how explicit typing and validation rules are applied to enforce structural correctness before prompt serialization.

Everything that follows is the direct implementation of that chain, along with the actual runtime output it produced when I ran the benchmark.

The Implementation

I did not want to build another orchestration framework. The whole point was to keep this small enough to read in a single sitting. Six modules, zero external dependencies, and nothing that talks directly to an LLM.

If you are used to agent frameworks that bundle retrieval, vector memory, tool routing, and loop execution into one giant package, this will look aggressively minimal by comparison. That is deliberate. The goal was never to compete with those frameworks. It was to isolate one specific mechanism, type-checked context, cleanly enough that you could lift it straight into whatever stack you are already running.

The core type vocabulary consists of four fundamental values, implemented with Python’s Enum [4]: INSTRUCTION, EVIDENCE, MEMORY, and TOOL_OUTPUT. The exact string names are not what matter here. What matters is that a piece of context carries one of these explicit classifications before it does anything else, rather than existing as an unlabeled string.

Every context item is implemented as a Python dataclass [3] and carries five key metadata attributes beyond its raw text content:

Field

What it captures

context_type

one of the four values above

source

where the content came from (system, tool:order_lookup, a retriever name)

created

timestamp at ingestion

request_id

a unique id for this specific item

derived_from

the id of the item this one was transformed out of, if any

That last field matters more than I expected going in. It is what turns a type promotion into something you can audit, rather than an operation that happened silently inside a helper function.

The policy consists of two small, static definitions: which target channel is protected from silent relabeling (INSTRUCTION, and only INSTRUCTION in this version), and which type transitions are allowed to happen explicitly (TOOL_OUTPUT —-> EVIDENCE, EVIDENCE —-> MEMORY). This is deliberately boring configuration, and that is the point. Structural boundaries that can be decided in advance should never be left for an if statement buried three functions deep to figure out at runtime, and they definitely should not be left for the model to infer from prose.

The enforcement boundary is the one piece of this worth actually reading in code, because it is the core mechanism the entire approach relies on. ContextStore maintains an internal ledger mapping raw content to the type it was first registered under. When the exact same content shows up again under a protected type without passing through an explicit transformation step, the store rejects the operation instead of accepting it:

existing = self._ledger.get(key)if existing is not None:    origin_type, origin_id = existing    if origin_type != context_type:        if context_type in PROTECTED_TYPES and not _via_transform:            raise ContextTypeError(                f"{origin_type.value} cannot be inserted into "                f"{context_type.value} context "                f"(content first registered as {origin_type.value}, id={origin_id})"            )

Everything else in the project exists to set this check up correctly and to give it something meaningful to compare against.

Legitimate type changes still need a clear, intentional path to happen. A separate transform() routine allows tool outputs to become evidence explicitly, but only after passing a minimal validation check (like rejecting strings containing failure markers like "error" or "failed"). Crucially, it always attaches the derived_from lineage trail described earlier rather than mutating the original object in place.

None of this requires the model to participate. That is worth sitting with for a second, because it is easy to read “context type system” and assume there is a classification step somewhere asking an LLM to label each piece of context. There isn’t.

The caller who already knows a value came from a tool call declares it as TOOL_OUTPUT the moment it enters the store. The type is not inferred by analyzing the text after the fact; it is asserted by whichever part of the application produced that content in the first place. That is the exact same way a function’s return type is not guessed at the call site, but declared where the function is written.

The assembler is the single place where typed objects finally turn into a plain string. It walks the stored items in a fixed, deterministic order (instructions first, followed by memory, evidence, and tool outputs) and renders each into a cleanly labeled section. Everything upstream of that step operates strictly on ContextItem objects with real, inspectable fields. Only at the very last step does the rich type information collapse into a raw prompt.

Here is how the entire architecture fits together:

Architecture flowchart showing raw inputs flowing through a context store into typed items, undergoing ledger checks and policy-checked transformations, and finally assembling into a serialized prompt for an LLM.
End-to-end pipeline architecture illustrating how raw inputs are transformed into structured, typed context objects, validated by a ledger, and assembled into a serialized prompt before reaching the LLM.

The model still sees plain tokens at the end of the pipeline. Everything sitting upstream of that final arrow is what is actually new here: structured, typed objects that your application code can inspect, validate, and reject before a single prompt string ever gets allocated in memory.

Captured Output: What Actually Happens

I ran the real implementation rather than describing what it should do. This is demo.py, executed once, output captured top to bottom without editing:

--- Provenance ledger after ingestion ---[instruction ] source=system               id=7e4205e4[memory      ] source=conversation_memory  id=610e3a2d[tool_output ] source=tool:order_lookup    id=d74461e6

Three objects go in. Three typed objects come out, each with an explicit source and an ID. Nothing surprising yet, but notice what is already different from a plain prompt string: the runtime now holds three inspectable records instead of three interchangeable lines of text.

Next, the demo tries a legitimate promotion (raw tool output, validated, becoming evidence):

--- Attempting to promote raw tool output straight to evidence ---PROMOTED: evidence id=cd37dd7f 

That is the derived_from field. It is not decorative. It means the evidence item traces directly back to the tool output item it came from, and that lineage survives in the object even after the type has changed.

Then the demo tries the operation the entire project exists to catch: taking that same tool output and inserting it directly into the instruction channel with no transformation, just a relabel.

--- Attempting to promote tool output directly into instruction ---REJECTED: tool_output cannot be inserted into instruction context (content first registered as tool_output, id=d74461e6)

The important result here is simple: the runtime rejected a context transformation that its type rules did not permit. The original tool output remained a tool_output object. Nothing was inferred, negotiated, or interpreted. It is an if statement in validator.py that fired, the exact same way any other type check would.

The final assembled prompt shows both the evidence item and the original tool output item, side by side, because promotion does not delete the source:

--- Final assembled prompt (tool output stays tool output) ---Instructions:- Answer using current order information.Memory:- The customer prefers concise answers.Evidence:- Order #1842: estimated delivery August 19. Historical note: customer previously requested delivery on August 25.Tool Output:- Order #1842: estimated delivery August 19. Historical note: customer previously requested delivery on August 25.

Yes, seeing that text twice looks wasteful. Including both the raw tool output and the promoted evidence adds to your token count, and that cost is not zero. I kept both in this demo on purpose because it is the clearest way to show that promotion creates a fresh object rather than overwriting the original in place. In production, you would pick one representation for the prompt and keep the other in your trace log.

Provenance Across a Transformation

The lineage the runtime kept for that single transformation looks like this:

Comparison diagram showing two separate branching paths from the same tool output: a successful validation resulting in a tracked evidence lineage, and an attempted re-labeling to a protected instruction type that gets rejected by the runtime.
Two distinct outcomes originating from the exact same source object: a successful, lineage-tracked transformation into evidence versus a runtime rejection of an unauthorized promotion to a protected instruction type.

Two separate attempts starting from the exact same source object yielded two distinct, predictable outcomes. Crucially, both outcomes are immediately visible inside the object graph itself, rather than buried deep inside custom application code that would require its own dedicated audit log to trace.

The Test Suite

Debugging an agent failure by staring at a giant serialized prompt is painful because everything has already been flattened. Typed context gives you something to test directly, without a model in the loop. I wrote eight checks covering type registration, invalid promotion, provenance preservation, separation of memory and evidence, and validation of failed tool output.

Here is the complete test output:

[PASS] Test 1a: evidence item registered with correct type[PASS] Test 1b: promoting that evidence to instruction is rejected — evidence cannot be inserted into instruction context (content first registered as evidence, id=6e9dc559)[PASS] Test 2a: historical memory item still present, unmodified[PASS] Test 2b: current state promoted to evidence with visible lineage[PASS] Test 2c: memory item and evidence item are distinct, neither overwritten[PASS] Test 3a: direct tool_output -> instruction insertion is rejected — tool_output cannot be inserted into instruction context (content first registered as tool_output, id=3074861e)[PASS] Test 3b: original item remains tool_output, unaffected by the rejected attempt[PASS] Test 4: failed tool output cannot be promoted to evidence — tool output from 'tool:shipping_api' failed validation and cannot become evidence: 'Status: failed. No delivery date available.'8/8 checks passed

It is worth being precise about what that number does and does not mean. Passing all eight checks simply means the implementation obeys its own rules: invalid promotions get rejected, legitimate transitions leave an audit trail, and original objects stay intact. It does not prove that typed context makes an agent’s downstream answers smarter, and I am not going to pretend otherwise. Keep that distinction in mind for everything that follows.

  • Test 1 confirms that evidence resists promotion into the instruction channel the exact same way tool output does. The protection logic is structural, not special-cased to a single source type.

  • Test 2 addresses a subtle issue: ensuring historical memory and live state coexist without overwriting each other. A remembered preference (“user previously selected Model A”) and a fresh tool fact about current state must both survive prompt assembly. The test confirms both objects remain distinct. Deciding which value to trust for a given turn remains an application-level choice, but the type system guarantees the app gets to make that choice between two clear objects rather than inside a merged string.

  • Test 3 automates the central rejection shown in the demo, asserting both that the illegal promotion fails and that the rejected attempt leaves the original object completely untouched.

  • Test 4 verifies that the valid transform route is not a free pass. Even validate_tool_result()—the single path allowed to elevate tool output to evidence—includes an explicit validation guard. A tool output reporting its own internal error cannot become evidence simply by taking the sanctioned route.

None of these checks require an LLM, a mocked API response, or a synthetic dataset predicting what a model might say. That is the entire point of testing at the context layer rather than the prompt-response layer. A test suite that relies on mocking model outputs to test application logic is testing something adjacent to what you actually built. These checks test the pipeline itself.

A bug the tool caught in itself

While wiring up demo.py, I hit a real bug in the ledger. Every time transform() re-registered content under a new type, the code overwrote the original registration ID with the newest one instead of preserving it. This caused rejection errors to point to the wrong item as the source of conflict. A tool_output object’s error message was referencing its own later evidence variant.

Getting provenance wrong makes a type system worse than useless, since it gives you confident, incorrect diagnostics. The fix was just a single guard condition to lock in the first ID it sees:

if existing is None:    # First time this content has been seen — this item becomes    # the permanent origin record for the ledger key.    self._ledger[key] = (context_type, item.request_id)

I wanted to show this because pretending everything worked on the first try misses the point. The bugs here were basic state tracking errors, not model quirks. And those are the exact bugs a context type system should help you catch, even when you write them into the type checker itself.

The Factory Floor Analogy

No shop manager dumps assembly guides, inspection reports, and scrap parts into one unlabeled box just because they sit on the same bench. Work instructions tell you how to build. Quality checks show what was measured. Defective parts explain why a previous run failed. You keep those items distinct so nobody grabs a rejected part thinking it belongs in the final assembly.

A prompt string is that bench, and context items are what you set on top.

The runtime I built acts as the inventory tag. It doesn’t decide what to build. It just keeps bad parts out of the instruction pile before someone downstream makes an expensive mistake.

Honest Design Decisions

1. String Normalization Over Content Hashing

The ledger key is just a normalized string. _key() collapses whitespace and lowercases text. If two different context items normalize to the exact same string, they collide in the ledger and share an origin record. That shortcut works fine for a prototype. In production, handling high volumes of similar tool outputs requires proper cryptographic hashing with explicit collision handling rather than string manipulation.

2. Single Protected Channel

Only INSTRUCTION is protected here. Evidence, memory, and tool outputs move between categories with fewer restrictions. That is a deliberate scope choice rather than an oversight. The specific bug class targeted here is external data getting relabeled as an instruction, since instruction text exerts the most control over model behavior. Real-world deployments might choose to protect additional channels like MEMORY.

3. Ephemeral Identifiers

IDs change on every execution. request_id relies on unseeded uuid.uuid4(). Running demo.py or tests.py produces brand-new hex strings every single time, even though the pass/fail outcomes remain identical. If you run the code to verify the transcript, expect matching structural shapes rather than matching hex strings.

4. In-Memory Scope

ContextStore lives only in memory for a single request cycle. It does not survive process restarts, and it lacks thread locks for concurrent writes. That design fits single-request prototypes. Scaling to multi-agent architectures or persistent state requires swap-in storage and thread safety from day one.

5. Hardcoded Transition Rules

Type promotion relies on a hardcoded lookup table (ALLOWED_TRANSITIONS). The runtime never infers or learns whether a transition seems reasonable. The core value of this entire pattern comes from keeping transitions explicit and auditable rather than letting a runtime guess intent.

Trade-offs and What Is Missing

1. Minimal Type Vocabulary

The system ships with only four core types. It omits extra categories like TASK_STATE, POLICY, or custom domain types. Adding new enum values is easy in code, but every new entry forces you to manually define its handling rules in PROTECTED_TYPES and ALLOWED_TRANSITIONS. The type system cannot make those policy choices for you.

2. Stops Before the Model Call

This prototype ends at prompt assembly. Wiring ContextStore into an active agent loop, tool router, or vector store pipeline is omitted by design. Decoupling the enforcement engine from model execution lets you test and verify type rules in isolation.

3. Zero Automatic Type Inference

The application code calling add_context() must declare the content type up front. The system never scans raw text to guess whether a string looks like an instruction or evidence. Inferring types from text is a separate, error-prone problem. Adding an AI classifier here would downgrade deterministic guarantees to statistical guesses.

4. Restricted to Single-Process Runs

ContextStore operates entirely in local memory for a single request. It includes no serialization layer, network transport, or sync mechanism for sharing typed context across distributed workers or multi-agent networks.

5. No Micro-Benchmarks

Measuring execution speed here would be misleading. In-memory dictionary lookups and string checks take microseconds, which amounts to rounding error compared to an actual network call to an LLM. Performance benchmarking only becomes relevant once you introduce complex schema validation or large policy sets.

The Honest Takeaway

This is a targeted enforcement mechanism designed to catch one specific bug class: content silently changing semantic role on its way into a prompt. It is not a complete agent orchestration framework. Expanding it to handle distributed state or dynamic classification is straightforward in theory, but remains untested in this codebase. Saying that clearly matters more than pretending this solves context management end-to-end.

What This Does — and Doesn’t — Solve

What it provides:

  • Explicit type boundaries between different kinds of context.

  • Traceable provenance for every context item, even across transformation steps.

  • Controlled promotion rules enforced through strict whitelists instead of silent relabeling.

  • Deterministic validation checks that run entirely in local application code without calling a model.

  • Structured prompt assembly that retains section labels for every underlying fact.

What it cannot guarantee:

  • Correct model reasoning once tokens reach the transformer.

  • Factual accuracy of retrieved facts or recalled memories.

  • Elimination of hallucinations in downstream responses.

  • Deterministic model outputs across runs.

That second list matters more than it might seem at first glance. A type checker running upstream cannot fix what a model does with well-typed input. What it can do is ensure that context was not silently corrupted by a type confusion bug before it reached the prompt window.

It turns a subtle class of runtime bugs into something you can catch with a unit test, rather than something you uncover by staring at five thousand tokens of serialized text line by line.

Three Layers, Not One Replacing Another

It is worth being precise about where this fits relative to two terms already common in agent design, mainly because it is easy to misread context typing as a rebrand of an existing idea.

  • Prompt engineering asks how an instruction should be phrased. It operates on the precise wording within a message sent to the model.

  • Context engineering asks what information needs to reach the model for a given turn. It manages selection (retrieval, memory lookup, pruning) under a token budget.

  • Context typing asks a narrower question than either: once context engineering picks what reaches the model, what is each item permitted to represent, and what operations can the runtime perform on it before serialization?

Conceptual comparison diagram breaking down agent architecture into three distinct layers: Prompt Engineering, Context Engineering, and Context Typing, arranged hierarchically from wording selection to runtime type rules.
A conceptual hierarchy distinguishing prompt engineering, context engineering, and context typing as three complementary yet separate layers of agent design.

None of these layers replace the others; they stack. A properly typed context object must still be structured into a clear, well-phrased prompt. Conversely, a polished prompt generated from mistyped context remains unsafe regardless of how well written the text is. Context typing simply forms the base layer, ensuring data integrity before prompt and context engineering take over.

What Actually Changes When You Debug With This

Before introducing typed context, debugging an unexpected model response usually boiled down to staring at a single, giant, flattened string:

Sequential flowchart illustrating a traditional, opaque debugging pipeline where user input flows through a monolithic serialized prompt into an LLM, resulting in an unexpected answer.
The legacy debugging workflow: raw user input is compressed into a single, flattened prompt string, leaving developers to guess the root cause when the model produces an unexpected answer.

Troubleshooting from there was mostly educated guesswork. Was the retrieval step flawed? Was a historical memory stale? Was the system prompt phrasing ambiguous? Did a tool output return misleading data? By the time anything went wrong, every piece of context had already been flattened into interchangeable text, leaving no natural boundary where you could isolate the problem.

With context carrying explicit type tags and provenance metadata straight through to prompt assembly, that same investigation gains discrete checkpoints:

Sequential flowchart showing user input flowing through inspectable typed objects, validation, provenance tracking, and labeled prompt assembly before reaching the LLM and generating an answer.
An inspectable context pipeline featuring discrete validation and provenance checkpoints that simplify debugging and fault isolation in LLM applications.

Instead of treating every issue as a vague downstream failure, you can localize bugs to a specific pipeline stage. That is a modest claim compared to saying “this makes agents smarter,” but it is a far more realistic one. It shortens time-to-diagnosis when things break, without making false promises about how well the model reasons once clean input arrives.

The Practical Takeaway

The next time an agent produces a strange response, adding another paragraph of system instructions is rarely the highest-leverage fix. Before rewriting the prompt, it is worth stepping back to ask a narrower set of structural questions:

  • Was an instruction mixed with external evidence somewhere upstream?

  • Was a historical memory mistaken for current state?

  • Was a raw tool result inserted into context without validation?

  • Did retrieved content get elevated into an instruction channel it was never meant to occupy?

If the answer to any of those is yes, adding more prompt text merely treats a symptom. The real fix belongs one layer down, inside the context runtime.

Fixing this at the runtime layer isn’t as flashy as tweaking a prompt, and you won’t get that instant feedback of watching the model change its tone on the next run. But it gives you something much better: a clear signal on what actually broke. You can tell immediately whether context got mangled on the way in or if the model just misreasoned on clean data. Those are completely different problems, but most agent setups mash them together and hope a prompt patch fixes both.

Context engineering determines what information reaches the model window. Context typing governs what that information is permitted to mean before serialization. For any agent drawing context from more than one source, that distinction is doing essential work, whether your current runtime explicitly enforces it or not.

Reproducing This

The complete project consists of six modules plus a demo and a test file, requiring no external dependencies:

  • context_types.pyContextType enum and ContextTypeError

  • context_item.pyContextItem dataclass with provenance tracking fields

  • policy.py – Definitions for protected types and permitted transitions

  • validator.pyContextStore: origin ledger and enforcement logic

  • assembler.pyContextAssembler: turns typed items into a structured prompt

  • transforms.py – Explicit transformation rules (e.g., tool_output to evidence)

  • demo.py – The order-lookup walkthrough shown in this post

  • tests.py – The eight unit checks detailed above

python demo.pypython tests.py

Both scripts finish in milliseconds without requiring network calls or API keys. Running without an LLM in the loop keeps execution fast, local, and predictable.

If you run the code yourself, request_id values rely on uuid.uuid4(), so your generated IDs will not match the hex strings in this article. That is expected behavior. The pipeline structure, rejections, and promotion rules remain identical across runs even while the specific IDs change. Diffing the output of two runs shows identical log shapes with different hashes, demonstrating that the underlying type rules are deterministic even when identifiers are random.

You can check out the source and run the demos yourself on https://github.com/Emmimal/context-type-system/.

References

[1] Andrej Karpathy, post on X, June 25, 2025: describing context engineering as “the delicate art and science of filling the context window” with the right information for a given step. — https://x.com/karpathy/status/1937902205765607626

[2] Bertrand Meyer, “Applying ‘Design by Contract’,” Computer (IEEE), Vol. 25, No. 10, October 1992, pp. 40–51. — https://dl.acm.org/doi/10.1109/2.161279

[3] Python Software Foundation, dataclasses — Data Classes, Python 3 documentation. — https://docs.python.org/3/library/dataclasses.html

[4] Python Software Foundation, enum — Support for enumerations, Python 3 documentation. — https://docs.python.org/3/library/enum.html


Disclosure

All code in this article was written by me and is original work, developed and tested on Python 3.12. This article does not include benchmark numbers; the terminal output shown is captured directly from actual runs of demo.py and tests.py, zero API calls, and is reproducible by cloning the repository at github.com/Emmimal/context-type-system and running those two scripts directly.

The implementation uses no library beyond the Python standard library; the test suite is plain Python, not a testing framework. All diagrams in this article, including the featured image, were created by me. The featured image was generated with ChatGPT (DALL·E); the diagrams (the evidence chain, the architecture pipeline, provenance lineage across a transformation, the three-layer comparison, and the before/after debugging flow) were built directly from the project’s own code and design. I have no financial relationship with any tool, library, or company mentioned in this article.

Shape
Shape
Stay Ahead

Explore More Insights

Stay ahead with more perspectives on cutting-edge power, infrastructure, energy,  bitcoin and AI solutions. Explore these articles to uncover strategies and insights shaping the future of industries.

Shape

Network architecture pay climbs amid AI shift

Network architects today must make decisions that involve multiple technologies. From topology to WAN and SD-WAN to segmentation and security, the scope of networking skills continues to evolve. Those networking decisions become more complicated as enterprises incorporate AI workloads, edge computing, Wi-Fi 7, private 5G, and more. AI and automation

Read More »

Golar contracts CIMC Raffles for fourth FLNG

Golar LNG Ltd. last week executed an engineering, procurement, and construction (EPC) contract with Yantai CIMC Raffles Offshore Ltd. (CIMC Raffles) for its fourth floating LNG (FLNG) and second MKII design FLNG vessel with an annual liquefaction capacity of 3.5 million tonnes/year (tpy). Golar’s fourth FLNG is expected to be

Read More »

Energy Department Announces $500 Million Award to Revitalize American Steelmaking

WASHINGTON—The U.S. Department of Energy (DOE) today announced a $500 million award to support a $1 billion investment at Cleveland-Cliffs’ Middletown Works facility in Middletown, Ohio. Vice President JD Vance and U.S. Energy Secretary Chris Wright visited Middletown Works today to highlight the Trump Administration’s commitment to American steelworkers and the resurgence of American manufacturing. The investment will modernize American steelmaking, protect 2,300 American jobs, and strengthen the domestic steel supply chain. The project advances President Trump’s commitment to put American workers first, bring investment back to American communities, and strengthen the industries critical to America’s economic and national security. Cleveland-Cliffs determined that the business case for the original project scope no longer made sense given customers’ unwillingness to pay a “green premium” for steel. Working with DOE, Cleveland-Cliffs identified a viable alternative that will upgrade and improve the efficiency of the existing coal-fired blast furnace while also capturing and commercializing co-product blast furnace gas (BFG). “President Trump is rebuilding America’s industrial base,” said Secretary Wright. “This investment puts American workers and American manufacturing first. It will modernize one of our nation’s critical steelmaking facilities, protect thousands of jobs, and strengthen our domestic steel production—keeping Ohio at the heart of American manufacturing and strengthening our national security.” The investment will modernize critical steelmaking operations at Middletown Works by rebuilding and upgrading the plant’s main coal-fired ironmaking furnace, deploying AI to optimize furnace operations and improve energy efficiency, and building an on-site facility to convert steel mill process gases into electricity. Follow-on investments will turn industrial byproducts into materials for concrete used in regional infrastructure. “This landmark investment at Middletown Works will secure a reliable domestic supply of high-purity steel while protecting thousands of quality jobs in Ohio,” said Assistant Secretary of Energy Audrey Robertson. “DOE is proud to partner with Cleveland-Cliffs to reduce America’s dependence on foreign products

Read More »

Energy Secretary Keeps Critical Generation Available in Mid-Atlantic

WASHINGTON—U.S. Secretary of Energy Chris Wright today issued an emergency order to address critical grid reliability issues facing the Mid-Atlantic region of the United States. The emergency order directs PJM Interconnection L.L.C. (PJM), in coordination with Constellation Energy Corporation, to ensure Units 3 and 4 of the Eddystone Generating Station in Pennsylvania remain available to operate and to employ economic dispatch to minimize costs for the American people. The units were originally slated to shut down on May 31, 2025. “The energy sources that perform when you need them most are the most valuable,” Secretary Wright said. “During recent Mid-Atlantic heat waves, coal, natural gas, and nuclear kept the lights and air conditioners on. President Trump and the Energy Department are committed to keeping critical generation available when demand is highest, reducing the risk of blackouts and ensuring Americans have affordable, reliable, and secure power—regardless of whether the wind is blowing or the sun is shining.” As outlined in DOE’s Resource Adequacy Report, power outages could increase by 100 times in 2030 if the U.S. continues to take reliable power offline. This order is in effect beginning on August 23, 2026, through November 20, 2026.                                                                                             ###

Read More »

Energy Department Announces $500 Million to Secure America’s Critical Mineral and Battery Supply Chains

WASHINGTON—The U.S. Department of Energy’s (DOE) Office of Critical Minerals and Energy Innovation (CMEI) today announced $500 million for seven selected projects to expand critical mineral and material processing, battery manufacturing, and recycling capacity in the United States. In accordance with President Trump’s Executive Order, Unleashing American Energy, the selected projects advance the President’s agenda to strengthen America’s domestic critical minerals and materials supply chains, reduce reliance on foreign sources, bolster national security, and advance American energy dominance. “For too long, America has depended on foreign actors for critical materials essential to modern life that underpin our economy, energy security, and national security,” said U.S. Secretary of Energy Chris Wright. “President Trump is reversing that dependence by securing our critical supply chains, unleashing American industry, and bringing critical materials production and processing back to the United States.” “DOE is taking decisive action to secure the critical supply chains necessary to power our nation,” said Assistant Secretary of Energy Audrey Robertson. “These projects underscore DOE’s commitment to driving innovation, reducing reliance on foreign sources, and promoting American energy dominance.” This is the third round of funding from DOE’s Battery Materials Processing and Battery Manufacturing and Recycling programs, which support battery materials processing, recycling, and manufacturing projects. These include demonstration projects, construction of commercial-scale facilities, and retrofitting or retooling existing facilities.  Critical minerals and materials are essential to American industry, energy production, and national security. Expanding domestic capacity will help ensure the resources America needs are processed, manufactured, and recycled in the United States.  Information on the selected projects is available here and here.

Read More »

bp lets Shah Deniz compression automation contract

bp has let a contract to Emerson to deliver automation technologies for the Shah Deniz Compression project offshore Azerbaijan. Emerson will provide integrated control and safety systems aimed at enhancing production, safety, and reliability on the new offshore compression platform. The contract includes systems to provide process control, safety shutdown, fire and gas detection, and power management. Together, these systems deliver real-time visibility and remote control of critical operations, Emerson said. The $2.9 billion Shah Deniz Compression project, which includes an electrically powered, normally unattended offshore production platform, is a next stage development of the Caspian Sea Shah Deniz field. Designed to access low-pressure gas reserves and maximize overall recovery, the platform will be equipped with four 11 Mw compressors and serve as the central compression hub for gas from the Shah Deniz Alpha and Bravo platforms. The platform will operate remotely from bp’s onshore Sangachal terminal 55 km south of Baku. The project is expected to enable about 50 billion cu m of additional gas and about 25 million bbl of condensate production and export. Construction is scheduled to be completed in 2029, with first gas compression expected from the Shah Deniz Alpha platform in 2029 and from the Shah Deniz Bravo platform in 2030. The agreement follows a previous automation contract bp signed with Emerson for the Azeri Central East and Shah Deniz Stage 2 developments. bp is operator at Shah Deniz (29.99%) with partners Lukoil (19.99%), TPAO (19%), Cenub Qaz Dehlizi (16.02%), NICO (10%), and MVM (5%).

Read More »

Federal court voids Texas GulfLink license over agency’s ‘serious procedural errors’

The ruling voids the license, halting all construction or progress. Sentinel Midstream declined comment on the ruling and would not answer questions about the status of construction. GulfLink, sited about 30 miles offshore Freeport, Tex., is designed to export up to 1 million b/d via Very Large Crude Carriers (VLCCs) to the government of Japan and Freeport Commodities. The project involves a 44-mile, 42-in. OD pipeline and was scheduled to begin operations around 2028. The estimated $2.1 billion investment was funded as part of a broader trade agreement between the US and Japan. The legal battle stems from a specific rule in the Deepwater Port Act of 1974 that dictates that the federal government can only permit one crude oil deepwater port, including any supporting infrastructure, within a single designated “application area.” Because the competing SPOT project’s pipeline route physically overlaps and intersects GulfLink’s lines, the plaintiff—Citizens for Clean Air & Clean Water in Brazoria County (Better Brazoria), represented by Earthjustice—successfully argued that MARAD violated the “one port” rule when issuing GulfLink’s license in February. The three-judge panel found that MARAD “improperly drew” the map designing the project’s official boundaries to exclude the pipelines and approved two overlapping projects in the same zone instead of only licensing one. The court wrote that the scope of the error made vacatur, not the less serious remand without vacatur, the appropriate remedy. Vacatur deems the license invalid and is used when the court finds “serious procedural errors” that cannot be easily explained or fixed with minor changes. Remand without vacatur sends the decision back to the agency for corrections but leaves the current license in place in the meantime. SPOT project status The $2.5-3-billion SPOT project, developed by Enterprise Products Partners in partnership with Enbridge Inc., also lies about 30 miles from Freeport. Designed to handle VLCCs,

Read More »

IEA: Emergency reserve withdrawals slow

The International Energy Agency (IEA) member countries continued to release emergency oil stocks in July, but the pace of withdrawals slowed sharply as crude supply availability improved in parts of the Asia Pacific and the market faced increasing product tightness. IEA countries released 26 million bbl of emergency stocks in July, bringing cumulative releases to 300 million bbl since the agency announced a coordinated 400-million bbl action on Mar. 11. Government stock draws averaged 750,000 b/d in July, down from 1.5 million b/d in June and 2.5 million b/d in May. The slowdown was particularly pronounced among IEA members in Asia Oceania, which released 4 million bbl from emergency stocks in July, compared with 8 million bbl in June and 44 million bbl in May. The decline reflected improved crude oil supply availability in Japan and Korea. The US also reduced the pace of emergency stock releases. Withdrawals from the Strategic Petroleum Reserve totaled 17 million bbl in July, roughly half the volume released in June. More than 100 million bbl of the emergency stocks committed under the IEA’s 400-million bbl coordinated action has yet to reach the market. The timing of the remaining releases will depend on market developments and broader oil supply security considerations in coming months, according to the agency. Most of the remaining emergency stocks consist of crude oil, however, limiting their ability to ease increasingly tight oil product markets, IEA said. At the same time, global observed oil inventories fell sharply in July amid severely constrained shipping through the Strait of Hormuz. Stocks declined by 69 million bbl, equivalent to 2.2 million b/d, with oil on water accounting for more than 90% of the decline. Oil on water fell by 63 million bbl, or about 2 million b/d, reflecting higher arrivals and lower exports amid

Read More »

PJM’s New Data Center Power Equation

PJM Interconnection has now filed one of the most consequential proposed changes yet in the relationship between data centers and the electric grid. Rather than simply treating a new hyperscale or AI facility like any other customer whose demand will be backed through regional capacity procurement, PJM is proposing a framework under which the largest new loads would need to be supported by new capacity, have their needs covered through the Reliability Backstop Procurement, or face potential curtailment when the regional power system is short of supply. The approach has been developing since PJM launched its Critical Issue Fast Path process for large loads in 2025, but it became substantially more concrete in late July and August 2026. PJM filed its proposed Reliability Backstop Procurement with FERC on July 31 and began accepting applications that day for its FERC-approved Expedited Interconnection Track. On Aug. 13, PJM filed its proposed Interim Resource Adequacy Service, or IRAS, along with the Large Load Registry that would support it. The immediate numbers explain the urgency. PJM’s July 2026 capacity auction for the 2028/2029 delivery year procured 138,318 MW of unforced capacity through the centralized auction. Even after including Fixed Resource Requirement resources, however, PJM came up 6,831 MW short of its reliability requirement. The auction cleared at the FERC-approved $325/MW-day price cap. It was the second consecutive auction in which the PJM region failed to procure its full reliability requirement, something that had not happened before these two auctions. That gap is occurring while demand continues to accelerate. PJM’s 2026 long-term forecast projects summer peak demand growing at an average 3.6% annually over the next decade, compared with just 0.3% in the comparable forecast issued in 2021. Summer peak demand is projected to rise by nearly 66 GW over 10 years. Data centers are

Read More »

Zayo, NVIDIA Build the Long-Haul Backbone for Distributed AI

The data center industry’s increasingly power-first approach to site selection has created a follow-on question: Once the megawatts are found, is there enough network infrastructure to make the site useful at AI scale? Zayo and NVIDIA are putting real infrastructure behind that question. Zayo said it is working with NVIDIA to expand network capacity supporting AI factories across North America, including an 8,000-route-mile program targeting some of the fastest-growing AI corridors in the United States. The project encompasses six new long-haul routes along with overbuilds of existing network across 10 high-demand corridors. The announcement arrives as AI data center development moves beyond the largest established hubs toward markets where power and land may be more readily available, but fiber capacity cannot necessarily be taken for granted. That geography is increasingly important. NVIDIA has separately developed “scale-across” networking technology designed to allow AI infrastructure distributed among different buildings — or even data centers separated by hundreds of kilometers — to operate as a more unified computing environment. Put together, the developments suggest that networking is becoming inseparable from the AI factory buildout itself. Power may determine where the next generation of AI infrastructure can be built. Fiber will increasingly determine how effectively those sites can participate in the larger AI ecosystem. Fiber Follows the Power Zayo CEO Steve Smith said AI demand is changing both where network infrastructure is needed and how aggressively capacity must be deployed ahead of development. “AI is fundamentally reshaping where and how network infrastructure needs to be built across the U.S.,” Smith said. The company’s 8,000-mile program is more nuanced than that top-line number might suggest. Zayo disclosed in April that the expansion includes approximately 3,000 route miles across six new long-haul routes, plus more than 5,000 route miles of overbuilds across 10 existing corridors. Zayo

Read More »

Southern’s 17 GW Pipeline Puts AI Power Demand Into Utility Math

The headline number from Southern Company’s latest earnings report is hard to miss: electricity use by data centers across the utility’s system increased 55% in the second quarter compared with a year earlier. But the more consequential numbers may be the ones sitting behind it. Southern now has more than 1.2 GW of operating data center load, up by more than 500 MW from a year ago. At the same time, its electric utilities have signed contracts and large-load agreements totaling more than 17 GW by the mid-2030s, with another 8 GW in late-stage development and a prospective pipeline of large industrial and data center projects exceeding 75 GW. That leaves an enormous gap between the data center megawatts consuming electricity today and the load Southern has contractually positioned itself to serve during the next decade. For the data center industry, that gap may be the most important part of Southern’s second-quarter story. It offers a look at how utilities are beginning to convert the AI infrastructure boom from forecasts and campus announcements into contracts, generation procurement, transmission investment and eventually energized capacity. From Contracts to Megawatts Southern added roughly 6 GW of contracted large load during the quarter alone. Alabama Power signed three projects representing about 3 GW, while Georgia Power reached a 25-year agreement to serve OpenAI’s planned project in Effingham County near Savannah. That facility is expected to require approximately 3.2 GW and begin taking electric service in phases in 2028. The numbers nevertheless require an important distinction. Seventeen gigawatts contracted does not mean 17 GW will suddenly appear on Southern’s grid. Large data center campuses ramp gradually, often over several years, and Southern executives acknowledged that actual customer ramp schedules do not always match the assumptions made when projects are first approved. CEO Chris Womack said

Read More »

PORTS-Pike Takes Shape as an 8-GW AI Infrastructure Model

Back on March 31, 2026, we discussed we discussed SoftBank and SB Energy’s plans to redevelop the former Portsmouth Gaseous Diffusion Plant site near Piketon as a 10-GW artificial intelligence data center campus supported by almost an equal amount of new power generation. At the time, the plan called for as much as 10 GW of new generation, including 9.2 GW of natural gas capacity, along with approximately $4.2 billion of high-voltage transmission infrastructure developed with AEP Ohio. An initial 800-MW data center phase was targeted for service in 2028. The March story was notable because Pike County appeared to offer a preview of a new model for building hyperscale infrastructure: develop the generation, transmission and data center simultaneously rather than wait for an increasingly congested regional grid to deliver multiple gigawatts of capacity. Not to mention the reuse of a brownfield site with the encouragement of the federal government. Since then, almost every important part of the project has moved forward, and on August 17, the most consequential missing pieces fell into place. NVIDIA announced that it will become the exclusive AI compute infrastructure provider for the PORTS-Pike Technology Campus. OpenAI will be the data center customer, signing a 20-year lease with SB Energy for approximately 8 GW of IT capacity. NVIDIA will invest another $1.5 billion in SB Energy and provide credit support for the land, power and shell infrastructure behind an initial 4.25 GW of IT load, with an option covering approximately another 3.75 GW. The Securities and Exchange Commission filing accompanying the announcement makes the financial commitment even more significant. NVIDIA disclosed that its aggregate payment obligation associated with its initial commitment is capped at $105 billion. That is not a conventional capital commitment to spend $105 billion building the campus, nor is it simply a

Read More »

Nvidia scales back financing guarantee for OpenAI data center

Nvidia is scaling back a proposed financial guarantee tied to a massive OpenAI data center project in Ohio, reducing its initial commitment from as much as $250 billion to less than $120 billion, according to report in the Wall Street Journal. Earlier this month, Nvidia announced partnerships with major financial firms including Apollo Global Management, BlackRock, Blackstone, Brookfield Asset Management, Goldman Sachs and KKR, aimed at mobilizing more than $500 billion in capital for AI computing infrastructure. The change represents a significant restructuring of Nvidia’s role in financing the planned facility, which is being developed by SB Energy, a subsidiary of SoftBank. Under the revised arrangement, Nvidia would guarantee financing for the project’s first phase, representing roughly 5 gigawatts of capacity, or half of the total proposed capacity. Financing for the remaining capacity would be considered separately at a later stage.

Read More »

Texas Tightens Oversight of Data Center Development

Texas has spent the past decade building one of the most data center-friendly policy environments in the United States. But the state’s political posture is tightening. The emerging message from Austin is that continued data center growth will face greater scrutiny over grid costs, water use, tax incentives and community impacts. What is interesting about this policy conversation is that the Texas Legislature is not in regular session. The 89th regular session ended June 2, 2025, and the 90th Legislature does not convene until January 12, 2027. What has occurred instead is a concentrated period of interim committee work, gubernatorial recommendations, implementation of Senate Bill 6, calls for a special session, and regulatory action by the Public Utility Commission of Texas and the Electric Reliability Council of Texas. Together, those efforts are creating the framework for a broader legislative debate in 2027 while already affecting projects seeking ERCOT interconnection, infrastructure costs and site-selection decisions. Abbott Sets Out a New Policy Framework The policy shift accelerated June 10, when Gov. Greg Abbott directed the PUCT to require data centers to fully fund the electric infrastructure needed to serve their operations and directed PUCT and ERCOT to identify additional actions available under existing authority. Separately, Abbott pledged to work with lawmakers in 2027 on legislation requiring data centers to add electric capacity, use water-efficient cooling systems, report electricity and water use, phase out outdated tax incentives and adopt additional protections for neighboring communities. The most consequential shift began June 10, when Gov. Greg Abbott sent state electricity regulators a sweeping list of data center policy priorities. Abbott called for future legislation requiring new facilities to add generation to the Texas grid, pay the full cost of their interconnection and related infrastructure, use closed-loop or similarly water-efficient cooling systems, and file annual reports

Read More »

Microsoft will invest $80B in AI data centers in fiscal 2025

And Microsoft isn’t the only one that is ramping up its investments into AI-enabled data centers. Rival cloud service providers are all investing in either upgrading or opening new data centers to capture a larger chunk of business from developers and users of large language models (LLMs).  In a report published in October 2024, Bloomberg Intelligence estimated that demand for generative AI would push Microsoft, AWS, Google, Oracle, Meta, and Apple would between them devote $200 billion to capex in 2025, up from $110 billion in 2023. Microsoft is one of the biggest spenders, followed closely by Google and AWS, Bloomberg Intelligence said. Its estimate of Microsoft’s capital spending on AI, at $62.4 billion for calendar 2025, is lower than Smith’s claim that the company will invest $80 billion in the fiscal year to June 30, 2025. Both figures, though, are way higher than Microsoft’s 2020 capital expenditure of “just” $17.6 billion. The majority of the increased spending is tied to cloud services and the expansion of AI infrastructure needed to provide compute capacity for OpenAI workloads. Separately, last October Amazon CEO Andy Jassy said his company planned total capex spend of $75 billion in 2024 and even more in 2025, with much of it going to AWS, its cloud computing division.

Read More »

John Deere unveils more autonomous farm machines to address skill labor shortage

Join our daily and weekly newsletters for the latest updates and exclusive content on industry-leading AI coverage. Learn More Self-driving tractors might be the path to self-driving cars. John Deere has revealed a new line of autonomous machines and tech across agriculture, construction and commercial landscaping. The Moline, Illinois-based John Deere has been in business for 187 years, yet it’s been a regular as a non-tech company showing off technology at the big tech trade show in Las Vegas and is back at CES 2025 with more autonomous tractors and other vehicles. This is not something we usually cover, but John Deere has a lot of data that is interesting in the big picture of tech. The message from the company is that there aren’t enough skilled farm laborers to do the work that its customers need. It’s been a challenge for most of the last two decades, said Jahmy Hindman, CTO at John Deere, in a briefing. Much of the tech will come this fall and after that. He noted that the average farmer in the U.S. is over 58 and works 12 to 18 hours a day to grow food for us. And he said the American Farm Bureau Federation estimates there are roughly 2.4 million farm jobs that need to be filled annually; and the agricultural work force continues to shrink. (This is my hint to the anti-immigration crowd). John Deere’s autonomous 9RX Tractor. Farmers can oversee it using an app. While each of these industries experiences their own set of challenges, a commonality across all is skilled labor availability. In construction, about 80% percent of contractors struggle to find skilled labor. And in commercial landscaping, 86% of landscaping business owners can’t find labor to fill open positions, he said. “They have to figure out how to do

Read More »

2025 playbook for enterprise AI success, from agents to evals

Join our daily and weekly newsletters for the latest updates and exclusive content on industry-leading AI coverage. Learn More 2025 is poised to be a pivotal year for enterprise AI. The past year has seen rapid innovation, and this year will see the same. This has made it more critical than ever to revisit your AI strategy to stay competitive and create value for your customers. From scaling AI agents to optimizing costs, here are the five critical areas enterprises should prioritize for their AI strategy this year. 1. Agents: the next generation of automation AI agents are no longer theoretical. In 2025, they’re indispensable tools for enterprises looking to streamline operations and enhance customer interactions. Unlike traditional software, agents powered by large language models (LLMs) can make nuanced decisions, navigate complex multi-step tasks, and integrate seamlessly with tools and APIs. At the start of 2024, agents were not ready for prime time, making frustrating mistakes like hallucinating URLs. They started getting better as frontier large language models themselves improved. “Let me put it this way,” said Sam Witteveen, cofounder of Red Dragon, a company that develops agents for companies, and that recently reviewed the 48 agents it built last year. “Interestingly, the ones that we built at the start of the year, a lot of those worked way better at the end of the year just because the models got better.” Witteveen shared this in the video podcast we filmed to discuss these five big trends in detail. Models are getting better and hallucinating less, and they’re also being trained to do agentic tasks. Another feature that the model providers are researching is a way to use the LLM as a judge, and as models get cheaper (something we’ll cover below), companies can use three or more models to

Read More »

OpenAI’s red teaming innovations define new essentials for security leaders in the AI era

Join our daily and weekly newsletters for the latest updates and exclusive content on industry-leading AI coverage. Learn More OpenAI has taken a more aggressive approach to red teaming than its AI competitors, demonstrating its security teams’ advanced capabilities in two areas: multi-step reinforcement and external red teaming. OpenAI recently released two papers that set a new competitive standard for improving the quality, reliability and safety of AI models in these two techniques and more. The first paper, “OpenAI’s Approach to External Red Teaming for AI Models and Systems,” reports that specialized teams outside the company have proven effective in uncovering vulnerabilities that might otherwise have made it into a released model because in-house testing techniques may have missed them. In the second paper, “Diverse and Effective Red Teaming with Auto-Generated Rewards and Multi-Step Reinforcement Learning,” OpenAI introduces an automated framework that relies on iterative reinforcement learning to generate a broad spectrum of novel, wide-ranging attacks. Going all-in on red teaming pays practical, competitive dividends It’s encouraging to see competitive intensity in red teaming growing among AI companies. When Anthropic released its AI red team guidelines in June of last year, it joined AI providers including Google, Microsoft, Nvidia, OpenAI, and even the U.S.’s National Institute of Standards and Technology (NIST), which all had released red teaming frameworks. Investing heavily in red teaming yields tangible benefits for security leaders in any organization. OpenAI’s paper on external red teaming provides a detailed analysis of how the company strives to create specialized external teams that include cybersecurity and subject matter experts. The goal is to see if knowledgeable external teams can defeat models’ security perimeters and find gaps in their security, biases and controls that prompt-based testing couldn’t find. What makes OpenAI’s recent papers noteworthy is how well they define using human-in-the-middle

Read More »