Codex Tool Profiles
Copy MarkdownBackplane.AgentRuntime.Codex.profile/4 is the runtime-owned boundary for
explicit Codex profiles. It binds trusted host resources into descriptors,
requires exact run grants and descriptor revisions, and returns one
ToolCatalog registry/tools/authority bundle for Conversation.
definitions/0 retains the local provider definitions for compatibility.
Every model-callable profile below dispatches through
Conversation -> Execution.commit/dispatch. Codex.Backend receives the
descriptor-owned backend_context only after the intent commit. Model arguments
cannot select adapters, credentials, workspaces, environments, or grants.
Profiles
:pinned_localexposes configuredexec_command,write_stdin,apply_patch,update_plan,view_image,clock::curr_time, andclock::sleep.apply_patchis a custom/freeform tool using the pinned Lark grammar; raw input follows the same admission and commit path as JSON input.:interactiveexposes configured synchronous/asynchronous user interaction, permission request, environment readiness,new_context, andget_context_remainingtools. Host callbacks authenticate replies, apply grants, and supply authoritative readiness/token state.:collaboration_v1and:collaboration_v2expose their distinct pinned names.Codex.MultiAgentowns wait/list state and starts childConversationprocesses under aDynamicSupervisor; child options and authority come only from the host.:extensionsexposes 27 concrete goal, memory, skill, history, note, and message-board tools. The bundled scoped reference state is ephemeral. A host adapter is required before claiming durability or restart recovery.:dynamicconditionally exposes MCP resource operations,tool_search, and plugin request tools. Search publishes admitted tools for the next provider turn; another call in the discovery batch remains fenced to the old catalog.:code_mode,:code_mode_only, and:mixedexpose the pinned freeformexecand functionwaitcontracts only when the host can verify Deno process identity and bounded cleanup. Deno presence alone is insufficient; the current native adapter requires Linux/procandkill, and unsupported hosts are rejected before a cell or nested tool can start. The opt-in Deno worker has no ambient filesystem or network access. Nested calls re-enter the admitted Conversation dispatcher with the existing run, authority, revision, budget, resource owner, catalog callbacks, and audit path.:service_compatexposes only configured service adapters. It includes the pinnedweb::runandimage_gen::imagegencontracts plus explicit Backplane compatibility toolsweb::fetch,web::search, andweb::x_search.:configuredcombines explicitly selected:local,:interactive,:collaboration_v1or:collaboration_v2,:extensions,:dynamic,:code_mode, and:servicesfamilies. Missing families and duplicate canonical names fail before admission.
Provider-hosted capabilities are separate from local tools. A configured
provider adapter negotiates them and :configured returns them in
profile.hosted_tools; they are never inserted into ToolRegistry. The current
projection supports the pinned web_search declaration and normalizes observed
provider events. Local tests use an injected adapter and do not establish live
provider compatibility.
Host Requirements
Profiles are capability-driven and fail closed. Command tools need the selected
workspace, command adapter, caller identity, and Codex.ResourceRegistry; plan
needs a host-started Plan; collaboration needs Codex.MultiAgent; extensions
need Codex.ExtensionRuntime; dynamic tools need Codex.DynamicRuntime plus the
relevant MCP/plugin adapters; Code Mode needs Codex.ResourceRegistry, Deno,
and a verified process-lifecycle capability; service and hosted tools need
host-owned adapters and credentials. Selecting no
profile starts none of these resources.
Existing consumers can upgrade without selecting a Codex profile; their current
Execution, ExecutionController, provider, and tool APIs remain available.
To opt in, start only the required host runtimes, call Codex.profile/4 with the
run's exact grants/revisions, and pass the returned registry, tools, and
authority together to Conversation. Do not merge profile fields with an old
catalog or persist backend_context, PIDs, callbacks, credentials, or grants.
The standalone local example is examples/codex_local.exs:
mix run --no-start --no-deps-check apps/backplane_agent_runtime/examples/codex_local.exs
On Linux it uses the existing LocalCommand process-group backend. On other
platforms it uses an explicitly labelled one-shot System.cmd example adapter
because production LocalCommand currently requires Linux /proc, setsid,
and process-group probing. PTY compatibility is not claimed.
Compatibility Boundary
The exact 66-entry inventory for Codex revision
46fdd5ef39735f4159cdcf0ec5e85c10521494e5 is packaged as
priv/codex/source-inventory.json. Per-family contract, execution,
availability, and parity evidence is maintained under
docs/agent-runtime/codex-tools/. Source presence does not establish behavior.
The old direct-call clock and time-waiting wait names remain Backplane
compatibility aliases and are not in :pinned_local. The pinned wait name is
the Code Mode continuation. Hosted search is web_search, standalone service
search is web::run, and image generation is image_gen::imagegen.
Compatibility remains adapted rather than unqualified full parity:
- Code Mode
waitresumes a stored generator continuation, not the pinned time-sliced running-cell implementation. - Linux process-group cleanup and PTY behavior are unavailable on macOS.
- Extension reference state is ephemeral unless a durable host adapter supplies and verifies recovery.
- Full pinned output schemas, all schema property descriptions, and native Codex event/wire differential coverage remain incomplete.
- Production MCP, web/image services, and provider-hosted tools were not tested against live backends.
Command response budgets
exec_command.max_output_tokens and write_stdin.max_output_tokens bound the
output returned by each call, independently of Command.output_limit, which is
a host-owned backend hard limit. The response uses a four-bytes-per-token
estimate (default 10,000); it is not tokenizer accounting. Results expose
output_budget_unit: :estimated_token_bytes, output_truncated, and
omitted_output_bytes. A poll advances past the entire observed backend batch,
including intentionally omitted bytes; the next poll does not repeat that batch.
UTF-8 prefixes are not cut inside a character.
Results retain backend status, exit status when available, termination and
cleanup evidence, and output_limit_exceeded?. A hard-limit termination is not
a successful command merely because an exit code is missing. LocalCommand keeps
its bounded output buffer and Linux process-group cleanup; descendants that
create a separate session remain outside that backend's cleanup guarantee.
Worker framing
The packaged Deno worker runs with explicit denied ambient permissions using
deno run and a data URL. Its stdin protocol is bounded NDJSON: UTF-8 decoding
is streaming, only newline-terminated records are parsed, and a record is limited
to 1 MiB before buffering. Malformed JSON, invalid UTF-8, oversized records, and
incomplete records at EOF produce an explicit protocol error and exit the worker.
The Elixir port also assembles bounded records independently of pipe read sizes.
codex_framing_test.exs deterministically splits raw records and UTF-8 bytes in
the actual packaged JavaScript source; separate tests exercise the real
CodeMode.execute worker with large source and nested results. Those framing
tests alone are not evidence of cross-provider-turn continuation behavior.
Patch results
apply_patch parses operations and ordered line hunks before modifying files.
Anchors, EOF constraints, whitespace/punctuation matching, additions and
rename-with-edit follow the pinned parser/application semantics while preserving
workspace and symlink checks. Move destinations may create parent directories.
The legacy direct-call move form remains a Backplane compatibility extension.
Patches are not whole-patch atomic. Successful operations appear in files;
on a later failure they remain in Error.details.files. A failed write can
leave uncertain content and reports :unknown_outcome with uncertain_files.
Callers must inspect this evidence rather than treating an error as proof that
nothing changed. Malformed bodies are rejected before executing any operation.