State Model
An agent isn't a stateless function. Between a bare axon.request("hello") and a
multi-day project thread, there are four distinct layers of state, each with different
scope and lifetime. Understanding which layer holds what explains why the agent remembers
some things and not others.
State layers, outermost to innermost:
| Layer | Scope | Lifetime |
|---|---|---|
| Base state | All sessions | Process lifetime |
| Session state | One working session | Until session ends |
| Thread state | One conversation lineage | Within session |
| Request context | One invocation | Cleared when loop completes |
Base state
Base state is what the agent is when nothing is happening. It comes entirely from the agent folder and is loaded by the runtime.
src/boot.vue— identity, working practices, standing instructionssrc/tools/— what the agent can callsrc/prompts/— available context templatesaxon.config.ts— engine, policy, environment- Installed modules — their tools, prompts, and routes
Base state changes when source changes. In local development, hot reload applies those changes to future work without rewriting the current session or thread history. Nothing that happens during execution changes base state.
This is why the agent's identity and working practices don't drift over a session — they come from source, not from conversation history.
Session state
Session state accumulates over a working session. It includes conversation history across
all threads, summaries the runtime builds as threads grow, and any material the agent
writes to data/sessions/.
A session typically maps to one working context — one day's work on a project, one deployment cycle, one support shift. Sessions persist to disk, so they survive agent restarts.
Session state is the agent's long-term working memory. It's why an agent can be restarted and still know what it was working on.
Thread state
A thread is a scoped slice of working memory for one conversation lineage. The agent sees the full history of a thread on every call to it, but not the history of other threads.
This is the primary tool for structuring complex work. A main execution thread carries the primary conversation. Named side threads handle isolated sub-tasks without polluting the main context. Parallel threads run independent research simultaneously.
// three calls on the execution thread — agent sees full history across all three
const r1 = await axon.request("what's the current sprint status?")
const r2 = await axon.request("which issues are blocking the release?")
const r3 = await axon.request("draft a status update for the team")
// side thread — isolated, agent has no context from r1-r3
const r4 = await axon.request({
prompt: "research the error in the sentry trace",
thread: "sentry-investigation",
})
Thread state persists within a session. Named threads — those with an explicit string name — also persist across script runs within the same session, so work can be resumed.
For the full thread composition patterns, see axon.
Request context
Request context is temporary task state for a single invocation. It's what you pass to
axon.request() or axon.stream() — rendered prompts, policy narrowing, inline data.
const context = await axon.prompt("project-context") // standing task framing
const review = await axon.prompt("code-review", { issueId }) // task-specific context
const result = await axon.request({
prompt: [context, review], // request context
policy: { fs: { write: false } }, // narrowed for this invocation
})
// prompt and policy are gone when this completes
Request context is consumed and cleared when the loop completes. Loading a support ticket for one invocation doesn't permanently teach the agent about that ticket — the next invocation starts without it.
This is what makes agents predictable. The same agent handles a hundred different tasks over a session without cross-contamination between them.
Why the layers exist
Each layer exists because it has different ownership and different change cadence.
Base state changes when you edit the agent source. Session state changes as the agent works. Thread state changes per conversation. Request context changes per call.
If everything lived in one pool, an agent that handled a hundred tasks in a day would have a context window full of noise by task fifty. The layering keeps each invocation focused on what's relevant — the agent's permanent identity, the session's accumulated context, the thread's conversation history, and the specific task at hand.