# Four ways to organize the same feedback loop

All four harnesses turn model output into tool execution and feed the results back. The useful comparison is where each places decisions about state, authority, concurrency, and continuation. Sidekick also wraps external harnesses; its native execution path is the comparison target here.

The short descriptions below are an interpretation of the inspected architecture, not a claim about which product is best. See the [methodology](methodology.md) for pinned revisions and scope. The website's comparison explorer exposes all 15 dimensions with per-cell qualifications and direct source links.

## The architectural center

| Harness | Center of the design | What a builder can learn |
| --- | --- | --- |
| Codex | Session tasks contain repeated sampling steps; tools execute against a captured step context through routing and policy machinery. | How to preserve coherent execution settings while tools, clients, and context change. |
| pi | A reusable agent loop exposes hooks; the coding session adds application behavior around it. | How to separate provider normalization, loop scheduling, and product-level state. |
| Goose | An ordered set of operations inspects session state; the first applicable operation emits effects, then the machine scans again. | How to make continuation decisions reconstructible from persisted state. |
| Sidekick | Durable turns and worker attempts coordinate an iterative model/tool loop through workflows, message reducers, and recorded tool intents. | How to distinguish admitted work from a worker's lifetime and recover without assuming an uncertain tool never ran. |

Sources: [Codex turn preparation][c-loop], [pi loop][p-loop], [Goose state machine][g-loop], [Sidekick native loop][s-loop] and [attempt ownership][s-attempt]. Sidekick's repository is private; its pinned source links require repository access.

These are different decompositions, not mutually exclusive strategies. Pi's coding application still has persistence. Codex still has a repeated sampling loop. Goose still needs a provider adapter and executable tools. Sidekick still iterates within its conversation workflow.

## Compare behavior, not feature counts

