Skip to content

Object model

The nouns and verbs of the whole runtime: Pi, our extension packages, Pi core, and every frontend. The glossary owns the names, one or two sentences each. This page holds how they relate, their lifecycles, the verbs that change them, and where each comes from in Pi. The TUI’s object model keeps only what belongs to the TUI: its regions, components, keys, and visual rules. Why we took Pi’s model is in decision 0006.

Code and tool text still carry some older words. Where the code differs lists them, with the gaps between today’s behavior and this model.

Pi has two models, and this one reads both:

  • Pi’s coding agent, 1.3.0. What we run: session files, the entry tree, extension events, and RPC. Sources: Pi’s docs/how-pi-works.md, sessions.md, session-format.md, message-types.md, extensions.md, json.md, rpc.md, and rpc-commands.md, and pi-agent-core’s README.
  • pi-durable, 1.2.0. Pi’s experimental durable harness (packages/durable, read at upstream 3daa202), with a normative spec. It is Pi’s newest model, and the only one that names inputs, answers, owned work, and background boundaries. The coding agent does not use it yet.

Rules:

  1. Where Pi has a word, use it with Pi’s meaning.
  2. Where the two Pi models differ, take durable’s word for what it defines: input, answer, run, task, outcome, and owner. Take the coding agent’s word for the host we run: session, entry tree, branch, delivery, events, and RPC.
  3. One exception: we say async task where durable says background task.
  4. Define a my-pi concept as an addition to Pi’s model, in Pi’s nouns, not as a parallel model.
  5. Presentation nouns derive from domain nouns and own no lifecycle.
  6. Adopting durable’s words does not adopt its API. Our code stays on the coding agent.
Session: a tree of entries; the active branch is the history; runs with an Agent
User turn: opened by a user's input; holds runs until its final answer
Input: submitted, queued, placed as a user entry, answered by a Run
Run: Turns, from an input to its answer; each turn is one assistant message and its tool calls
Tool call: may launch an Async task (a shell task, a subagent)
Async task: its origin is the user turn whose run launched it
Subagent: owns a child Session
Async task ends: an outcome, and a result it delivers to the session
Wake: a delivered result that triggers a run, which belongs to the origin's user turn
User turn done: its final answer is the last answer once nothing it launched can wake it

A noun whose Pi source says “none” is my-pi’s own, defined in Pi’s terms.

