Start with a familiar workflow. You ask Codex to write an article, explicitly invoke $article and $image, keep Browser and GitHub plugins enabled, expose a large MCP tool set, and maybe spawn a subagent to review the draft. All of that is "capability" in everyday language, but the source does not treat it as one blob.

Codex separates the shapes. Some capability becomes prompt context, some becomes tool specs, some becomes a package boundary, and some becomes another thread. Those paths still serve the same user turn, but they are owned and projected differently.

The useful reading model is simple: extensions enter the current turn as bounded runtime inputs. skills enter context, plugins provide package boundaries and roots, MCP enters tool exposure, and subagents enter the thread control plane.

Evidence boundary. This article only describes behavior visible in the public openai/codex source: skill discovery and injection, plugin manifests and load outcomes, MCP tool exposure, tool_search, dynamic tools, the multi-agent tool surface, and AgentControl. References to apps, plugins, and subagents mean those public runtime structures.

This part follows six questions:

  1. Why separate context capability, tool capability, and thread capability?
  2. Which TurnContext fields receive extension inputs?
  3. How does a skill move from catalog entry to full SKILL.md injection?
  4. How does a plugin package skills, MCP servers, apps, and hooks?
  5. When are MCP tools exposed directly, and when are they deferred to tool_search?
  6. Why is a subagent a child thread rather than an ordinary tool result?

1. Four Capability Shapes

The hardest part of this area is vocabulary. The UI may call many things "capabilities", but the runtime needs sharper boundaries.

Shape User-facing entry Runtime entry Owner to follow
Working method $article, $image, or a structured skill selection. The catalog is visible first; full SKILL.md content is injected only when selected. SkillsManager, build_skill_injections.
Capability bundle Browser, GitHub, Documents, and other plugins. The manifest declares skills, MCP servers, apps, and hooks; loading produces effective roots and summaries. PluginManifest, PluginLoadOutcome.
Callable tool MCP server, app connector, or dynamic tool. Converted into model-visible tool specs; large tool sets can be deferred behind tool_search. build_mcp_tool_exposure, ToolSearchHandler, ToolRouter.
Parallel work unit spawn_agent, send_message, wait_agent. Creates or resumes a child thread with copied runtime boundaries and inter-agent communication. AgentControl, multi-agent handlers, SessionSource::SubAgent.

Keep this table close while reading the code. A skill answers "how should this work be done?", a plugin answers "which package owns these abilities?", MCP answers "what can the model call?", and a subagent answers "does this need a separate context track?".

1.1 Follow One Turn Through Those Shapes

Use one realistic request as the representative unit: "use $article to write the Codex memory chapter, use Browser if a page must be checked, and ask a subagent to review the draft." Codex does not merge that into one universal capability. At turn start, the request is split into bounded runtime materials.

Stage Unit at that moment Owner and visibility What changes next
Raw input User text plus explicit mentions. The input layer recognizes $article, Browser, and subagent intent. It selects entries to prepare; it does not produce tool results.
Capability snapshot turn_skills, extension_data, and dynamic_tools in TurnContext. The runtime owns it inside the turn boundary. Injection and tool planning read the same snapshot.
Context injection The selected SKILL.md content for $article. Model-visible guidance. It changes how the model should work; it is not a function call.
Tool exposure Browser or other MCP/app tool specs. The model sees direct tools or deferred tools retrieved through tool_search. Actual calls still pass through the tool router and permission layer.
Child thread A review task created by spawn_agent. The parent starts it; the child owns its own context and event stream. Results return to the parent through inter-agent communication.

This chain is more useful than vocabulary alone. A single request can involve skills, plugins, MCP, and subagents, but they take effect at different layers. Once you separate context injection, tool exposure, and child-thread control, the source has a clear path to follow.

2. TurnContext Holds the Inputs

Earlier parts focused on TurnContext as the place where context, permissions, and token policy meet. For extensions, the relevant fields are dynamic_tools, extension_data, turn_skills, multi_agent_version, parent_thread_id, and session_source.

make_turn_context assembles the turn's config, model information, permission profile, dynamic tools, extension data, and loaded skills into one structure. Two details matter here: HostLoadedSkills is inserted into extension_data for host extensions, and dynamic_tools is carried from session configuration into the later tool plan.

Codex forms a turn capability snapshot before the model request: current config, loaded skills, extension data, multi-agent mode, and permission boundaries. Injection and tool planning both build on that snapshot.

3. Skills: Catalog First, Full Text on Demand

Skill exposure has a light first layer. Codex renders available skill names, descriptions, paths, and usage rules into developer context through AvailableSkillsInstructions. That tells the model what can be selected without paying the cost of loading every long skill body.

The heavier layer appears after an explicit mention. build_skills_and_plugins collects skill mentions from the current user input, then calls build_skill_injections. That function resolves the skill metadata, reads the full SKILL.md, and wraps the contents as SkillInstructions. The full working method enters context only when the turn needs it.

Stage Model-visible content Why it is shaped this way
Catalog Skill name, description, path, and trigger guidance. The model can choose without loading every long instruction file.
Explicit mention Full SKILL.md contents. The user or structured input has confirmed that the skill is relevant.
Injection shape SkillInstructions as a contextual user fragment. A skill is a work method and constraint, so it enters context rather than the tool list.

