Tell Exo to drop a file and it leaves the window that turn — the tokens come straight back. No restart, no rebuild, no praying the harness forgets what you told it to forget.
What's in the model's head is yours to edit, mid-thought.
The harness is inert — it assembles nothing on its own. No hidden
system prompt, no auto-loaded files, no injected date. Whatever
.exo.context.ts returns is the entire context the model sees.
“AGENTS.md is a wish. context.ts is a program.”
// you own this file. the harness is inert — // whatever you return is the whole context. import type { Env, Ctx, Msg, Compaction } from "exo"; // front of the system prompt, loaded once → cached. // keep it stable; volatile data here busts the cache. export function alwaysPresentLoadedOnce(env: Env): string { return env.readFile(`${env.cwd}/AGENT.md`); } // re-run every turn, after the cached prefix — // the home for volatile data like the clock. export function eachTurnBeforeUserMessage(env: Env): string { return `Current time: ${env.now.toISOString()}`; } // you own where history comes from. export function conversation(ctx: Ctx): Msg[] { return ctx.linearize(ctx.sessionEntries, ctx.leafId); } // compact when the window gets tight… export function shouldCompact(ctx: Ctx): boolean { return ctx.budget.usedPercent > 80; } // …and how. summarize the older half, keep recent. export function compact(ctx: Ctx): Promise<Compaction> { return ctx.summarizeOlder(); }
Exo has none. Load all or none — assemble your context-as-code.
Your context deserves a compiler, not a markdown file.
export function alwaysPresentLoadedOnce(env: Env): string[] { return [ env.readFile(`${env.cwd}/ALWAYS_LOADED.md`), ]; }