Skip to content

Modules

A module is one unit of per-agent state with defined rules for four questions: what it contributes to its holder’s prompt, what it reports as telemetry, how it is copied, and what happens to it when a different agent takes it over. Everything an agent instance holds is a module: its conversation window, its memories, its task list, its handle on the board, the skills it has used, and its thread archive.

There are six kinds, and the list is closed.

KindWhat it holds
historyThe agent’s conversation window: every message, open view and pinned block. Always present.
memoriesThe memories it curates, under whichever strategy the capability configures.
tasksThe task list, a blocked-by DAG.
boardThe project-management board. Run-global: every holder holds the same board.
skillsIts profile’s skills catalogue and the set of skills used so far.
archiveThe thread archive archive_thread fills and search_archive reads.

What a module contributes to its holder’s prompt is fixed per kind; nothing about it is configurable, and an agent’s system prompt is never rewritten after it is created. A window is its holder’s prompt. A task list is what an agent steers by from turn to turn, so it is always carried as its own message. For memories the strategy already decides what the store puts in the window, and for skills its own catalogue is the only route an agent has to knowing which skills exist.

The project-management board and the agent-managed-context thread archive contribute nothing at all: no system-prompt section and no pinned block. Each is reachable through its tools alone — the tools read and write it, it is copied and transferred like any other module, and its telemetry is unchanged — so it costs its holder no context between calls. What the model gets is each tool’s own schema and description.

There are two ways to copy a module.

  • Fork produces an independent copy: a new backing store, deep-copied contents, and monotonic counters carried forward rather than restarted. The two copies diverge from the moment the fork is made, and neither sees the other’s writes. A fork leaves undrained telemetry with the original, so one write is one event on the stream of the agent that made it.
  • Share produces a linked handle on the same store. What one holder writes, the other reads. A new holder’s watermarks start at the store’s current head, so it is not handed a backlog of everything that happened before it existed, and each holder reports only its own writes.

Two kinds override the choice. The board is always shared, because two boards would each keep their own per-prefix issue counter and both hand out ABC-4 for two different pieces of work in a run whose logs, briefs and agent names all quote that id. The window is never shared, because the turn loop holds it exclusively for the whole of a turn; asking to share one yields an independent copy.

The skills module is copied in halves. The catalogue is the one its profile names a directory for, so a copy of the agent holds the same one, and two profiles naming one directory hold one copy between them. The read set, which records which skill bodies are already pinned in the window, follows the window it describes: a fork copies it and a share aliases it.

fork clones a whole set for a copy of the agent that made it, applying these rules per kind. A copy therefore gets an independent window and task list, a shared board, and memories that follow the forker’s scope. The copy’s memories are re-stamped with the copy’s own agent id, so its writes are attributed to it.

The code an agent has loaded by using a code skill or memory is not a module. It holds no context, is never summarized and is never transferred; a new instance starts with nothing loaded, and using the skill again is the whole of the recovery.

Handing a live module to an agent running under a different profile is a transfer, and it happens two ways. An FSM transition carries exactly the modules the edge names, and everything else the outgoing instance held is dropped. An exec carries every kind both profiles have, drops what the successor’s profile turns off, and starts fresh whatever only the successor has.

Per kind, one of four things happens:

  1. Carried. The module moves across live, with its contents, and is re-resolved against the receiving profile: its caps and its mode.
  2. Dropped. The receiving profile does not enable the capability.
  3. Dropped and re-initialized. The receiving profile configures the capability in a shape the contents cannot be read under, so a fresh module is started and the successor is told why in its opening note. The concrete case is a memory strategy mismatch: a scratchpad is not re-rendered as a markdown index, because that would change both what the store means and which tools read it.
  4. Initialized fresh. The receiving profile enables a capability the predecessor did not hold.

Two rules govern limits. A transfer re-points a store’s caps only when the module’s holder is its sole holder, since a store several agents curate together has one set of limits by construction. And caps tighten forward only: contents already over a newly resolved cap are kept, and it is the next write that is refused.

The window’s system prompt is never inherited. A system prompt states the toolset, the roster and the ending calls of the agent it was rendered for, and it sits in a slot of its own that renders first on every request rather than in the thread. A window crosses a transfer or a fork with that slot empty, and the successor’s loop fills it with its own before its first turn. The whole thread is what the successor keeps, and the turn counter is never renumbered.

Only an FSM transition names modules explicitly, and the six kind names are the vocabulary its transfer list is written in. The console’s state editor renders them as a checkbox each. A name that is not one of the six refuses the launch, and so does an edge naming a kind the outgoing state’s agent would not hold — which is its profile’s own switch for every kind but the board, and the board is the run’s, held by every agent in a run that has one. Where only the live module set settles it, a transfer meeting a kind its predecessor does not hold is gg’s own defect and ends the run under internal_error.