That is why skill quality matters so much. The runtime can put the file in the right place, but the file itself still needs to encode workflow, boundaries, and verification criteria clearly.

4. Plugins Package Several Kinds of Capability

Plugins solve a broader packaging problem. A plugin may contribute skills, scripts, MCP servers, app connectors, and hooks. In the source, PluginManifest.paths names those components as separate resources: skills, mcp_servers, apps, and hooks.

pub struct PluginManifestPaths<Resource> {
    pub skills: Option<Resource>,
    pub mcp_servers: Option<Resource>,
    pub apps: Option<Resource>,
    pub hooks: Option<PluginManifestHooks<Resource>>,
}

This small source shape is the plugin mental model. A plugin manifest groups several resources under one package identity; it does not collapse skill context, MCP tools, app connectors, and hooks into one new kind of runtime ability. The loader still routes each resource to its own channel.

After loading, PluginLoadOutcome exposes effective skill roots, plugin skill roots, MCP servers, apps, hook sources, and capability summaries. A summary is a compact model-facing description. The actual capability still enters through its own path: skill context, MCP tool, app tool, or hook.

The plugin instructions make this boundary explicit: a plugin is a local bundle of skills, MCP servers, and apps. Solving work still means using the underlying skill, MCP tool, or app tool.

build_skills_and_plugins loads plugins from the current config, resolves explicit plugin mentions, and, when needed, loads raw MCP/app inventory for the turn. build_plugin_injections then turns a plugin mention into guidance about the package's currently usable abilities.

5. MCP and tool_search: Discover Before Loading Everything

Part IV covered the ordinary tool-call path. The extension layer adds an exposure decision before the model sees MCP tools. build_mcp_tool_exposure filters model-visible MCP tools and then decides whether to expose them directly or defer them.

The threshold is concrete: DIRECT_MCP_TOOL_EXPOSURE_THRESHOLD is 100. If search is enabled and the configuration requests always-defer, or the tool set reaches that threshold, Codex does not place the whole set in the direct tool list. It exposes tool_search, and the model retrieves relevant specs by query.

Tool source Before model exposure Runtime boundary
Regular MCP tool Filtered for model visibility and exposed directly when the set is small enough. Calls still go through McpHandler and approval metadata.
Large MCP set Indexed as deferred tools and retrieved through tool_search. The search step reduces context noise without bypassing the call path.
App connector tool Visible only when the connector is allowed and enabled for this turn. Tool metadata keeps connector and plugin information.
Dynamic tool Added from TurnContext.dynamic_tools during tool planning. Still becomes a normal handler routed by ToolRouter.

The practical point is scale. Once tool libraries become large, the key question is not just whether the model can call them; it is how many specs should be placed in front of the model before it knows what it needs.

6. Subagents Add a Controlled Thread

Multi-agent operations are exposed through tools: spawn_agent, send_message, followup_task, wait_agent, and list_agents. Their effect is different from a normal function result. A spawned agent becomes a child thread managed by AgentControl.

handle_spawn_agent parses task_name, agent_type, model options, reasoning effort, service tier, and fork_turns. It then builds a child config from the parent turn, applies allowed model or role overrides, and copies runtime boundaries such as approval policy, sandbox, cwd, permission profile, and environments.

The spawn path uses SessionSource::SubAgent and ThreadSpawn metadata. When history is forked, it reads parent history and keeps all turns, the last N turns, or none, depending on fork_turns. Completion is reported back to the parent through InterAgentCommunication in the v2 path, or by injecting a parent-thread message for older paths.

A subagent is a controlled thread, not just a function call. It has its own context, status, history, and completion notification, while still inheriting the parent's runtime boundaries.

7. Rejoin the Main Turn

The four paths now connect back to the series map. User input enters a turn; TurnContext fixes the current snapshot; skill and plugin guidance become contextual injection; MCP, dynamic tools, and collaboration tools enter the tool plan; tool calls, agent activity, and model output continue into events and client projection.

What you see Where to read Series connection
"Use $article for this post" collect_explicit_skill_mentions, then SkillInstructions. Part II: context management.
"Enable Browser or GitHub plugin" Manifest and load outcome, then contributed skill roots, MCP servers, and apps. This part's plugin boundary, plus Part IV tools.
"Search the tool catalog first" build_mcp_tool_exposure and ToolSearchHandler. Part IV: tool specs and routing.
"Spawn a reviewer subagent" Multi-agent handlers, AgentControl, and SessionSource::SubAgent. Part III events and Part VI client projection.

Seen this way, Codex extensions are not an external plugin layer bolted around the runtime. They are bounded inputs to the same turn: context when the model needs a working method, tool specs when it needs callable capability, and child threads when the work needs a separate context track.

8. The Series Map After Part VII

With seven parts in place, a single request can be read end to end: entry converts user intent into typed operations; session creates a turn; context management prepares model-visible material; tool specs and routers define callable surface; permission and sandboxing gate side effects; events project runtime facts to clients; extensions and multi-agent explain how extra capability joins that same path.

Part VIII follows hooks and lifecycle. Before or after a user prompt, before or after a tool call, and when a turn stops, Codex allows more code to add context or intercept side effects. At that point, the hooks entry in a plugin manifest becomes an execution path.

Source References