Skip to content
EthosLink/Open source/RubyLLM Codex

RubyLLM Codex

Use the local Codex CLI as a RubyLLM provider for non-streaming text and structured output, with per-request process isolation.

RubyLLM Codex: project workflow and Ethos Link open-source identity.
EthosLink · Ruby · RubyLLM · Codex

Overview

Use the local Codex CLI as a RubyLLM provider for text and structured output. It is for Ruby applications using RubyLLM with the local Codex generation harness. This is an independent adapter. It supports non-streaming text and structured output; attachments, RubyLLM tools and temperature are rejected. It does not offer a raw model API request path.

Installation

Ruby 4.0 or newer; RubyLLM 2.1.1 or newer, below 2.2; Codex CLI 0.162.1 or newer on PATH; Linux or macOS. Complete codex login and select a model available to that account.

gem install ruby_llm-codex

For a Bundler application, add gem "ruby_llm-codex" to its Gemfile and run bundle install.

Quick start

require "ruby_llm-codex"

response = RubyLLM.chat(
  model: ENV.fetch("CODEX_MODEL"), provider: :codex
).ask("Reply with a short greeting.")

puts response.content

Set CODEX_MODEL to a model available in your installed Codex CLI. After login, the request starts a local codex exec process and prints its text response. It uses the Codex account’s access and usage limits; the gem does not accept an OpenAI API key.

Usage

Structured output

Require the gem and use Codex as an explicit RubyLLM provider:

require "ruby_llm-codex"

class SummarySchema < Schematist::Schema
  string :summary
end

response = RubyLLM.chat(model: ENV.fetch("CODEX_MODEL"), provider: :codex)
  .with_instructions("Return a concise summary.")
  .with_schema(SummarySchema)
  .with_thinking(effort: :medium)
  .ask("The text to summarize")

pp response.parsed

response.content contains the JSON string. Read response.parsed for the structured Hash, and response.tokens for token counts.

Isolation and reproducibility

By default every request:

  • runs in a fresh empty temporary directory;
  • uses a read-only sandbox;
  • disables interactive approvals;
  • ignores user Codex configuration while retaining authentication;
  • creates an ephemeral Codex session;
  • disables Codex shell snapshots, which are unnecessary because this provider does not support tools;
  • prevents model-generated shell commands from inheriting the parent process environment;
  • passes RubyLLM’s system instruction as Codex developer instructions;
  • passes RubyLLM’s JSON schema through --output-schema.

These defaults separate the request from the current repository and user configuration. Supplying a working directory, profile or user configuration changes that context deliberately; the adapter still runs the Codex harness. Sandbox behaviour also depends on the installed CLI and host platform.

Configuration

Per request

To deliberately let Codex inspect a repository or use selected configuration:

chat = RubyLLM.chat(model: ENV.fetch("CODEX_MODEL"), provider: :codex)

chat.with_provider_options(
  codex: {
    working_directory: "/path/to/project",
    sandbox: "read-only",
    ignore_user_config: false,
    ephemeral: true,
    timeout: 300,
    shell_environment_inherit: "none"
  }
)

Global

Global configuration is also available:

RubyLLM.configure do |config|
  config.codex_cli_path = "/usr/local/bin/codex"
  config.codex_working_directory = nil
  config.codex_profile = nil
  config.codex_home = nil
  config.codex_ignore_user_config = true
  config.codex_ephemeral = true
  config.codex_timeout = 300
  config.codex_shell_environment_inherit = "none"
end

Only the nested codex namespace is accepted by with_provider_options; unsupported generic provider options raise an error instead of being silently ignored. Use with_thinking for reasoning effort and with_instructions for developer instructions. Those settings, plus features.shell_snapshot and shell_environment_policy.inherit, are reserved from the arbitrary codex.config map so their precedence remains unambiguous.

Deliberate limitations

  • Non-streaming chat only.
  • Text prompts only; attachments are rejected.
  • RubyLLM tools are rejected. Codex remains the generation harness, not a tool execution backend for your application.
  • Temperature is rejected because this Codex path does not expose it.
  • Fresh codex exec process per RubyLLM completion. This prioritizes isolation and predictable behavior over throughput.
  • Multi-turn RubyLLM histories are serialized into a role-labelled transcript. One-shot with_instructions(...).ask(...) requests have the most direct semantic mapping.

Streaming, persistent threads and a long-running app-server client are not implemented by this gem.

Troubleshooting

  • codex is not found: install the Codex CLI, run codex login, or set RubyLLM.config.codex_cli_path to its absolute path.
  • A request times out: increase codex.timeout or CODEX_TIMEOUT for the smoke task. Timed-out process groups are terminated automatically.
  • Codex consumes excessive memory: use the current gem version. The provider explicitly disables Codex shell snapshots, which are unnecessary for its completion-only execution and previously caused runaway Bash processes.
  • Local instructions affect output: keep ignore_user_config: true and do not set a working directory when you need isolated requests.

Technical details

Each completion starts a fresh Codex process. Defaults use an empty temporary working directory, a read-only sandbox, ephemeral sessions, ignored user configuration and no inherited shell environment. RubyLLM system messages map to Codex developer instructions. POSIX process groups support timeout cleanup. Provider errors report missing executables, incompatible CLI versions, timeouts and malformed responses.

Project resources

Ethos Link is a software company founded by Paulo Fidalgo. We publish these Ruby tools alongside our business products.

  • Reviato: private customer feedback and public review analysis.
  • Nuntio: prepare, review and schedule social posts.
  • EthosPlaces: find places, opening hours and contact details.