Skip to main content

Deterministic LangGraph orchestration with optional Codex execution

Project description

langgraph-codex

Put Codex inside the LangGraph you already own.

langgraph-codex is a small adapter library for one practical pattern: keep your deterministic graph, then replace one bounded node with a Codex-backed node when ordinary Python is not enough.

  • LangGraph owns orchestration, state, routing, persistence, and checkpoints.
  • Python owns parsing, context building, policy, and validation.
  • Codex owns one explicit execution step with a clear prompt and workspace.
  • Your application stays in control.

It is not a chat framework, hidden agent runtime, repository automation product, or broad model abstraction layer.

Install

uv add langgraph-codex

For local development:

uv sync --extra dev
make check

Start Here: Codex As One LangGraph Node

This is the main use case. Build a normal langgraph.graph.StateGraph, authorize Codex once, and use create_codex_node only for the node that needs agentic execution.

import pathlib
import typing

import langgraph.graph

from langgraph_codex.execution import ExecutionResult
from langgraph_codex.graph import create_codex_node
from langgraph_codex.runtime import create_codex_executor, ensure_codex_authorized


class ReviewState(typing.TypedDict, total=False):
    workspace_path: typing.Required[pathlib.Path]
    repo_context: dict[str, list[str]]
    codex_result: ExecutionResult
    validation_message: str


def inspect_codebase(_state: ReviewState) -> dict[str, dict[str, list[str]]]:
    return {
        "repo_context": {
            "package_files": ["langgraph_codex/graph/nodes.py"],
            "test_files": ["tests/test_graphs.py", "tests/test_execution.py"],
            "example_files": ["examples/00_existing_langgraph_graph.py"],
        }
    }


def prompt_for_codex(state: ReviewState) -> str:
    return "\n".join(
        [
            "Audit the existing langgraph-codex repository.",
            f"Repository context: {state.get('repo_context', {})}",
            "Write codebase_audit.md with concrete findings about tests and examples.",
            "Do not invent an unrelated service configuration.",
        ]
    )


def validate_result(state: ReviewState) -> dict[str, str]:
    result = state.get("codex_result")
    if result is None:
        return {"validation_message": "Codex did not return a result."}
    if result.returncode != 0:
        return {"validation_message": f"Codex failed: {result.stderr}"}

    return {"validation_message": "Codex completed. Validate codebase_audit.md next."}


ensure_codex_authorized()
codex_node = create_codex_node(
    executor=create_codex_executor(timeout_seconds=300),
    prompt_builder=prompt_for_codex,
    workspace_path=lambda state: state["workspace_path"],
)


def draft_audit(state: ReviewState) -> dict[str, ExecutionResult]:
    update = codex_node(state)
    result = update.get("codex_result")
    if not isinstance(result, ExecutionResult):
        raise TypeError("Codex node did not return codex_result.")

    return {"codex_result": result}

graph = langgraph.graph.StateGraph(ReviewState)
graph.add_node("inspect_codebase", inspect_codebase)
graph.add_node("draft_audit", draft_audit)
graph.add_node("validate_result", validate_result)
graph.add_edge(langgraph.graph.START, "inspect_codebase")
graph.add_edge("inspect_codebase", "draft_audit")
graph.add_edge("draft_audit", "validate_result")
graph.add_edge("validate_result", langgraph.graph.END)

result = graph.compile().invoke({"workspace_path": pathlib.Path.cwd()})
print(result["validation_message"])

That is the intended shape:

prepare deterministic context -> call Codex node -> validate deterministically -> route

Authorization

Real Codex execution requires the Codex CLI and credentials. The runtime helpers load local .env values and map OPEN_AI_SECRET_KEY to OPENAI_API_KEY when needed.

cp .env.example .env

Then set the relevant values:

OPEN_AI_SECRET_KEY=...
OPEN_AI_KEY_NAME=github-actions
OPEN_AI_MODEL=

See docs/codex-authorization.md for local setup, GitHub Actions secrets, and CI guidance.

Validation

Codex output should be checked by deterministic code before anything downstream consumes it.

Good validators check files, schemas, command output, tests, checksums, and domain-specific facts:

from langgraph_codex.utils.validation import require_files

validators = [require_files(["remediation_plan.md"])]

You can use the built-in validation helpers, or write normal LangGraph nodes that inspect your application state and route from there.

Examples

The examples are intentionally few and close to the production integration shape:

Run:

uv run python3 -m examples.00_existing_langgraph_graph
uv run python3 -m examples.01_real_codex_node
uv run python3 -m examples.02_codebase_audit

Convenience Builders

For small tests and quick starts, the package also includes complete graph builders:

  • build_context_only_graph()
  • build_execution_graph()
  • build_retry_graph()

Most production applications should prefer create_codex_node inside their own graph.

CI/CD

The repository validates:

  • GitHub Actions workflow syntax with actionlint;
  • Ruff formatting and linting;
  • Pylint with 10.00/10;
  • strict mypy and Pyright;
  • Python compile checks;
  • pytest across Python 3.11, 3.12, and 3.13;
  • offline examples;
  • wheel and source distribution build plus Twine metadata validation;
  • optional real Codex smoke checks through workflow dispatch.

Release publishing uses PyPI trusted publishing through the pypi GitHub environment.

Design Notes

The package deliberately stays small. It does not own memory, UI, checkpoint storage, broad model selection, or repository policy. Those concerns belong in the graph and infrastructure you already control.

Read more in docs/design-philosophy.md.

Testing Without Codex

Use FakeExecutor when you want CI-safe tests, examples, or local development without calling the Codex CLI.

from langgraph_codex.execution import FakeExecutor

executor = FakeExecutor(stdout="Priority: medium. Area: billing exports.")

FakeExecutor records requests and returns deterministic results, so you can assert prompt content, metadata, options, and graph routing without network credentials.

Development

make sync
make format
make check

Useful targets include make quality, make test, make package-check, make examples, make examples-codex, and make clean.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

langgraph_codex-0.1.0.tar.gz (136.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

langgraph_codex-0.1.0-py3-none-any.whl (21.2 kB view details)

Uploaded Python 3

File details

Details for the file langgraph_codex-0.1.0.tar.gz.

File metadata

  • Download URL: langgraph_codex-0.1.0.tar.gz
  • Upload date:
  • Size: 136.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for langgraph_codex-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cda9779ce3b0f91eace6a2dd622d3f69dc17ed663690d9fcd1e90c939212bc38
MD5 dc3f0e64b22fcd0b22fd8da9f698ed04
BLAKE2b-256 33c4490ae09e55f7e36d08a24ace725d43337f8a13b0bfd794b1cc4333d15f71

See more details on using hashes here.

File details

Details for the file langgraph_codex-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: langgraph_codex-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 21.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for langgraph_codex-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cab671906b7eefb450998345680617dda8b9ca64cece8c98d79879a0ed1af672
MD5 898703b5726ab2c7a84bf3f32ac51d05
BLAKE2b-256 e5a919a90d6e24a18149ea0c95075baabe059282e21e5ab3a6e21a0dc3f0fc4e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page