SamgitaProtocolCodex
All package versions below 1.0 are experimental releases for testing. The package version is separate from the pinned Codex version; publication does not establish complete native behavioral compatibility or platform production readiness.
A standalone native wire/schema library for official Codex 0.163.0, with a
retained convenience adapter for selected Samgita protocol operations. It opens no listener, starts no runtime, and
depends only on the sibling samgita_protocol library. It does not depend on
Phoenix, Samgita persistence, providers, Backplane, or umbrella configuration.
Reference and compatibility boundary
The reference is the official OpenAI Codex release rust-v0.163.0,
commit 83086188ae0614bd882818ff1aa23f3194962012.
The GitHub release/tag and official app-server documentation
were verified on 2026-10-22. priv/upstream/source.json records immutable source
paths, upstream SHA-256 hashes and vendored SHA-256 hashes. Schemas have only an
added terminal newline; Apache-2.0 LICENSE and NOTICE are preserved byte for byte.
These describe Codex independently of Samgita's neutral event/session protocol.
The complete generated stable and experimental bundles, source gate metadata and
per-file hashes now live in priv/upstream/0.163.0/. Generate/check them with
scripts/codex/inventory.py from the repository root. The executable is fetched
into ignored scratch storage by scripts/codex/fetch_pin.py; it is never installed
globally or included in this package.
The official JSON exporter omits three legacy requests/results and two raw notifications. A separately labeled locally derived supplement uses the pinned TypeScript export and matching Rust/serde declarations. Its origins/hashes are recorded separately; the original 318 stable and 452 experimental JSON artifacts remain unchanged. The full source inventory contains 485 requirements and 6,621 field/variant contracts; generated examples do not verify their runtime behavior.
The same pin's timeline JSON export disagrees with its native serializer on two
turn-boundary variants. A separately derived, hash-checked output contract uses
the Rust/TypeScript camelCase names while preserving every original export and
all value/type constraints. See
docs/codex-app-server/thread-history-qualification.md; received values are
never rewritten to fit an incorrect export.
thread/start also uses a custom native decoder for legacy flat dynamicTools
without a type tag. A separately derived, hash-checked input contract accepts
those declarations and enforces native list-wide format consistency, including
nested tools. Original flags and wire values remain unchanged; native Codex owns
namespace grouping, exposure defaults and flag precedence. The descriptor can
be reproduced with scripts/codex/generate_input_semantics.py; see
docs/codex-app-server/legacy-dynamic-tool-input-qualification.md for the three
actual-native profiles and remaining limits.
A second input-only descriptor covers the pinned compaction_summary alias in
thread/resume.history. The driver preserves that caller tag; native Codex alone
serializes, persists and consumes canonical compaction items. All original
field constraints and output contracts remain intact. See
docs/codex-app-server/compaction-input-alias-qualification.md for genuine
checkpoint import/continuation evidence and its limits.
A third input-only descriptor accepts native ModeKind::Default aliases code,
pair_programming, execute and custom for turn/start and
thread/settings/update. Caller values and experimental negotiation stay intact;
Codex owns canonical default settings, parser behavior and persistence. See
docs/codex-app-server/collaboration-input-alias-qualification.md for actual
applied settings, literal assistant output and first cold history evidence.
The same descriptor also accepts single-key unit objects for plan, default
and those four aliases, with null or {} payload. See
docs/codex-app-server/collaboration-unit-input-qualification.md for distinct
native Plan/Default parser and canonical history evidence on these forms.
A fourth descriptor covers deprecated multiAgentMode inputs: none and the
single-key unit objects for none, explicitRequestOnly and proactive, with
null or {} payload. The actual nested request decoder's pinned serde source
and MIT license are included as references, never compiled. These three request
fields are native no-ops; accepted input does not activate delegation. See
docs/codex-app-server/deprecated-mode-input-qualification.md for exact native
sends, applied snapshots and model/history evidence.
Tests distinguish generated schema examples, real executable journeys and the
restricted convenience mapping. See docs/codex-app-server/qualification.md for
current evidence and gaps. Complete behavioral compatibility, real account/backend
acceptance and deployed Sigma/Synapsis integration remain unverified.
Native wire and schemas
alias SamgitaProtocolCodex.{Schema, Wire}
wire = %{"id" => "native-1", "method" => "thread/list", "params" => %{"limit" => 10}}
:ok = Schema.validate_request(wire["method"], wire["params"])
{:ok, json} = Wire.encode(wire)
{:ok, ^wire} = Wire.decode(json)
methods = Schema.methods(:client_request, experimental: true)
Native contracts cover all four directions and correlated results from the pinned release. They preserve string/integer IDs, omitted versus null fields, structured errors, trace metadata and unknown additions. Validation does not insert defaults or create atoms. Explicit experimental opt-in follows the pinned Rust request gate semantics, including nullable options and nonempty collections. The schema corpus provides structural evidence; it does not certify each operation's runtime behavior.
Use Schema.validate_request/3 with direction: :server_request for incoming
interactions, validate_notification/4 for either notification direction, and
validate_result/4 for correlated :server_response or :client_response values.
Wire enforces JSON, envelope, nesting and byte bounds independently of transport.
Error retains complete upstream error wire for authorized programmatic callers;
Inspect and Exception output redact upstream payloads. Never log raw wire blindly.
The independent sibling samgita_codex_driver owns optional processes, transports,
sessions and interactions. Neither loading this library nor validating a schema
starts execution. The following sections describe the retained convenience API;
its restrictions do not limit the native interface.
Convenience handshake
{:ok, initialize} = SamgitaProtocolCodex.initialize_request("init-1", %{
"name" => "my_client", "version" => "0.1.0"
})
# Send initialize over an already authenticated connection.
{:ok, _metadata} = SamgitaProtocolCodex.decode_initialize_response(response, "init-1")
# Only after a successful response:
initialized = SamgitaProtocolCodex.initialized()
The caller owns authentication, handshake order, one initialization per connection,
transport I/O, pending request state, timeout/disconnect uncertainty and reconnect.
initialized/0 emits %{"method" => "initialized"}. Codex omits the jsonrpc
version field on its wire. Native connection/initialize and native capability
negotiation cannot be translated into Codex negotiation; no capabilities are
inferred from an initialize response. This adapter never enables experimental APIs.
Convenience requests and responses
encode_request(native_request) returns {:ok, upstream_map} or
{:error, %SamgitaProtocol.Error{}}. Supported methods are available from
supported_methods/0:
| Native method/fields | Codex method/fields |
|---|---|
thread/start with empty params |
thread/start with empty params |
thread/read, thread/resume: thread_id |
Same method: threadId |
turn/start: thread_id, text input |
Same method: threadId, text input |
turn/steer: thread_id, turn_id, text input |
Same method: threadId, expectedTurnId, text input |
turn/interrupt: thread_id, turn_id |
Same method: threadId, turnId |
Native thread/start title/metadata are rejected explicitly; this subset does not
silently discard them or invent upstream equivalents. Model/provider, working
directory, tool and sandbox configuration stay with the upstream host. Approval
requests/responses, native request/cancel, stream/resume, and project-event
methods are unsupported. The adapter exposes per-method support rather than
claiming complete native capability-group compatibility.
decode_message(upstream_map, original_native_request) correlates a reply to its
exact pending request and returns a native response. Native identity, correlation,
command and reference metadata are copied only from that original request; they
are never inferred from upstream thread IDs. Thread results contain the upstream
thread as optional JSON. Turn start/steer acknowledges a running turn; interruption
acknowledges only requested, never proof that tools stopped. Malformed or
mismatched results fail explicitly. Upstream errors map to a safe upstream_error
with numeric code only; upstream message/data are not copied into native errors.
Only the documented overload code -32001 is marked retryable; callers still
must reconcile uncertain mutations before retrying.
command_id remains a native reconciliation identity and is not sent upstream:
Codex does not thereby supply durable acknowledgement, deduplication, exactly-once
effects, Project/Task mutation or management acceptance. No command is automatically
replayed. Hub references and native envelope metadata are never injected into
Codex messages.
Convenience notifications
supported_notifications/0 lists turn/started, turn/completed and
item/agentMessage/delta; the last maps to native item/delta. A notification
requires explicit context with correlation_id, expected thread_id and turn_id.
The context may also provide native causation_id, project_ref, task_ref and a
paired stream_id/positive cursor. Mismatched thread/turn IDs fail before mapping.
Without stream metadata the adapter emits no cursor. Supplied stream metadata is the caller's local projection position, not an upstream durable cursor or replay guarantee. The caller owns ordering, retention and authorization. Full item/tool events, approvals and unknown notifications fail explicitly; codecs never approve or execute tools. A connection owner may deliberately route other upstream traffic elsewhere; it must not silently treat an adapter error as a successful translation.
Build and verify
From this directory, using Elixir 1.18+:
mix deps.get
mix test
mix compile --warnings-as-errors
mix format --check-formatted
The package has its own build/dependency/config/lock paths. Run package commands from this directory; no umbrella application or database needs to start.