<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://rongzhou.github.io/agentscript/blog</id>
    <title>AgentScript Blog</title>
    <updated>2026-05-11T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://rongzhou.github.io/agentscript/blog"/>
    <subtitle>AgentScript Blog</subtitle>
    <entry>
        <title type="html"><![CDATA[Why You Should Optimize Context, Not Prompts]]></title>
        <id>https://rongzhou.github.io/agentscript/blog/context-not-prompts</id>
        <link href="https://rongzhou.github.io/agentscript/blog/context-not-prompts"/>
        <updated>2026-05-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Prompt optimization is the obvious next step after prompt engineering.]]></summary>
        <content type="html"><![CDATA[<p>Prompt optimization is the obvious next step after prompt engineering.</p>
<p>If hand-written prompts are brittle, let an optimizer improve them. Let it search
over instructions. Let it select examples. Let it compile a better prompt from
data and metrics.</p>
<p>This is a reasonable idea. It has produced useful systems. DSPy is a strong
representative of this direction: it frames itself as a framework for
programming rather than prompting language models, and its optimizers can tune
the prompts or LM weights of a DSPy program against a user-specified metric.</p>
<p>But for many agents, prompt optimization is not the most important optimization
surface.</p>
<p>The problem is not that prompts do not matter.</p>
<p>The problem is that prompts are often the wrong thing to optimize first.</p>
<p>An agent prompt is not just an instruction. It is a mixture:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">prompt =</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  system_instruction</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">+ role</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">+ context_data</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">+ examples</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">+ user_instruction</span><br></div></code></pre></div></div>
<p>Prompt optimization usually focuses on the instruction-shaped parts of this
mixture: the wording, the demonstrations, the phrasing of the task, the examples
that surround the call.</p>
<p>But agent behavior often depends more on <code>context_data</code>: retrieved documents,
tool observations, memory records, intermediate state, previous generated
values, summaries, citations, and outputs from other agents.</p>
<p>If the model sees the right evidence, a mediocre instruction often works.</p>
<p>If the model sees the wrong evidence, a beautiful instruction only makes the
wrong answer more fluent.</p>
<p>This post is about a different optimization target:</p>
<blockquote>
<p>Do not only optimize what you say to the model.
Optimize what the model sees.</p>
</blockquote>
<p align="center"><img src="https://rongzhou.github.io/agentscript/img/selectable-context.png" alt="Selectable context slots make context optimization a source-level decision" width="900"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-prompt-is-not-the-unit-of-an-agent">The Prompt Is Not the Unit of an Agent<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#the-prompt-is-not-the-unit-of-an-agent" class="hash-link" aria-label="Direct link to The Prompt Is Not the Unit of an Agent" title="Direct link to The Prompt Is Not the Unit of an Agent" translate="no">​</a></h2>
<p>For a single LLM call, the prompt feels like the obvious unit.</p>
<p>You write an instruction. You provide a few examples. You test the output. You
adjust the wording.</p>
<p>That mental model breaks down in agents.</p>
<p>An agent does not just have a prompt. It has a changing context boundary.</p>
<p>A research agent may have:</p>
<ul>
<li class="">the user question</li>
<li class="">search queries</li>
<li class="">search results</li>
<li class="">retrieved documents</li>
<li class="">summaries of those documents</li>
<li class="">memory records from previous runs</li>
<li class="">intermediate observations</li>
<li class="">failed attempts</li>
<li class="">tool errors</li>
<li class="">outputs from helper agents</li>
<li class="">final answer requirements</li>
</ul>
<p>Some of that data should enter the next model call. Some should not.</p>
<p>The failure mode is often not:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">The instruction was unclear.</span><br></div></code></pre></div></div>
<p>It is:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">The model saw the wrong context.</span><br></div></code></pre></div></div>
<p>Or:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">The right context existed in the program, but it never entered the prompt.</span><br></div></code></pre></div></div>
<p>Or:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">The context entered the prompt, but in the wrong form.</span><br></div></code></pre></div></div>
<p>A tool result might be too large. A memory query might retrieve stale advice. A
summary might drop the citation needed by the final answer. A reasoning step may
need a compact digest, while the answer step needs source-preserving excerpts.</p>
<p>These are not mainly wording problems.</p>
<p>They are context selection problems.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prompt-text-is-a-soft-optimization-variable">Prompt Text Is a Soft Optimization Variable<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#prompt-text-is-a-soft-optimization-variable" class="hash-link" aria-label="Direct link to Prompt Text Is a Soft Optimization Variable" title="Direct link to Prompt Text Is a Soft Optimization Variable" translate="no">​</a></h2>
<p>Prompt optimization has an attractive promise: replace manual prompt tweaking
with search.</p>
<p>DSPy's MIPROv2, for example, jointly optimizes instructions and few-shot
examples. The MIPRO work frames the problem as optimizing free-form instructions
and demonstrations for modules in multi-stage LM programs, using downstream
metrics without gradients or module-level labels.</p>
<p>That is a serious and useful line of work.</p>
<p>But the optimized object is still soft.</p>
<p>Prompt wording has difficult properties:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">high-dimensional</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">free-form</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">model-sensitive</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">hard to constrain</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">hard to compare semantically</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">easy to overfit</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">hard to debug when it works</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">hard to debug when it fails</span><br></div></code></pre></div></div>
<p>A prompt diff can show that some words changed. It rarely explains why the
system became more reliable.</p>
<p>Did the model improve because the new instruction is genuinely better?</p>
<p>Because one phrase happens to activate a behavior in this model?</p>
<p>Because a few-shot example resembles the validation set?</p>
<p>Because the optimizer found a local trick that will disappear with the next
model version?</p>
<p>Because the downstream metric is incomplete?</p>
<p>These questions are not signs that prompt optimizers are useless. They are signs
that free-form prompt text is a difficult optimization surface.</p>
<p>It is too close to model-specific behavior.</p>
<p>It is too far from the actual data-flow problem inside many agents.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="context-is-a-better-optimization-surface">Context Is a Better Optimization Surface<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#context-is-a-better-optimization-surface" class="hash-link" aria-label="Direct link to Context Is a Better Optimization Surface" title="Direct link to Context Is a Better Optimization Surface" translate="no">​</a></h2>
<p>Context is different.</p>
<p>Context is not primarily a sentence.</p>
<p>Context is a set of choices.</p>
<p>Should the model see raw tool output or a summary?</p>
<p>Should it see the top three documents or the top ten?</p>
<p>Should it see recent memory, durable lessons, or no memory at all?</p>
<p>Should it see citation-preserving excerpts or compressed observations?</p>
<p>Should a final answer step receive the full evidence bundle, while an earlier
planning step only receives a small digest?</p>
<p>These are structured decisions.</p>
<p>They are easier to enumerate:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">none</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">compact digest</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">summary</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">top documents</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">source-preserving excerpts</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">combined memory + docs</span><br></div></code></pre></div></div>
<p>They are easier to inspect:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">This run used docs.top5 max 4k.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">That run used scratch.digest max 500.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">This run omitted memory entirely.</span><br></div></code></pre></div></div>
<p>They are easier to trace:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">Which context source entered the prompt?</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">How much token budget did it receive?</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Was it clipped?</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Was the source URL preserved?</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Was this context slot omitted?</span><br></div></code></pre></div></div>
<p>They are also more portable across models.</p>
<p>Different models may respond differently to the same phrase. But the question
"should the model see the retrieved documents or only a summary?" is less tied
to one model's prompt quirks. GPT, Claude, Gemini, Qwen, and local models may
differ in style, but they all need the right evidence.</p>
<p>Context optimization is not magic. It can overfit too. A context policy selected
on one dataset may fail on another distribution.</p>
<p>But when it fails, the failure is inspectable.</p>
<p>You can see the selected source. You can see what was omitted. You can see
whether the model had access to the evidence. You can change a structured
choice, not a spell.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="from-prompt-engineering-to-context-engineering">From Prompt Engineering to Context Engineering<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#from-prompt-engineering-to-context-engineering" class="hash-link" aria-label="Direct link to From Prompt Engineering to Context Engineering" title="Direct link to From Prompt Engineering to Context Engineering" translate="no">​</a></h2>
<p>Prompt engineering asks:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">What should I say to the model?</span><br></div></code></pre></div></div>
<p>Context engineering asks:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">What should the model see?</span><br></div></code></pre></div></div>
<p>That shift matters.</p>
<p>In ordinary Python or TypeScript agents, context often appears as strings,
message arrays, framework objects, or prompt templates. The boundary between
local program data and prompt context is maintained by convention.</p>
<p>AgentScript starts from a stricter rule:</p>
<blockquote>
<p>Local data is not prompt context.</p>
</blockquote>
<p>Tool results, memory query results, intermediate observations, trace events, and
outputs from other agents do not enter the prompt automatically.</p>
<p>If the model should see a value, the program must select it with <code>use</code>.</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use input.question as "user question"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use docs.summary max 4k as "evidence"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use past max 2k as "past lessons"</span><br></div></code></pre></div></div>
<p>This is the first step.</p>
<p>Context becomes visible.</p>
<p>A <code>use</code> declaration says:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">source = docs.summary</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">label  = "evidence"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">budget = 4k</span><br></div></code></pre></div></div>
<p>It is not just a string template. It is a context contract.</p>
<p>The next step is natural:</p>
<p>If context can be explicit, context alternatives can be explicit too.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-one-of-context-search-space-as-code"><code>use one of</code>: Context Search Space as Code<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#use-one-of-context-search-space-as-code" class="hash-link" aria-label="Direct link to use-one-of-context-search-space-as-code" title="Direct link to use-one-of-context-search-space-as-code" translate="no">​</a></h2>
<p>AgentScript can express a context choice directly:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use one of {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    none:     empty</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    compact:  scratch.digest max 500</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    verbose:  scratch.summary max 4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    grounded: docs.top5 max 4k selected</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">} as "evidence"</span><br></div></code></pre></div></div>
<p>This says:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">There is a context slot named "evidence".</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">It can be absent.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">It can use a compact digest.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">It can use a verbose summary.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">It can use retrieved documents.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">The current selected version is grounded.</span><br></div></code></pre></div></div>
<p>This is not runtime magic.</p>
<p>There is no hidden optimizer running inside the agent.</p>
<p>There is no invisible learning state.</p>
<p>There is only a declaration of possible context sources, and a visible selected
choice.</p>
<p><code>use one of</code> declares the search space.</p>
<p><code>selected</code> records the current specialization.</p>
<p><code>empty</code> means the context slot is absent.</p>
<p>The model does not see the candidate list. It only sees the selected context
source.</p>
<p>If <code>grounded</code> is selected, the prompt receives an <code>evidence</code> section built from
<code>docs.top5</code>.</p>
<p>If <code>none: empty</code> is selected, the prompt receives no <code>evidence</code> section at all.</p>
<p>The source remains auditable.</p>
<p>The runtime remains simple.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-empty-belongs-in-the-same-mechanism">Why <code>empty</code> Belongs in the Same Mechanism<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#why-empty-belongs-in-the-same-mechanism" class="hash-link" aria-label="Direct link to why-empty-belongs-in-the-same-mechanism" title="Direct link to why-empty-belongs-in-the-same-mechanism" translate="no">​</a></h2>
<p>It is tempting to invent a separate syntax for optional context.</p>
<p>For example:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use? docs.top5 max 4k as "evidence"</span><br></div></code></pre></div></div>
<p>But that makes optionality a separate language mechanism.</p>
<p>A simpler model is to treat absence as one candidate in the same context choice:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use one of {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    none: empty</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    docs: docs.top5 max 4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">} as "evidence"</span><br></div></code></pre></div></div>
<p>This is easier to read and easier to optimize.</p>
<p>The search space is explicit:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">evidence ∈ { none, docs }</span><br></div></code></pre></div></div>
<p>The default is explicit too. If <code>none</code> is first, the unoptimized program omits
the context slot by default. If <code>docs</code> is first, the unoptimized program includes
it by default.</p>
<p>No extra optional-use syntax is needed.</p>
<p>Absence is just another context choice.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="selected-is-a-source-level-decision"><code>selected</code> Is a Source-Level Decision<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#selected-is-a-source-level-decision" class="hash-link" aria-label="Direct link to selected-is-a-source-level-decision" title="Direct link to selected-is-a-source-level-decision" translate="no">​</a></h2>
<p>The important part of this design is where the optimization result lives.</p>
<p>It lives in source code.</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use one of {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    none:     empty</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    compact:  scratch.digest max 500</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    verbose:  scratch.summary max 4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    grounded: docs.top5 max 4k selected</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">} as "evidence"</span><br></div></code></pre></div></div>
<p>The current choice is not hidden in a database.</p>
<p>It is not stored in a runtime profile.</p>
<p>It is not controlled by an ambient optimizer.</p>
<p>It is written next to the alternatives.</p>
<p>This makes the program self-describing.</p>
<p>A human can review it.</p>
<p>A tool can parse it.</p>
<p>A trace can point back to it.</p>
<p>A version control diff can show exactly what changed:</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain"> use one of {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">     none:     empty</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">     compact:  scratch.digest max 500</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">-    verbose:  scratch.summary max 4k selected</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">-    grounded: docs.top5 max 4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">+    verbose:  scratch.summary max 4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">+    grounded: docs.top5 max 4k selected</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"> } as "evidence"</span><br></div></code></pre></div></div>
<p>This is a very different kind of optimization artifact from a rewritten prompt.</p>
<p>The output is not a new incantation.</p>
<p>The output is a changed context decision.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="optimization-as-source-to-source-specialization">Optimization as Source-to-Source Specialization<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#optimization-as-source-to-source-specialization" class="hash-link" aria-label="Direct link to Optimization as Source-to-Source Specialization" title="Direct link to Optimization as Source-to-Source Specialization" translate="no">​</a></h2>
<p>The cleanest optimization model for AgentScript is source-to-source
specialization.</p>
<p>An optimizer does not need to mutate the runtime.</p>
<p>It does not need to inject hidden state.</p>
<p>It does not need to rewrite the prompt text.</p>
<p>It can do something much simpler:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">read AgentScript source</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">find use one of sites</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">evaluate candidates</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">move the selected marker</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">write new AgentScript source</span><br></div></code></pre></div></div>
<p>The input is AgentScript.</p>
<p>The output is AgentScript.</p>
<p>The runtime still executes ordinary AgentScript.</p>
<p>There are two useful output forms.</p>
<p>The development form keeps the search space:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use one of {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    none:     empty</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    compact:  scratch.digest max 500</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    verbose:  scratch.summary max 4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    grounded: docs.top5 max 4k selected</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">} as "evidence"</span><br></div></code></pre></div></div>
<p>This form is good for review, auditing, and future optimization.</p>
<p>The production form can be flattened:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use docs.top5 max 4k as "evidence"</span><br></div></code></pre></div></div>
<p>If the selected variant is <code>empty</code>, the production form can remove the context
slot entirely:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">// evidence omitted</span><br></div></code></pre></div></div>
<p>Both forms are understandable.</p>
<p>Neither requires a special runtime learning mechanism.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="runtime-should-be-boring">Runtime Should Be Boring<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#runtime-should-be-boring" class="hash-link" aria-label="Direct link to Runtime Should Be Boring" title="Direct link to Runtime Should Be Boring" translate="no">​</a></h2>
<p>This is the main design constraint.</p>
<p>The runtime should not be where learning hides.</p>
<p>At runtime, a <code>use one of</code> site resolves to exactly one candidate.</p>
<p>The rule is deterministic:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">if a candidate is marked selected:</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    use that candidate</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">else:</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    use the first candidate</span><br></div></code></pre></div></div>
<p>Then the selected candidate behaves like ordinary <code>use</code>.</p>
<p>If the candidate is non-empty:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">grounded: docs.top5 max 4k selected</span><br></div></code></pre></div></div>
<p>the runtime behaves as if the program had written:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use docs.top5 max 4k as "evidence"</span><br></div></code></pre></div></div>
<p>If the candidate is empty:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">none: empty selected</span><br></div></code></pre></div></div>
<p>the runtime behaves as if there were no <code>use</code> for that context slot.</p>
<p>That is all.</p>
<p>No prompt rewriting.</p>
<p>No hidden profile overlay.</p>
<p>No adaptive runtime state.</p>
<p>No agent self-modification during execution.</p>
<p>This keeps the trace honest. When a trace says the model saw <code>docs.top5 max 4k</code>
as <code>evidence</code>, the source code contains the corresponding selected candidate.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-is-more-auditable-than-prompt-optimization">Why This Is More Auditable Than Prompt Optimization<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#why-this-is-more-auditable-than-prompt-optimization" class="hash-link" aria-label="Direct link to Why This Is More Auditable Than Prompt Optimization" title="Direct link to Why This Is More Auditable Than Prompt Optimization" translate="no">​</a></h2>
<p>Prompt optimization often produces an artifact that looks like text:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">You are a careful and precise assistant. Use the provided context...</span><br></div></code></pre></div></div>
<p>The optimizer may have improved it, but the result is still hard to inspect as
an engineering artifact.</p>
<p>A reviewer sees changed wording.</p>
<p>They may not know what behavior changed.</p>
<p>They may not know whether the improvement will transfer to another model.</p>
<p>A context optimization diff is different.</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">-    verbose:  scratch.summary max 4k selected</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">+    grounded: docs.top5 max 4k selected</span><br></div></code></pre></div></div>
<p>This says something concrete:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">The model now sees retrieved documents instead of a summary.</span><br></div></code></pre></div></div>
<p>Or:</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">-    lessons: Lessons.relevant(input.question) max 1k selected</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">+    none: empty selected</span><br></div></code></pre></div></div>
<p>This says:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">The model no longer receives memory in this step.</span><br></div></code></pre></div></div>
<p>These are engineering decisions.</p>
<p>They can be reviewed.</p>
<p>They can be traced.</p>
<p>They can be tested.</p>
<p>They can be reverted.</p>
<p>They can be discussed without guessing which phrase happened to work.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="context-optimization-still-needs-evaluation">Context Optimization Still Needs Evaluation<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#context-optimization-still-needs-evaluation" class="hash-link" aria-label="Direct link to Context Optimization Still Needs Evaluation" title="Direct link to Context Optimization Still Needs Evaluation" translate="no">​</a></h2>
<p>None of this removes the need for evaluation.</p>
<p>An optimizer still needs a signal.</p>
<p>That signal may come from fixtures, tests, validation output, user feedback,
downstream task success, or human review.</p>
<p>Context optimization can still overfit.</p>
<p>A candidate that works on one fixture set may fail elsewhere. A memory policy
that improves one workflow may pollute another. A larger evidence bundle may
improve factuality but hurt latency and cost.</p>
<p>The difference is not that context optimization is automatically correct.</p>
<p>The difference is that its variables are visible.</p>
<p>When it fails, you can inspect the context choices directly.</p>
<p>When it improves, you can often explain why.</p>
<p>That matters for agents because agents are not just single model calls. They are
programs. Programs need reviewable state, explicit boundaries, and understandable
changes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-this-means-for-agentscript">What This Means for AgentScript<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#what-this-means-for-agentscript" class="hash-link" aria-label="Direct link to What This Means for AgentScript" title="Direct link to What This Means for AgentScript" translate="no">​</a></h2>
<p>AgentScript's first bet was:</p>
<blockquote>
<p>Agent context should be code.</p>
</blockquote>
<p>That is what <code>use</code> provides.</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use input.question as "user question"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use docs.summary max 4k as "evidence"</span><br></div></code></pre></div></div>
<p>The next bet is:</p>
<blockquote>
<p>Agent context search space should be code too.</p>
</blockquote>
<p>That is what <code>use one of</code> provides.</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use one of {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    none:     empty</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    compact:  scratch.digest max 500</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    verbose:  scratch.summary max 4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    grounded: docs.top5 max 4k selected</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">} as "evidence"</span><br></div></code></pre></div></div>
<p>This is the bridge from context engineering to context optimization.</p>
<p>The language does not need to make prompt text adaptive.</p>
<p>It does not need to optimize role descriptions.</p>
<p>It does not need to let agents rewrite their control flow.</p>
<p>It can keep the core model small:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use       declares what the model can see</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">generate  declares where the model is called</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">one of    declares context alternatives</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">selected  records the current context choice</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">empty     records deliberate absence</span><br></div></code></pre></div></div>
<p>That is enough to make context optimization possible without hiding it in the
runtime.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-real-question">The Real Question<a href="https://rongzhou.github.io/agentscript/blog/context-not-prompts#the-real-question" class="hash-link" aria-label="Direct link to The Real Question" title="Direct link to The Real Question" translate="no">​</a></h2>
<p>The old prompt engineering question was:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">What should I say to the model?</span><br></div></code></pre></div></div>
<p>AgentScript's first question was:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">What did the model actually see?</span><br></div></code></pre></div></div>
<p>Context optimization adds a second question:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">What could the model have seen, and why did we choose this version?</span><br></div></code></pre></div></div>
<p>That is the difference between prompt optimization and context optimization.</p>
<p>Prompt optimization searches over language.</p>
<p>Context optimization searches over evidence, memory, summaries, tool results,
budgets, and absence.</p>
<p>For agents, that is often the more important surface.</p>
<p>Not because prompts do not matter.</p>
<p>Because in real agent programs, the model's next output is usually constrained
less by the beauty of the instruction and more by the quality of the information
placed in front of it.</p>
<p>Reliable agents need more than better prompts.</p>
<p>They need context choices that are explicit, scoped, auditable, and eventually
optimizable.</p>
<p>That is the direction AgentScript is exploring:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">Agent context as code.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Context search space as code.</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Learning results as code.</span><br></div></code></pre></div></div>]]></content>
        <author>
            <name>Rong Zhou</name>
            <uri>https://github.com/rongzhou</uri>
        </author>
        <category label="agentscript" term="agentscript"/>
        <category label="context-optimization" term="context-optimization"/>
        <category label="llm-agents" term="llm-agents"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[What Did the Model Actually See?]]></title>
        <id>https://rongzhou.github.io/agentscript/blog/introducing-agentscript</id>
        <link href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript"/>
        <updated>2026-05-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Introducing AgentScript, a small language for explicit, scoped, auditable LLM]]></summary>
        <content type="html"><![CDATA[<p>Introducing AgentScript, a small language for explicit, scoped, auditable LLM
context.</p>
<p>Many programmers of my generation first learned computing through a simple
model: input, processing, output.</p>
<p>A program receives data, transforms it, and produces a result. It is an old
mental model, but still a useful one. It made programs feel understandable
because the boundaries were visible.</p>
<p>LLM agents stretch that model.</p>
<p>The input is no longer just a file, a request, or a record with a known schema. It
is prompt context: user intent, tool observations, retrieved documents, memory
records, intermediate state, retry messages, and outputs from other agents.</p>
<p>The output is no longer just a return value. It is generated text or JSON that
may need to satisfy a contract before the next step can trust it.</p>
<p>Most agent programs do not fail because calling a model is hard.</p>
<p>They fail because nobody can tell, with confidence, what the model actually saw
before it generated the next value.</p>
<p>After a few iterations, an agent has local variables, tool results, memory
records, intermediate observations, retry messages, and outputs from other
agents. Some of that data should reach the next model call. Some should not. In
most Python or TypeScript agents, that boundary is maintained by convention.</p>
<p>That works for small demos. It becomes fragile in real workflows.</p>
<p align="center"><img src="https://rongzhou.github.io/agentscript/img/context-boundaries.png" alt="Traditional append-only chat versus AgentScript scoped context boundaries" width="900"></p>
<p>What did the model actually see? Which tool result was included in the prompt,
and which one was only local data? Was memory clipped? Did another agent's output
enter as evidence or as prior assistant text? What exactly must the model return
before that value flows into the next step?</p>
<p>AgentScript is an experiment in making those questions answerable from the
program itself.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-agentscript-is">What AgentScript Is<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#what-agentscript-is" class="hash-link" aria-label="Direct link to What AgentScript Is" title="Direct link to What AgentScript Is" translate="no">​</a></h2>
<p>AgentScript is a small language for building LLM agents where prompt context is
explicit, scoped, typed, traceable, and auditable.</p>
<p>It is aimed at developers building multi-step agents where tool output, memory,
intermediate state, and generated values must be controlled and audited.</p>
<p>It is not a prompt template format. It is not YAML configuration. It is not a
general-purpose agent framework.</p>
<p>Its core idea is simple:</p>
<blockquote>
<p>Agent context should be code.</p>
</blockquote>
<p>The two most important language features are <code>use</code> and <code>generate</code>.</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use content max 8k as "file content"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">generate({</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    input: "Summarize the file for a busy teammate",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    max_output: 1000</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}) -&gt; {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    title</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    summary</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    key_points: list[string]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    action_items: list[string]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p><code>use</code> declares what the model is allowed to see. <code>generate</code> declares where the
model is called and, when needed, what contract its output must satisfy. In the old
input/process/output framing, AgentScript puts language-level attention on the
two unstable edges of LLM programs: prompt input and generated output.</p>
<p>The important part is not that AgentScript can call an LLM. The important part
is that the prompt boundary is visible in the code.</p>
<p>Everything else in the language exists to support that workflow: variables,
functions, agents, imports, loops, tools, memory, and trace output.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-not-just-use-python-or-typescript">Why Not Just Use Python or TypeScript?<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#why-not-just-use-python-or-typescript" class="hash-link" aria-label="Direct link to Why Not Just Use Python or TypeScript?" title="Direct link to Why Not Just Use Python or TypeScript?" translate="no">​</a></h2>
<p>Python and TypeScript are excellent general-purpose languages, and AgentScript
is not trying to replace them.</p>
<p>The problem is that they do not have a native concept of prompt context. Context
usually appears as strings, arrays, objects, templates, framework calls, or
message lists. The program can be correct, but the intent is scattered across
ordinary code:</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> messages </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">system</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"You are a reviewer"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">Question: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">input</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation property-access">question</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">Search results: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation known-class-name class-name" style="color:rgb(255, 203, 107)">JSON</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation method function property-access" style="color:rgb(130, 170, 255)">stringify</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation">results</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token function" style="color:rgb(130, 170, 255)">user</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token template-string string" style="color:rgb(195, 232, 141)">Memory: </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">${</span><span class="token template-string interpolation">memory</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation method function property-access" style="color:rgb(130, 170, 255)">map</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation">item</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation"> </span><span class="token template-string interpolation arrow operator" style="color:rgb(137, 221, 255)">=&gt;</span><span class="token template-string interpolation"> item</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation property-access">text</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token template-string interpolation method function property-access" style="color:rgb(130, 170, 255)">join</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token template-string interpolation string" style="color:rgb(195, 232, 141)">"\n"</span><span class="token template-string interpolation punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token template-string template-punctuation string" style="color:rgb(195, 232, 141)">`</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> answer </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="font-style:italic">await</span><span class="token plain"> model</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token method function property-access" style="color:rgb(130, 170, 255)">generate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">messages</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></div></code></pre></div></div>
<p>Which fields from <code>results</code> are included? Was raw tool output included? Was
memory clipped? Did another agent's output enter as evidence or as prior
assistant text? What schema must <code>answer</code> satisfy?</p>
<p>AgentScript makes context selection a first-class operation:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use input.question as "user question"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use results.summary max 4k as "search results"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use past max 2k as "past lessons"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">generate({</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    input: "Answer using only the selected context",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    max_output: 800,</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    strict: true</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}) -&gt; {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    answer</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    citations: list[string]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>Labels can be simple identifiers or quoted strings.</p>
<p>Local variables do not enter prompts automatically. Tool results do not enter
prompts automatically. Memory query results do not enter prompts automatically.
Trace events do not enter prompts automatically.</p>
<p>If data should be visible to the model, it must be selected with <code>use</code>.</p>
<p>That one rule changes the contract of agent development. The prompt is no longer a
side effect of arbitrary string assembly. It is a scoped contract.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-minimal-example">A Minimal Example<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#a-minimal-example" class="hash-link" aria-label="Direct link to A Minimal Example" title="Direct link to A Minimal Example" translate="no">​</a></h2>
<p>Here is a complete file summarizer:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">import llm Qwen from "ollama://localhost:11434/qwen3.6"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">import tool File from "file://workspace"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">main agent FileSummarizer {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    model Qwen</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    role "Technical Writer"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    description "Read one local file and produce a useful structured summary."</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    main func(input { path: string }) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        file = File.read({</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            path: input.path</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        })</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        use input.path as "source path"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        use file.content max 8k as "file content"</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        generate({</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            input: "Summarize the file for a busy teammate",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            max_output: 1000</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }) -&gt; {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            title</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            summary</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            key_points: list[string]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            action_items: list[string]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>The file tool can read from the workspace, but the tool result does not
implicitly become prompt context. The program explicitly selects the path and
file content, labels them, gives the content a budget, and then asks the model
for a structured result.</p>
<p>Run it with a real model:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">agentscript recipes/summarize-file.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"README.md"}'</span><br></div></code></pre></div></div>
<p>Or try it immediately with deterministic output and a trace:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-g</span><span class="token plain"> @rong/agentscript</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">agentscript recipes/summarize-file.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"README.md"}'</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--mock</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--trace</span><br></div></code></pre></div></div>
<p>Run it with a deterministic mock model:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">agentscript recipes/summarize-file.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"README.md"}'</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--mock</span><br></div></code></pre></div></div>
<p>Inspect the prompt and trace without calling a model:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">agentscript recipes/summarize-file.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"README.md"}'</span><span class="token plain"> --dry-run</span><br></div></code></pre></div></div>
<p>Print an auditable trace:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">agentscript recipes/summarize-file.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"README.md"}'</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--trace</span><br></div></code></pre></div></div>
<p>The trace can show which context sources were selected, which budgets were
applied, what was clipped, which instruction was used, what output contract was
requested, and whether validation passed. That trace is for debugging and audit.
It is not itself prompt context.</p>
<p>For example, the useful part of a trace is not just that a model was called. It
is the boundary around that call:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">Generate #1</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Agent: FileSummarizer / Technical Writer</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Selected context:</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  [source path] input.path</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  [file content] content, budget=8k, clipped=false</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Instruction:</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  Summarize the file for a busy teammate</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Output contract:</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  title: string</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  summary: string</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  key_points: list[string]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  action_items: list[string]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">Validation: ok</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="generate-is-the-only-llm-call-site"><code>generate</code> Is the Only LLM Call Site<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#generate-is-the-only-llm-call-site" class="hash-link" aria-label="Direct link to generate-is-the-only-llm-call-site" title="Direct link to generate-is-the-only-llm-call-site" translate="no">​</a></h2>
<p>In AgentScript, ordinary code can compute values, call tools, query memory, call
other agents, and organize intermediate state. Only <code>generate</code> asks a model to
produce new output.</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">answer = generate({</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    input: "Answer using only the selected context.",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    max_output: 800,</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    attempts: 3,</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    strict: true</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}) -&gt; {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    ok: boolean</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    answer</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    citations: list[string]</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>The contract after <code>-&gt;</code> is an output contract. AgentScript can ask providers for
structured output when possible, validate the returned value, and retry when the
model returns invalid JSON or a mismatched contract. Downstream code can then depend
on the returned contract instead of parsing prose.</p>
<p>This gives each model call a visible boundary:</p>
<ul>
<li class="">the current agent identity</li>
<li class="">the selected context from visible <code>use</code> declarations</li>
<li class="">the local instruction in <code>generate({ input: ... })</code></li>
<li class="">the optional output contract after <code>-&gt;</code></li>
</ul>
<p>That boundary is the unit you can review, debug, and trace.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="scope-is-the-context-boundary">Scope Is the Context Boundary<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#scope-is-the-context-boundary" class="hash-link" aria-label="Direct link to Scope Is the Context Boundary" title="Direct link to Scope Is the Context Boundary" translate="no">​</a></h2>
<p>AgentScript uses scope to control prompt visibility.</p>
<p>This is also a way to avoid the pressure of long conversations. In a traditional
chat loop, each step tends to append more messages to the same history. The
context grows heavier over time, and the next model call inherits whatever the
conversation happened to accumulate.</p>
<p>AgentScript treats each generation differently. Before a <code>generate</code>, the program
selects the visible context deliberately with <code>use</code>: the specific values, labels,
and budgets that matter for this step. It is closer to precise sampling than to
endless appending.</p>
<p>A <code>use</code> declaration is visible to later <code>generate</code> calls in the same scope and
child scopes. It does not leak upward. Function calls and agent calls create
independent context boundaries.</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">func caller(input) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    use input.goal as goal</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    helper(input)</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">func helper(input) {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    use input.detail as detail</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    generate({ input: "Work on the detail" }) -&gt; {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        ok: boolean</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>The <code>generate</code> inside <code>helper</code> sees <code>input.detail</code>. It does not automatically
inherit <code>caller</code>'s selected <code>goal</code> context.</p>
<p>Agent calls are isolated in the same way. A called agent sees the input value
passed to it and the context selected inside its own functions. It does not
inherit the caller's prompt context.</p>
<p>That makes multi-agent composition easier to audit. Each agent has its own
prompt contract instead of sharing an ambient conversation buffer.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tool-results-are-data-not-prompt">Tool Results Are Data, Not Prompt<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#tool-results-are-data-not-prompt" class="hash-link" aria-label="Direct link to Tool Results Are Data, Not Prompt" title="Direct link to Tool Results Are Data, Not Prompt" translate="no">​</a></h2>
<p>One of AgentScript's most important rules is that tool results are local program
data. They are not prompt context until selected.</p>
<p>This matters in repository review, research, code analysis, and any workflow
where tools can return much more data than the model should see.</p>
<p>A repository review can collect a file tree, TODO matches, package metadata, and
CI configuration. The review step can then choose only the relevant pieces:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use "file tree"          budget=8k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use "todo findings"      budget=4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use "package metadata"   budget=4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use "ci configuration"   budget=4k</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">generate                 blockers, risks, quick_wins, next_steps</span><br></div></code></pre></div></div>
<p>The distinction is deliberate.</p>
<p><strong>Tools expand what the program can do. <code>use</code> controls what the model can see.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="memory-is-explicit-too">Memory Is Explicit Too<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#memory-is-explicit-too" class="hash-link" aria-label="Direct link to Memory Is Explicit Too" title="Direct link to Memory Is Explicit Too" translate="no">​</a></h2>
<p>AgentScript includes file JSONL and SQLite memory backends, but memory follows
the same rule as everything else.</p>
<p>The memory handle is a capability, not prompt data:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">import memory Lessons from "file://./.agentscript/lessons.jsonl"</span><br></div></code></pre></div></div>
<p>The agent must query memory, receive ordinary data, and then explicitly select
that data if it should influence the next generation:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">past = Lessons.query({</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    text: input.goal,</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    kind: "lesson",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    limit: 5</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">})</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use input.goal as goal</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">use past max 2k as "past lessons"</span><br></div></code></pre></div></div>
<p>Writing to memory is also explicit:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">Lessons.add({</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    kind: "lesson",</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    text: reflection.insight,</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    goal: input.goal</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">})</span><br></div></code></pre></div></div>
<p>This supports reflection and self-improvement without automatic context growth.
A future run can use durable lessons, but only through a visible query and a
visible <code>use</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="agent-patterns-as-composable-primitives">Agent Patterns as Composable Primitives<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#agent-patterns-as-composable-primitives" class="hash-link" aria-label="Direct link to Agent Patterns as Composable Primitives" title="Direct link to Agent Patterns as Composable Primitives" translate="no">​</a></h2>
<p>AgentScript does not hardcode agent patterns as keywords.</p>
<p>There is no special <code>planner</code> keyword. No special <code>executor</code> keyword. No special
<code>reflect</code> keyword. Those names are just agents, functions, or ordinary data in
your program.</p>
<p>That is intentional. ReAct, plan-and-execute, evaluator-optimizer, reflection,
self-improvement, and multi-agent workflows can all be built from the same small
set of primitives:</p>
<ul>
<li class="">agents and functions for boundaries</li>
<li class="">tools for external capabilities</li>
<li class="">memory for durable explicit state</li>
<li class=""><code>use</code> for prompt context selection</li>
<li class=""><code>generate</code> for model calls and output contracts</li>
<li class="">trace for auditability</li>
</ul>
<p>For independent bounded work, AgentScript also provides <code>parallel for</code>:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">results = parallel for step in plan.steps max 10 {</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    Executor({</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        goal: input.goal,</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        step: step</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    })</span><br></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></div></code></pre></div></div>
<p>For bounded independent work, <code>parallel for</code> is designed for multi-agent and
multi-generate bottlenecks without exposing <code>async</code>/<code>await</code>.</p>
<p>The result is still local data. It enters a later prompt only if selected:</p>
<div class="language-agentscript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-agentscript codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">use results.summary max 6k as execution_results</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="current-status">Current Status<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#current-status" class="hash-link" aria-label="Direct link to Current Status" title="Direct link to Current Status" translate="no">​</a></h2>
<p>AgentScript is experimental, but the core language design is now in place.</p>
<p>Currently implemented:</p>
<ul>
<li class="">parser</li>
<li class="">semantic checker</li>
<li class="">mock runtime</li>
<li class="">OpenAI, Anthropic, and Ollama LLM adapters</li>
<li class="">file, environment, HTTP, and shell-style host tools</li>
<li class="">JSONL and SQLite memory backends</li>
<li class="">structured output validation</li>
<li class="">trace output</li>
<li class="">arithmetic and comparison operators</li>
<li class="">compound assignment</li>
<li class=""><code>parallel for</code></li>
<li class="">runtime concurrency control for <code>parallel for</code></li>
<li class="">CLI support for <code>--mock</code>, <code>--dry-run</code>, <code>--trace</code>, <code>--trace-file</code>, <code>--check</code>, and <code>--concurrency</code></li>
</ul>
<p>The implementation is usable for experimentation, examples, and local workflows,
but the language is still pre-1.0 and may change.</p>
<p>Planned work includes a stable IR, richer diagnostics, and VS Code syntax
support.</p>
<p>The project is still early. The goal right now is not to claim that AgentScript
is a mature production framework. The goal is to test a sharper language idea:</p>
<blockquote>
<p>What if the most important part of an agent program is not the framework
around the model call, but the context contract before it?</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it">Try It<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#try-it" class="hash-link" aria-label="Direct link to Try It" title="Direct link to Try It" translate="no">​</a></h2>
<p>Install the CLI:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token function" style="color:rgb(130, 170, 255)">npm</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">install</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">-g</span><span class="token plain"> @rong/agentscript</span><br></div></code></pre></div></div>
<p>Run a recipe:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">agentscript recipes/summarize-file.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"README.md"}'</span><br></div></code></pre></div></div>
<p>Run without installing:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">npx @rong/agentscript recipes/code-review.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"src"}'</span><br></div></code></pre></div></div>
<p>Use mock mode for deterministic local checks:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">agentscript recipes/summarize-file.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"README.md"}'</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--mock</span><br></div></code></pre></div></div>
<p>Use trace mode when you want to inspect what happened:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#bfc7d5"><span class="token plain">agentscript recipes/summarize-file.as </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--input</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'{"path":"README.md"}'</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(191, 199, 213)">--trace</span><br></div></code></pre></div></div>
<p>Project links:</p>
<ul>
<li class="">npm: <a href="https://www.npmjs.com/package/@rong/agentscript" target="_blank" rel="noopener noreferrer" class="">https://www.npmjs.com/package/@rong/agentscript</a></li>
<li class="">GitHub: <a href="https://github.com/rongzhou/agentscript" target="_blank" rel="noopener noreferrer" class="">https://github.com/rongzhou/agentscript</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="closing-thought">Closing Thought<a href="https://rongzhou.github.io/agentscript/blog/introducing-agentscript#closing-thought" class="hash-link" aria-label="Direct link to Closing Thought" title="Direct link to Closing Thought" translate="no">​</a></h2>
<p>LLM agents are often described in terms of tools, memory, planning, and
autonomy. Those things matter, but they all depend on a more basic question:</p>
<p>What exactly did the model see before it generated the next value?</p>
<p>AgentScript is built around that question. It treats prompt context as something
you declare, scope, budget, label, validate, and trace.</p>
<p>That is the language's bet: reliable agents need context engineering to be a
programming model, not a pile of conventions.</p>]]></content>
        <author>
            <name>Rong Zhou</name>
            <uri>https://github.com/rongzhou</uri>
        </author>
        <category label="agentscript" term="agentscript"/>
        <category label="context-engineering" term="context-engineering"/>
        <category label="llm-agents" term="llm-agents"/>
    </entry>
</feed>