Documents
Extension and Goals System
Extension and Goals System
Type
Topic
Status
Published
Created
May 27, 2026
Updated
May 27, 2026
Template

Overview#

The Codex extension system exposes contributor traits that allow features and external integrations to hook into the session, thread, turn, and tool execution lifecycle. The Goals system is a first-class built-in extension that uses these same hooks to implement persistent, resumable agent objectives with token-budget tracking.

As of v0.133.0, Goals are enabled by default — the feature is registered as Stage::Stable with default_enabled: true , no longer behind an experimental flag.

Key entry points:

  • Extension APIcodex-rs/ext/extension-api/src/contributors.rs : all contributor trait definitions
  • Tool lifecycle metadatacodex-rs/ext/extension-api/src/contributors/tool_lifecycle.rs
  • Goals runtimecodex-rs/core/src/goals.rs
  • Goals storagecodex-rs/state/src/runtime/goals.rs
  • Goals extensioncodex-rs/ext/goal/src/extension.rs

Extension Contributor Lifecycle Hooks#

All hooks are defined as async traits in contributors.rs. Each callback receives scoped ExtensionData stores (session_store, thread_store, turn_store) for managing extension-private state without touching core runtime objects.

Thread scope — ThreadLifecycleContributor #

CallbackWhen called
on_thread_startAfter thread-scoped extension stores are created
on_thread_resumeAfter runtime is reconstructed from persisted history
on_thread_idleAfter the host drains all pending thread work
on_thread_stopBefore the thread runtime and thread-scoped store are dropped

Turn scope — TurnLifecycleContributor #

CallbackWhen called
on_turn_startAfter turn-scoped stores are created, before the task runs
on_turn_stopBefore the completed turn runtime and turn store are dropped
on_turn_abortAfter the host aborts a running turn

Tool scope — ToolLifecycleContributor #

CallbackWhen called
on_tool_startOnce the host has accepted a tool call for execution
on_tool_finishAfter the tool returns, is blocked, fails, or is cancelled

ToolLifecycleContributor is observer-only — it cannot inspect or rewrite tool input/output .

Additional contributor traits#

Tool Execution Metadata for Extensions#

The ToolLifecycleContributor callbacks receive typed structs defined in tool_lifecycle.rs.

ToolStartInput — supplied when the host starts a tool call:

  • session_store, thread_store, turn_store — scoped extension data
  • turn_id, call_id — stable identifiers for correlation
  • tool_name: &ToolName
  • source: ToolCallSource

ToolFinishInput — all of the above plus:

  • outcome: ToolCallOutcome

ToolCallSource distinguishes how the call originated:

  • Direct — the model invoked the tool directly
  • CodeMode { cell_id, runtime_tool_call_id } — a code-mode runtime cell issued the nested call

ToolCallOutcome captures the host-observed result:

  • Completed { success: bool } — normal output; success is the tool's own success marker
  • Blocked — blocked by host policy before the handler ran
  • Failed { handler_executed: bool } — did not produce normal output
  • Aborted — host cancelled before normal completion; a matching on_tool_start may not exist

Subagent Lifecycle Events#

When a subagent's status changes, the runtime injects a SubagentNotification into the model context as a hidden user-turn fragment. The struct carries two fields: agent_reference: String (the agent path) and status: AgentStatus.

The notification implements ContextualUserFragment — it is wrapped in <subagent_notification> / </subagent_notification> XML tags and serialized as JSON with agent_path and status keys. This makes subagent state visible to the model's next turn without appearing as a user-visible message.

AgentStatus variants :

VariantMeaning
PendingInitWaiting for initialization (default)
RunningCurrently executing
InterruptedTurn interrupted; may receive more input
Completed(Option<String>)Done; optional final assistant message
Errored(String)Terminated with an error message
ShutdownShut down
NotFoundAgent reference could not be resolved

Goals System#

Goals let an agent track a persistent objective with a token budget across multiple turns, stored in a dedicated database table that survives thread suspension and resumption.

Feature flag#

Feature::Goals is declared Stage::Stable with default_enabled: true . It can still be overridden in ~/.codex/config.toml via [features] goals = false. The Goals extension checks self.enabled(Feature::Goals) before every operation .

Goal states#

A goal's ThreadGoalStatus follows this state machine :

ActivePaused | Blocked | UsageLimited | BudgetLimited | Complete

Runtime event dispatch#

GoalRuntimeEvent drives all state transitions. The session reports events; goals.rs owns the policy:

EventTrigger
TurnStartedNew turn begins; carries current token usage
ToolCompletedAny tool finishes; carries tool name
ToolCompletedGoalThe update_goal tool completes
TurnFinishedTurn ends; turn_completed: bool flag
MaybeContinueIfIdleCheck for goal continuation while idle
TaskAbortedTask abort (optional turn context)
UsageLimitReachedGlobal usage limit hit
ExternalSet / ExternalClearExternal goal mutation
ThreadResumedThread reconstructed from history

GoalRuntimeState manages concurrency with a semaphore-based accounting_lock and a separate continuation_lock.

Extension integration#

GoalExtension implements all six contributor traits, wiring goals into every relevant lifecycle gate:

TraitResponsibility
ThreadLifecycleContributorInitialize/rehydrate goal accounting on thread start/resume
ConfigContributorUpdate enabled state on config change
TurnLifecycleContributorAccount goal progress on turn start/stop/abort
TokenUsageContributorRecord token consumption during active goals
ToolLifecycleContributorAccount tool execution toward goal completion
ToolContributorExpose get_goal, create_goal, update_goal tools

Goal persistence is delegated to GoalStore in the state layer, which handles creation, status updates, and accounting-mode-gated writes (ActiveStatusOnly, ActiveOnly, ActiveOrComplete, ActiveOrStopped) .