The Thread Model

A thread is an isolated conversation history. The agent sees the full entry log of a thread on every call to it, and nothing from other threads. You compose threads deliberately to control what context the agent has at each point in a task.

This is the primary tool for structuring complex multi-step work.

The execution thread

Every script runs on an execution thread. Calls with no thread option share it automatically — the agent carries context across them without any explicit management.

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")
// agent sees r1 and r2 when producing r3

The execution thread is implicit. You don't name it, you don't pass it anywhere. It's the natural context for a script that does one coherent piece of work.

Named threads

Pass a string name to create an isolated branch. The agent on that branch has no context from the execution thread, and vice versa.

const r1 = await axon.request("reviewing the codebase now")  // execution thread

const research = await axon.request({
    prompt: "analyse the error in this stack trace: ...",
    thread: "sentry-debug",    // isolated — agent has no context from r1
})

// bring the result back
const r2 = await axon.request(
    `the debug analysis found: ${research.text}. incorporate this into the review.`
    // no thread: — back on the execution thread, agent sees r1
)

Name threads for what they're doing. The name is stable within a session — any subsequent call with the same name continues the same conversation.

Thread handles

When you make multiple calls to the same named thread, a handle avoids repeating the name:

const debug = axon.thread("sentry-debug")

await debug.request("what's causing the null reference on line 47?")
await debug.request("is this related to the auth refactor last week?")
await debug.request("write a minimal reproduction case")

axon.thread(name) returns a handle with .request() and .stream() — same signatures as the top-level calls, minus the thread field. Use handles whenever you're making more than one call to the same thread.

Parallel branches

Independent sub-tasks can run concurrently on separate threads. Results come back together and get synthesised on the main thread.

const [securityAudit, perfAudit] = await Promise.all([
    axon.request({
        prompt: "audit this codebase for security vulnerabilities",
        thread: "audit-security",
    }),
    axon.request({
        prompt: "profile the hot paths and identify performance bottlenecks",
        thread: "audit-perf",
    }),
])

const summary = await axon.request(
    `two audits just completed:\n\n` +
    `Security: ${securityAudit.text}\n\n` +
    `Performance: ${perfAudit.text}\n\n` +
    `Write an executive summary with prioritised recommendations.`
)

Each branch runs the full agent loop independently. The final synthesis call has no context from either branch — just the results you explicitly inject via the prompt string.

Persistent threads

Named threads persist across script runs within a session. A thread named "project-alpha" on Monday is still there on Tuesday, with full prior context intact.

// Monday
const project = axon.thread("project-alpha")
await project.request("we've decided to use a document model for the user store. document rationale.")

// Tuesday — same session, full history available
const project = axon.thread("project-alpha")
await project.request("what was the rationale for the database decision?")
// agent sees Monday's conversation and answers from it

Use persistent threads for ongoing projects where continuity across multiple work sessions matters. The thread name is the key — keep it stable and specific enough that it doesn't collide with unrelated work.

When to use each pattern

Execution thread — one coherent task with a natural progression. The agent should carry full context across every step.

Named side thread — a sub-task that would pollute the main context if run inline. Research, debugging, fetching reference material. Run it separately, inject the result.

Thread handle — whenever you're making more than two calls to a named thread. Cleaner than repeating the name, and gives you .entries for the full history.

Parallel branches — independent tasks with no dependency between them. Both need the same agent, neither needs the other's context during execution. Merge at the end.

Persistent thread — ongoing work that spans multiple script runs or multiple days. The agent's memory of prior decisions is load-bearing for the current task.

What threads are not

A thread is not a record of external events. If a GitHub issue arrives via webhook, the issue content goes in the prompt — not the thread. The thread is the agent's reasoning about that issue, not the issue itself.

A thread is also not a global log. Each thread is a narrow, purposeful slice of working memory. An agent with twenty threads covering twenty different topics doesn't have a single tangled context — it has twenty clean ones.