NounMeaningPi source
SessionOne saved conversation: a file of entries in a tree, with an id, a name, and a working directory. What the user resumes, forks, and names.coding agent sessions.md; durable calls it a conversation
EntryOne immutable record in a session: a message, a model or thinking change, a compaction, a branch summary, a label, session info, or a custom entry.session-format.md; durable Entry
MessageAn entry’s model-facing content: user, assistant, tool result, custom, bash execution, compaction summary, or branch summary.message-types.md
Active branchThe path from the root to the current entry. It supplies the history of the next model request.how-pi-works.md
Tree, fork, clone/tree moves within a session; /fork starts a new session from an earlier user message; /clone copies the active branch into a new session.sessions.md; durable has only fork, which creates a conversation
CompactionA summary entry that replaces older history in later model requests. The entries stay.compaction.md; durable pi.compaction
Custom entry, custom messageExtension data kept out of the model’s context, and extension content sent in it.session-format.md; durable write submissions
TranscriptThe entries of the active branch, as recorded. What is drawn is the transcript view.durable: “a conversation is a transcript”; the coding agent uses the word for both the record and the screen
ContextWhat the model receives for one request: the system prompt, the active branch’s messages after compaction, and the tools.how-pi-works.md#context; durable §2.1
NounMeaningPi source
InputSomething submitted for the model to answer: a prompt, a steer, a follow-up, or a wake. It is placed as a user or custom message entry.durable input submission; coding agent prompt, steer, followUp, sendMessage with triggerTurn
QueueInputs waiting for a boundary: steers, placed after the current tool round, and follow-ups, placed once the run answers.coding agent queue_update, clear_queue; durable inbox
TurnOne assistant response and the tool calls it makes.all three sources agree
RunThe turns from an input to its answer. A steer joins the current run; a follow-up starts the next one.durable §1; the coding agent calls agent_start to agent_end a “low-level run”
Model requestOne provider request. A turn makes one; retries and compaction make more. Say “model request”, not “request” alone.coding agent, durable
Tool callOne invocation in an assistant message. It runs after its message ends. A tool can call other tools as nested calls.message-types.md; durable §7.3
AnswerThe assistant message that ends a run without tool calls. It answers the run’s input and every steer that joined the run.durable: a done submission names its answer entry
User turnOne request to the agent and all the work for it, until its final answer. “User” is Pi’s user role, whoever the agent answers: a person, a frontend, a parent agent, a Goal, or a supervisor. It holds the steers that join its runs and the runs its async tasks’ wakes start. “Turn” alone stays Pi’s turn.none: Pi’s turn is one model response; durable’s run ends at the first answer
Final answerA user turn’s last answer, once nothing it launched can wake the session.durable’s answer, extended by the user turn
Busy, idleA session is busy while a run is active, including from one queued run to the next. It is idle once Pi will not continue on its own. Becoming idle is settling. The coding agent’s span up to agent_settled is busy, not a run, and agent_start to agent_end is an event pair, not a noun.durable “busy”; coding agent agent_settled
NounMeaningPi source
TaskA unit of work with an owner and an outcome: a tool call or an async task.durable Task: every task has an owner, its conversation or another task
OwnerWhat a task belongs to. Aborting an owner aborts what it owns, and an owner stays busy while what it owns runs.durable §5.4
OutcomeHow a task ended: completed, failed, or aborted.durable TaskOutcome
Async taskA task launched by a call that returns at once. It runs outside its session’s busy and abort scope, so the session can settle and take new input, and Esc does not reach it. Its result arrives later.durable background task, { background: true }
Shell taskAn async task that runs one shell process group: the bg tool’s object, with its output file.none
Persistent jobA shell task that runs until stopped, such as a server. It never holds its origin waiting.none
SubagentAn async task that owns a child session launched from an agent definition. In a headless parent, the launch waits for the child instead, so it is ordinary tool work there.durable example 23, persistent background subagents
ChildA session owned by a task in another session: a subagent’s or a supervised one.durable task-owned conversation
ResultWhat an async task hands back when it ends: its outcome and output, as a message to its session.coding agent tool result; durable task result
WakeA delivered result that triggers a run: an input from an async task rather than the user. Its run belongs to its origin’s user turn.durable example 23: a background reporter posts the answer back as a follow-up input
OriginThe user turn whose run launched an async task.durable derives it from ownership: tool call, then run, then input
Wake-capableAn async task whose result will wake the session: not persistent, with delivery and its run trigger on.none
Settle reportAn entry a child appends after each settle: its user turn is waiting on wake-capable work, or done. Its parent ends the subagent only on done.none
NounMeaningPi source
AgentWhat a session runs with: model, thinking level, extensions, tools, instructions, and working directory.durable pi.agent
Agent definitionA named partial agent for a child: its roster line and added instructions.none
Model, provider, thinking levelAs Pi defines them.coding agent, pi-ai
ExtensionA module Pi loads that registers tools, commands, event handlers, providers, renderers, and UI. Extension package and entrypoint are my-pi’s words for how we ship them.coding agent; durable “a named bundle”
Tool, command, skill, prompt template, themeAs Pi defines them.coding agent
SettingsRun policy read at each use.settings.md; durable HarnessSettings
ModeHow Pi runs: interactive, print, JSON, or RPC.how-pi-works.md#interfaces

These keep their meanings, now defined over the nouns above: goal; coordinator; supervisor project, with its units, attempts, lease, and inbox; primary checkout; worktree; work root, the directory a session’s tools operate in, which worktree enter sets without replacing the session; aside, a fork opened in another pane; pane agent; gateway profile; frontend; and Pi core. The glossary defines all but worktree.

These derive from the nouns above and own no lifecycle.

NounDerived from
Transcript viewThe transcript as a frontend or display draws it. Display hides rows of the view, never entries.
SegmentThe transcript view’s span of one user turn. A steer can start another segment inside it, to keep the text drawn before the steer.
Status block, status rowThe running user turn, else the newest one that waits; the row also names the other user turns’ waits.
Answer summaryA done user turn’s one-line record: its active time and tool calls.
NoticeA transient UI message, Pi’s ctx.ui.notify. A result is not a notice.
BlockOne drawn transcript entry in my-tui.
Dialog, status entry, widget, footerExtension UI, as Pi defines it.

Retired words are listed in the glossary, each under Avoid in the entry for the word that replaced it.

Eight verbs, grouped by who does them. Steer and follow-up are modes of submit, not verbs.

ActorVerbActs onMeaningPimy-pi surface
user, extension, tasksubmitinput, as a prompt, steer, or follow-upHand an input to a session: a prompt when idle; a steer or follow-up when busy.RPC prompt with streamingBehavior; sendUserMessage; durable submit with whenBusyEnter; Alt+Enter
userwithdrawqueued inputTake it back out of the queue.RPC clear_queue; durable submission.abort()Alt+Up; Esc returns it to the draft
user, modelabortthe run, or one async taskStop it and the work it owns. Aborting the run withdraws queued inputs; async tasks continue.RPC abort; durable abort()Esc (app.interrupt); bg stop, subagent stop
userreplacesessionSwap the running session for another: resume, new, fork, or clone.session_before_switch; RPC switch_session, new_session, fork, clone/resume, /new, /fork
userconfigureagentChange the model, thinking level, or tools.set_model, set_thinking_level; durable configure()Ctrl+L, Shift+Tab
model, through a toollaunchasync taskStart an async task; the call returns at once.durable createTask with background: truebg run, subagent start
async taskdeliverits result, as a follow-up, except a subagent’s result in a headless parent or a nesting child, or from a launch that fails, which steers; a subagent’s ping or ask, as a steerSend the result to its session. A delivery that triggers a run is a wake; one that does not is appended. A result withdrawn from the queue, by a withdraw or an abort, is delivered again once; after an abort it joins the next run instead of starting one.sendMessage with deliverAs and triggerTurnshell tasks, subagents
extensionappendentryRecord an entry the model does not answer: a custom entry, or a custom message without a trigger.appendEntry, sendMessage; durable writesettle reports, status records

