Architecture

July 23, 2026 · View on GitHub

English | Русский

Purpose

codex-stt-bridge converts one local audio file into text. It is an isolated adapter between an agent runtime's local-command interface and the internal Codex Desktop transcription flow.

flowchart LR
    IN["Voice message or audio file"] --> AR["Agent runtime<br/>Hermes, OpenClaw, or other"]
    AR --> CLI["codex-stt CLI"]
    CLI --> AF["~/.codex/auth.json<br/>read only"]
    CLI --> BE["chatgpt.com<br/>Codex Desktop transcription"]
    BE --> CLI
    CLI --> TF["UTF-8 transcript<br/>mode 0600"]
    TF --> AR
    AR --> AG["Normal agent text turn"]

Responsibilities

Agent runtime

The agent runtime is responsible for:

  • receiving or locating the audio file;
  • invoking the CLI with an input path and optionally an output path;
  • reading the result;
  • showing the recognized text;
  • continuing with a normal agent turn.

Hermes uses a command-type STT provider with {input_path} and {output_path}. OpenClaw uses a media CLI with {{MediaPath}} and reads stdout. Neither agent core is patched.

Bridge

The bridge is responsible for:

  • validating the input file and size;
  • reading the current Codex OAuth session;
  • uploading the original audio directly;
  • refreshing once and retrying once after HTTP 401;
  • validating the response shape;
  • writing the result atomically with mode 0600;
  • failing safely without exposing credential material.

The bridge does not retain its own copy of audio, tokens, or the account ID.

Codex

Codex CLI is responsible only for initial login and refreshing an expired OAuth session. Its real-time app server is not used for transcription.

The current implementation requires file-based credential storage. The bridge cannot read the Codex keyring directly, while the internal transcription endpoint requires a bearer token. If Codex stops supporting a safe file-based flow, the bridge must stop rather than extract credentials through an unofficial workaround.

Why a local CLI

A local CLI is the smallest stable integration boundary:

  • no separate process or port;
  • no dependency on an agent plugin API;
  • no MCP server;
  • an STT failure does not stop normal text chat;
  • the CLI can be checked independently from the gateway;
  • updating the bridge does not require changing the agent core.

Hermes and OpenClaw both support bounded local commands for transcription. Refresh is encapsulated inside a deterministic one-command CLI, so this remains a smaller and better-isolated boundary than a custom plugin. Reconsider a plugin if streaming chunks, provider metadata, or interactive setup become necessary.

Failure flow

flowchart TD
    A["Audio received"] --> B["codex-stt"]
    B --> C{"HTTP status"}
    C -- "2xx" --> D["Validate JSON text"]
    C -- "401" --> E["Codex account/read refresh"]
    E --> F["Retry once"]
    C -- "other error" --> G["Safe non-zero failure"]
    F --> D
    F --> G
    D --> H["Atomic transcript file"]
    G --> I["Agent reports STT failure<br/>text chat remains available"]

Data flow

DataReadTransmittedStored by bridge
Input audioyeschatgpt.comno
OAuth access tokenyeschatgpt.comno
Codex account IDyeschatgpt.comno
Refresh tokennot directlythrough Codex CLIno
Transcriptyesagent runtimestdout or the requested output path

Production ownership

Recommended boundary:

/opt/codex-stt-bridge/       root/admin owned, runtime read+execute
~/.codex/auth.json           agent user owned, mode 0600
agent config                 agent user owned, mode 0600
audio cache                  agent user owned
transcript temp output       agent user owned, mode 0600

A user-writable checkout is acceptable for development, but it is not the preferred production executable path for code that handles credentials.