A module’s telemetry is attributed to its holder, which is what keeps the console’s per-agent panels honest when a store has more than one. A write is reported once, on the stream of the agent that made it. Every other holder re-emits its own state snapshot instead, because its panel changed while the work was not its own.

A module that is dropped is drained onto the outgoing agent’s stream before it goes, and every module the successor ends up with re-states itself on the successor’s stream as soon as it arrives. The console reduces per agent, so a module that arrived silently would leave the successor’s panel empty for the rest of the run.

Every backing store carries an id, such as memories-2, tasks-0 or board-0, minted once per kind for the life of the run. The id belongs to the store rather than to the holder: two holders reporting the same id are holding one store, and two ids are two stores that may merely happen to agree.

The id follows the store through every operation above. A share keeps it, a fork mints a new one, and a transfer carries the one it was handed. The one transfer that swaps the store underneath a successor, a shared memories binding re-pointing to the successor’s own profile, reports the new id.

Each agent instance reports its whole set as it opens: one roster row per kind, naming the store it bound, whether the capability is on, how it came by it (created, inherited, profile, run, transferred or forked), and, for memories, the scope it declared and whether it may write. A roster cannot change within an incarnation, since every operation that changes what an agent holds mints a new agent id, so it is stated once and never restated. See Telemetry for the events.

A module instance is not one-to-one with an agent instance, so three surfaces read the same folded model at three grains. Between them they answer which instances share a store, when it was handed on or copied, what it costs the windows carrying it, and whether anything is in it. A store described as shared by four holders on one surface reads the same way on the other two.

Every agent instance’s folder carries a modules folder, closed by default, holding one file per module it holds in kind order. It sits after the agent’s own files (Overview, Prompt, Surface, Activity, Context, Requests, Metrics and Compaction) and before that instance’s successors and its subagents.

A row whose store is held by more than one instance at once carries a link glyph and that count. A store that merely passed from one instance to the next is annotated handed on and is counted as shared nowhere. Sharing is read off the holders whose origin is not transferred, the ones that joined the store rather than replacing its previous holder; without that rule every exec would look like sharing and an FSM run would turn one conversation window into an N-holder store.

The history file carries the window’s message log itself, the same turn-by-turn view the Requests file renders. Every other kind’s file states its figures the way the Modules tab’s overviews do: a row of large values over muted labels.

Each file leads with an identity strip carrying the store’s id, its kind, how this holder came by it, its read access, everything that has happened to it, what it costs this window every turn and what it costs across every live holder, and a chip per co-holder that opens that instance’s same file. A store every holder has let go of is badged dropped.

The strip’s link to the Modules tab is offered only when the run has that tab. Every instance of every run holds a window, so a modules/history file exists in runs the tab is not offered for.

The Modules tab sits between Instances and Project and is offered whenever any profile enables a module-backed capability. It groups module instances by kind, and a store shared by four agents is one row however many hold it.

Each kind’s group leads with an overview covering how many stores exist, how many holders they have between them and how many are still running, how many are genuinely shared and how widely, what they cost every turn summed over the windows carrying them, how many were never written to, and every store side by side.

Two figures are withheld where they would be a lie rather than a zero. History reports no “holding nothing” figure, because a window reports itself per turn as a context breakdown rather than as a snapshot of a store. And a per-turn cost of zero is distinguished both from an unmeasured one and from the archive, which has no context band by construction.

Selecting a store reads it in five sections: its identity; its holders, each with its origin, read access and what the module costs that instance’s window; its lifetime, oldest first, each entry naming the succession that caused it; its cost per holder against the summed live figure; and its contents, taken from the store’s own snapshot. History and archive report no snapshot, so their contents are read off their holder’s stream.

Holder ids link into the Instances tab at that agent’s own modules/<kind> file, and profile names into the Agents tab. The Instances module file links back.

The Agents tab reads the run per configured profile, which is the grain a configuration is tuned at. A Modules section under each profile’s instance chips carries one row per kind, badged by how the stores are distributed:

BadgeWhat it means
agent-scopedOne store, bound by every instance at once. The contents belong to the agent, so they are shown inline.
per instanceEvery instance holds its own. Nothing is shown inline; Compare in Modules puts them side by side.
handed onOne store, held one instance at a time. It has several holders and is not sharing.
run-globalThe store reaches beyond this profile: the board, or a store a spawner of another profile owns.
splitSeveral stores, at least one genuinely shared. Usually worth opening.

Where the declared configuration and the observed distribution disagree, the row carries a note naming both and the likely cause: a scope: inherited whose instances each got their own, or a shared profile re-bound mid-run by a succession. Each of those is a legal configuration, so it is a note rather than an error. Notes are written only for a run that reported its rosters.