What the verbs absorb:

  • Steer and follow up are modes of submit, as they are Pi’s streamingBehavior, deliverAs, and whenBusy values.
  • Notify, wake, and report are deliver. Wake stays a noun, and a child’s report to its parent is its delivered result.
  • Stop is abort applied to one async task; the tool action keeps the name stop.
  • Revise is no act of its own: a wake’s run belongs to its origin’s user turn, so its answer becomes that user turn’s latest answer. That is answer continuation.
  • Place, answer, and settle are transitions Pi performs, so they live in the lifecycles below.
  • Compact, name, and /tree stay Pi’s session commands, not domain verbs.

Transitions are Pi’s; the verbs above cause some of them.

Durable’s submission states:

submit ─▶ queued ──place──▶ placed ──answer──▶ done
│ │
└──withdraw────────┴──abort, failure──▶ unanswered (aborted, failed, reset)

An input submitted to an idle session is placed at once; done carries the answer entry.

My-pi’s addition, over the runs it holds. What starts one:

InputEffect
A prompt or follow-up: from a person, a frontend, or a parent agent sending its child a taskstarts a user turn
Goal’s start and resume, sent after the user’s /goal, and an arranged Goal wakestarts a user turn
A supervisor wakestarts a user turn
A steerjoins the running user turn
An async task’s resultruns in its origin’s user turn, never a new one
A stall retrycontinues the user turn whose run it recovers
open ─▶ running ──a run answers──▶ waiting ──nothing left that can wake it──▶ done
▲ │ │
│ └──abort, failure──▶ unanswered
└────a wake starts a run──┘
  • A user turn is running while one of its runs is active, and waiting once a run has answered while a wake-capable async task it launched is live. Its latest answer is provisional meanwhile, and the session may be idle or running another user turn.
  • A wake starts a run in its origin’s user turn, and that run’s answer becomes the user turn’s latest answer.
  • With nothing left that can wake it, the user turn is done, and its last answer is its final answer. A user turn that launched nothing wake-capable is done at its first answer.
  • A child’s settle report is this state for the child’s own user turn: waiting or done.

Durable’s task states are pending, running, waiting, completing, then terminal, with the outcome completed, failed, aborted, orphaned, or faulted. An async task delivers its result as it completes, and is terminal once that result is in the session, or at once when it delivers none.

OursDurable outcome
shell task completed; subagent completedcompleted
shell task failed (exit code, timeout, output cap, signal); subagent failedfailed
shell task killed; subagent cancelledaborted
subagent timed-out, idlefailed, with our reason; both are local additions

The async-task service lists our tasks the same way: running; completing from the known outcome until the result is in the session; then terminal, at once for a task that delivers none.

A session is busy or idle, and it settles when it becomes idle. Herdr’s working, blocked, and idle are a different reading, of the pane, and stay separate: architecture keeps the rule against one universal busy flag.

The model is ahead of the code in these places:

  • An aborted user turn that still waits keeps waiting. In the model it ends unanswered at the abort, and a later wake from one of its async tasks reopens it. The code leaves it waiting, so that wake runs in it and one answer summary covers both. A wake whose origin is not open, such as a /bg task’s, starts a user turn of its own.
  • Segments follow component order, not user turns. A run that a hidden message starts, such as a Goal or supervisor wake, while an earlier user turn waits draws in that user turn’s segment, because no drawn row marks where the new user turn starts. Live answer ids keep each user turn’s latest good answer visible even when segments overlap; a wake’s revision draws where its run runs, below any later user turn. The transcript view hides the answer it replaced only while user-turns remembers those ids, in memory: a reload falls back to component order.
  • A result in another user turn’s run revises nothing. A result that an abort drops joins the next run, which usually belongs to another user turn; that run answers it, and the origin’s earlier answer stays its final answer.
  • “Answer” has two readings. Display’s draw rule shows a segment’s last assistant message with visible text. The model’s answer is the message that ends a run without tool calls, which can be thinking-only or empty.
  • The async-task service keeps an older reading. It lists a Goal-owned subagent as wake-capable, though Goal’s guarded wake can decline to start a run.

Some names keep older words, on purpose or until a rename:

ConceptName in code or session files today
A shell task’s resultthe bg tool’s notifyOnCompletion parameter
User turnthe turn title of tui-display’s status block