| Concern | Codex | pi | Goose | Sidekick |
| --- | --- | --- | --- | --- |
| Concurrent tools | Parallel-capable calls share an execution lock; exclusive calls take a write lock. Results drain into history in call order. | Parallel by default after ordered preflight; any sequential tool can serialize its batch. Results are recorded in call order. | An ordered operation dispatches tool work, then polls concurrent streams. Results are recorded as observed and associated by request ID. | Tool workflows may overlap; correlated results return in model call order. [Source][s-order] |
| Context management | Client-managed or provider-supported summarization, optional background compaction, and a distinct token-budget rollover path. | Compaction entries summarize history while preserving raw JSONL records and a recent projected tail. | Compaction changes model visibility and adds summary records while retaining conversation history. | Optional trimming replaces old large tool outputs in request context; native full-history summary compaction was not established. [Source][s-context] |
| Steering | Active-turn input admission, expected-turn checks, and some feature-controlled sampling preemption. | Input arriving during a response/tool batch is consumed after that batch; additional polls occur before requests. Follow-up waits for natural quiescence. | Queued guidance consumed between model/tool phases; shared run IDs support cross-connection steering. | Durable steers enter at the main loop's next iteration; answered settlement admits waiting follow-ups as a new turn. [Placement][s-loop], [follow-up][s-followup] |
| Persistence | A storage interface distinguishes append contexts and explicit durability barriers. | Coding sessions use append-only JSONL trees. A separate experimental durable runtime has stronger recovery contracts. | SQLite session state and operation notes participate directly in state-machine decisions. | Turn, attempt, and tool-intent records distinguish committed outcomes from uncertain execution. [Source][s-recovery] |
| Multi-player foundations | Multiple subscribed connections and attach/history ordering. | Replicated view primitives in Chord/durable; coding RPC is a separate subprocess interface. | Shared active-run arbitration and steering across ACP connections. | Shared conversations have view/edit/manage access; sending requires edit and admission is serialized. [Source][s-sharing] |
| Multi-agent support | Child-thread lifecycle tools and control rules. | Optional coding-agent example; separate durable child-conversation examples. | Foreground child sessions with progress, result delivery, and approval forwarding. | Owned child turns and peer panels use distinct coordination rules. [Delegation][s-child], [panels][s-panel] |
| MCP and code mode | Deferred tool search and V8 orchestration; nested calls reenter the tool runtime. | Built-in MCP and selectable QuickJS code mode; nested calls retain tool hooks. | MCP-based extension layer and optional Boa code mode; nested callbacks have a different approval boundary from direct calls. | Neither native MCP integration nor MCP code mode was established; external adapters are a separate scope. [Review](../snapshots/sidekick/463d653124e1/chapter.md#context-collaboration-and-tool-authority) |

Each row compresses important details. Follow the evidence in [Codex](../snapshots/codex/8c076942cb70/chapter.md#evidence-matrix), [pi](../snapshots/pi/482c1381a00d/chapter.md), [Goose](../snapshots/goose/34a222e3f2b9/chapter.md), and [Sidekick](../snapshots/sidekick/463d653124e1/chapter.md), or expand the corresponding website cells. A “core” or “optional” label is a scope marker, not a quality score.

## Follow one problem across the designs

### A tool takes longer than its neighbor

The model requests reads A and B; B finishes first. Codex and pi can report progress while retaining call order in the final transcript. Goose records observed results with IDs. Sidekick submits separate tool workflows, collects results by correlation ID, and returns the batch in call order. These approaches can represent the exchange correctly. The tradeoff is between a predictable source-order transcript and immediate append of the observed outcome; client code must understand which contract it consumes. [Codex ordered drain][c-order], [pi scheduling][p-order], [Goose execution][g-order], [Sidekick collection][s-order].

Now replace read B with “test the file after edit A.” These are dependent actions. None of these scheduling descriptions proves the harness infers that dependency from natural-language tool arguments. Put dependent work in separate model steps or explicitly sequence it in a supported orchestration program.

### The user changes their mind during execution

“Steer” can mean “queue this for the next safe boundary,” not “stop the current tool.” Pi explicitly finishes the current batch before consuming steering. Codex has active-turn admission and feature-dependent preemption paths. Goose consumes queued input through a state-machine operation after the relevant model/tool phase. A client should distinguish queued, admitted, executed, and cancelled states. [Pi loop][p-loop], [Codex turn processing][c-loop], [Goose steering][g-steer].

Sidekick makes the queue itself durable. Its main bound-agent loop places steers before rebuilding context, commits them, then broadcasts their placement. Follow-up admission occurs after an answered settlement. Those are separate boundaries from cancellation and from child or panel execution. [Sidekick iteration boundary][s-loop], [next-turn admission][s-followup].

### A conversation is too large

Codex, pi, and Goose can continue from summary-based representations, but they store and adopt them differently. Codex has multiple compaction/rollover paths. Pi projects an append-only session tree using compaction checkpoints. Goose uses conversation visibility plus inserted summary records. Sidekick's inspected native pipeline instead establishes optional trimming of older, large tool outputs; this is not evidence of equivalent full-history summary compaction. [Sidekick context factory][s-context]. “Compaction supported” therefore says little about retained raw history, replay, adoption races, or context reconstruction. The [advanced chapter](advanced-topics.md) compares those contracts.

### A worker disappears while a tool is running

Sidekick separates the user's turn from the worker attempt processing it. A replacement attempt can take ownership, then inspect recorded tool intents before another model request. A settled intent supplies its saved result. An uncertain running call may rerun only when stored and current replay policy allow it; an unsafe call receives an interrupted-result explanation instead. Ownership prevents a superseded worker from settling the turn, but cannot undo an external effect. [Attempt ownership][s-attempt], [intent recovery][s-recovery].

This illustrates event-driven orchestration: admission, completion, and recovery change durable state and determine which work may execute next. Panel completion provides another example: the last completed or failed grant in a batch makes a moderator wake eligible. The native model/tool continuation remains an ordinary loop. The session reducer is not a complete event-sourced history, and this comparison does not establish Sidekick as the only event-driven harness. [Panel completion][s-panel], [native iteration][s-loop], [dispatch and storage boundaries][s-dispatch].

The [event-driven execution topic](advanced/event-driven.md) follows Sidekick's orchestration boundaries and compares their costs with the other designs.

## What to borrow first

For a small custom agent, study pi's explicit loop and hooks before adopting its surrounding application. For a runtime reconstructed from stored state, study Goose's operation/effect boundary. For a long-lived coding system with changing tools and multiple clients, study Codex's step snapshots, execution scheduling, and persistence barriers. For a shared service where work can outlive a worker, study Sidekick's turn/attempt distinction and tool-intent recovery.

These are educational suggestions grounded in the architectures, not deployment recommendations or measured rankings. Copy the invariant you need before copying the surrounding machinery. A script with one trusted tool may need only a loop and cancellation. A shared service with remote effects needs identities, policies, durable state, and recovery semantics even if its model loop stays small.

[c-loop]: https://github.com/openai/codex/blob/8c076942cb70fba8e5c4732c23f1faabc4aed484/codex-rs/core/src/session/turn.rs#L166-L570
[p-loop]: https://github.com/earendil-works/pi/blob/482c1381a00d8d00bc81697e4a980c593db6803e/packages/agent/src/agent-loop.ts#L159-L321
[g-loop]: https://github.com/aaif-goose/goose/blob/34a222e3f2b95d8b4a43482b53c2cc957ecce26d/crates/goose-agent/src/machine.rs#L118-L292
[c-order]: https://github.com/openai/codex/blob/8c076942cb70fba8e5c4732c23f1faabc4aed484/codex-rs/core/src/session/turn.rs#L2568-L2695
[p-order]: https://github.com/earendil-works/pi/blob/482c1381a00d8d00bc81697e4a980c593db6803e/packages/agent/src/agent-loop.ts#L498-L650
[g-order]: https://github.com/aaif-goose/goose/blob/34a222e3f2b95d8b4a43482b53c2cc957ecce26d/crates/goose/src/agents/state_machine/ops_toolcalling.rs#L664-L1106
[g-steer]: https://github.com/aaif-goose/goose/blob/34a222e3f2b95d8b4a43482b53c2cc957ecce26d/crates/goose/src/agents/state_machine/ops_steer.rs#L46-L98
[s-loop]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick_worker/services/agent_loop.py#L397-L513
[s-attempt]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/services/turn_record.py#L900-L1027
[s-order]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/services/tool_executor.py#L238-L393
[s-context]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/services/context_pipeline/factory.py#L34-L117
[s-followup]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/services/message_queue.py#L603-L679
[s-recovery]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/services/intent_recovery.py#L475-L651
[s-sharing]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/routers/conversations.py#L2010-L2045
[s-child]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/services/tool_executor.py#L46-L126
[s-panel]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/services/panel_session_service.py#L433-L508
[s-dispatch]: https://github.com/datex/sidekick/blob/463d653124e1c2cda46a3f14f01f3d6f384326b1/backend/src/sidekick/services/session_dispatch.py#L171-L219
