diff options
Diffstat (limited to 'gnu/packages/codex.scm')
| -rw-r--r-- | gnu/packages/codex.scm | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/gnu/packages/codex.scm b/gnu/packages/codex.scm new file mode 100644 index 00000000000..70f8bafd7d8 --- /dev/null +++ b/gnu/packages/codex.scm | |||
| @@ -0,0 +1,411 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2026 Danny Milosavljevic <dannym@friendly-machines.com> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | ;;; This module is separate from (gnu packages rust-apps) to avoid a | ||
| 20 | ;;; circular module dependency: (gnu packages rust-sources), which | ||
| 21 | ;;; defines rust-codex-0.98.0, transitively loads (gnu packages | ||
| 22 | ;;; rust-apps) through its #:use-module chain. If the codex package | ||
| 23 | ;;; lived in rust-apps.scm, loading rust-sources would trigger loading | ||
| 24 | ;;; rust-apps before rust-codex-0.98.0 is defined, causing an unbound | ||
| 25 | ;;; variable error. | ||
| 26 | |||
| 27 | (define-module (gnu packages codex) | ||
| 28 | #:use-module ((guix licenses) #:prefix license:) | ||
| 29 | #:use-module (guix gexp) | ||
| 30 | #:use-module (guix packages) | ||
| 31 | #:use-module (guix download) | ||
| 32 | #:use-module (guix git-download) | ||
| 33 | #:use-module (guix build-system cargo) | ||
| 34 | #:use-module (gnu packages) | ||
| 35 | #:use-module (gnu packages bash) | ||
| 36 | #:use-module (gnu packages base) | ||
| 37 | #:use-module (gnu packages cmake) | ||
| 38 | #:use-module (gnu packages compression) | ||
| 39 | #:use-module (gnu packages libunwind) | ||
| 40 | #:use-module (gnu packages llvm) | ||
| 41 | #:use-module (gnu packages perl) | ||
| 42 | #:use-module (gnu packages pkg-config) | ||
| 43 | #:use-module (gnu packages python) | ||
| 44 | #:use-module (gnu packages rust-sources) | ||
| 45 | #:use-module (gnu packages sqlite) | ||
| 46 | #:use-module (gnu packages tls) | ||
| 47 | #:use-module (gnu packages version-control)) | ||
| 48 | |||
| 49 | (define-public codex | ||
| 50 | (package | ||
| 51 | (name "codex") | ||
| 52 | (version (package-version rust-codex-0.98.0)) | ||
| 53 | (source | ||
| 54 | (origin | ||
| 55 | (inherit (package-source rust-codex-0.98.0)) | ||
| 56 | (patches (search-patches | ||
| 57 | "codex-0.98.0-remove-patch-sections.patch" | ||
| 58 | "rust-codex-0.98.0-test-shebangs.patch" | ||
| 59 | "rust-codex-0.98.0-test-timeout.patch")))) | ||
| 60 | (build-system cargo-build-system) | ||
| 61 | (arguments | ||
| 62 | (list | ||
| 63 | #:install-source? #f | ||
| 64 | #:cargo-install-paths '(list "cli" "exec" "exec-server" | ||
| 65 | "linux-sandbox" "mcp-server" "network-proxy" | ||
| 66 | "app-server" "tui") | ||
| 67 | ;; schema_fixtures_match_generated (upstream fixture is stale: | ||
| 68 | ;; FileChange::Update in codex-protocol gained old_content, | ||
| 69 | ;; new_content, move_path fields but the committed JSON schema | ||
| 70 | ;; fixture was not regenerated). | ||
| 71 | #:cargo-test-flags '(list "--workspace" | ||
| 72 | "--exclude" "codex-app-server-protocol" | ||
| 73 | "--" | ||
| 74 | ;; These tests exercise sandbox denial and | ||
| 75 | ;; escalation, which requires Landlock to | ||
| 76 | ;; cleanly deny filesystem access. Inside the | ||
| 77 | ;; build container Landlock returns NotEnforced | ||
| 78 | ;; and the sandbox binary panics instead. | ||
| 79 | ;; Disabling Landlock would not help either, | ||
| 80 | ;; since these tests need a working sandbox to | ||
| 81 | ;; have anything to deny and escalate. | ||
| 82 | "--skip" "sandbox_denied_shell_returns_original_output" | ||
| 83 | "--skip" "shell_escalated_permissions_rejected_then_ok" | ||
| 84 | "--skip" "unified_exec_runs_under_sandbox" | ||
| 85 | ;; These tests (in codex-exec) directly call | ||
| 86 | ;; spawn_command_under_linux_sandbox to verify | ||
| 87 | ;; that python and bash work correctly inside | ||
| 88 | ;; the Landlock sandbox. The sandbox binary | ||
| 89 | ;; (codex-exec) panics with LandlockRestrict | ||
| 90 | ;; (exit code 101) before the inner command | ||
| 91 | ;; even starts. | ||
| 92 | "--skip" "python_getpwuid_works_under_sandbox" | ||
| 93 | "--skip" "python_multiprocessing_lock_works_under_sandbox" | ||
| 94 | "--skip" "sandbox_distinguishes_command_and_policy_cwds" | ||
| 95 | ;; These linux-sandbox tests directly invoke | ||
| 96 | ;; the Landlock sandbox via | ||
| 97 | ;; process_exec_tool_call; same root cause. | ||
| 98 | "--skip" "test_writable_root" | ||
| 99 | "--skip" "test_timeout" | ||
| 100 | "--skip" "test_root_read" | ||
| 101 | "--skip" "test_dev_null_write" | ||
| 102 | "--skip" "test_no_new_privs_is_enabled" | ||
| 103 | ;; This test iterates many approval scenarios; | ||
| 104 | ;; one of them | ||
| 105 | ;; (danger_full_access_on_request_allows_network) | ||
| 106 | ;; runs a command through the Landlock sandbox | ||
| 107 | ;; binary, which panics with LandlockRestrict | ||
| 108 | ;; inside the build container. Cargo --skip | ||
| 109 | ;; cannot target individual scenarios, so we | ||
| 110 | ;; skip the entire matrix. | ||
| 111 | "--skip" "approval_matrix_covers_all_modes" | ||
| 112 | ;; This test verifies session-level patch | ||
| 113 | ;; approval caching: approve once, skip | ||
| 114 | ;; future prompts for the same file. When | ||
| 115 | ;; Landlock is unavailable (as in the Guix | ||
| 116 | ;; build container) the sandbox binary panics, | ||
| 117 | ;; triggering the escalation-retry path, which | ||
| 118 | ;; interferes with the approval cache and | ||
| 119 | ;; causes a spurious re-prompt on the second | ||
| 120 | ;; patch. | ||
| 121 | "--skip" "approving_apply_patch_for_session_skips_future_prompts_for_same_file" | ||
| 122 | ;; These tests expect to interrupt a | ||
| 123 | ;; long-running 'sleep 60' and receive | ||
| 124 | ;; TurnAborted. Default test config is | ||
| 125 | ;; OnRequest + ReadOnly. What happens: | ||
| 126 | ;; | ||
| 127 | ;; 1. ReadOnly wraps the command with | ||
| 128 | ;; codex-linux-sandbox (Landlock-based). | ||
| 129 | ;; 2. Landlock is unavailable in the Guix | ||
| 130 | ;; build container, so the sandbox | ||
| 131 | ;; binary exits instantly (~1 ms). | ||
| 132 | ;; 3. Orchestrator gets SandboxErr::Denied. | ||
| 133 | ;; wants_no_sandbox_approval(OnRequest) | ||
| 134 | ;; returns false (sandboxing.rs:222), | ||
| 135 | ;; so no escalation -- denial returned | ||
| 136 | ;; directly. | ||
| 137 | ;; 4. ToolEmitter::finish sends the error | ||
| 138 | ;; to the mock model as | ||
| 139 | ;; function_call_output. | ||
| 140 | ;; 5. Second mock SSE response fires, | ||
| 141 | ;; turn finishes with TurnComplete. | ||
| 142 | ;; 6. Op::Interrupt arrives 100 ms later, | ||
| 143 | ;; but the turn is already done -- | ||
| 144 | ;; TurnAborted is never emitted, | ||
| 145 | ;; test times out. | ||
| 146 | ;; | ||
| 147 | ;; The similar interrupt_long_running_tool_ | ||
| 148 | ;; emits_turn_aborted passes because it | ||
| 149 | ;; sends the interrupt with no delay and | ||
| 150 | ;; has only one mock response (so the turn | ||
| 151 | ;; cannot complete first). | ||
| 152 | "--skip" "interrupt_persists_turn_aborted_marker_in_next_request" | ||
| 153 | "--skip" "interrupt_tool_records_history_entries" | ||
| 154 | ;; Upstream bug: test hardcodes "0.0.0" in the | ||
| 155 | ;; expected user-agent string but the workspace | ||
| 156 | ;; version is "0.98.0". | ||
| 157 | "--skip" "get_user_agent_returns_current_codex_user_agent" | ||
| 158 | ;; Same upstream bug: mcp-server tests | ||
| 159 | ;; check the initialize response which | ||
| 160 | ;; includes "version": "0.0.0" but the | ||
| 161 | ;; server returns "0.98.0". | ||
| 162 | "--skip" "test_codex_tool_passes_base_instructions" | ||
| 163 | "--skip" "test_shell_command_approval_triggers_elicitation" | ||
| 164 | "--skip" "test_patch_approval_triggers_elicitation" | ||
| 165 | ;; These codex-exec-server tests need | ||
| 166 | ;; "dotslash", a Meta tool that lazily | ||
| 167 | ;; downloads pre-built binaries from a | ||
| 168 | ;; JSON manifest. The test helper | ||
| 169 | ;; create_transport runs | ||
| 170 | ;; `dotslash -- fetch <path>` to obtain a | ||
| 171 | ;; custom bash binary described in | ||
| 172 | ;; exec-server/tests/suite/bash. | ||
| 173 | ;; dotslash is not available in the build | ||
| 174 | ;; container. | ||
| 175 | "--skip" "list_tools" | ||
| 176 | "--skip" "accept_elicitation_for_prompt_rule" | ||
| 177 | ;;; Test isolation bug: each test in | ||
| 178 | ;;; state/src/runtime.rs calls | ||
| 179 | ;;; unique_temp_dir() to get its own | ||
| 180 | ;;; temporary directory (and thus its | ||
| 181 | ;;; own SQLite database). That function | ||
| 182 | ;;; names directories using the current | ||
| 183 | ;;; nanosecond timestamp, so when tests | ||
| 184 | ;;; run in parallel several can receive | ||
| 185 | ;;; the same name and open the same | ||
| 186 | ;;; database. The initial SQLite | ||
| 187 | ;;; migration runs CREATE TABLE threads | ||
| 188 | ;;; (without IF NOT EXISTS), so any init | ||
| 189 | ;;; after the first panics with "table | ||
| 190 | ;;; threads already exists". Any of | ||
| 191 | ;;; these tests | ||
| 192 | ;;; can be the victim. | ||
| 193 | "--skip" "init_removes_legacy_state_db_files" | ||
| 194 | "--skip" "upsert_and_get_thread_memory" | ||
| 195 | "--skip" "get_last_n_thread_memories_for_cwd_matches_exactly" | ||
| 196 | "--skip" "upsert_thread_memory_errors_for_unknown_thread" | ||
| 197 | "--skip" "get_last_n_thread_memories_for_cwd_zero_returns_empty" | ||
| 198 | "--skip" "get_last_n_thread_memories_for_cwd_does_not_prefix_match" | ||
| 199 | "--skip" "deleting_thread_cascades_thread_memory") | ||
| 200 | #:cargo-package-crates | ||
| 201 | ''(;;; Tier 0: No internal deps. | ||
| 202 | "codex-async-utils" | ||
| 203 | "codex-client" | ||
| 204 | "codex-execpolicy" | ||
| 205 | "codex-file-search" | ||
| 206 | "codex-git" | ||
| 207 | "codex-keyring-store" | ||
| 208 | "codex-utils-absolute-path" | ||
| 209 | "codex-utils-cache" | ||
| 210 | "codex-utils-cargo-bin" | ||
| 211 | "codex-utils-home-dir" | ||
| 212 | "codex-utils-json-to-toml" | ||
| 213 | "codex-utils-pty" | ||
| 214 | "codex-utils-readiness" | ||
| 215 | "codex-utils-string" | ||
| 216 | "codex-backend-openapi-models" | ||
| 217 | "codex-process-hardening" | ||
| 218 | "codex-ansi-escape" | ||
| 219 | ;;; Tier 1: Depends on tier 0. | ||
| 220 | "codex-utils-image" | ||
| 221 | "codex-apply-patch" | ||
| 222 | "codex-protocol" | ||
| 223 | "codex-windows-sandbox" | ||
| 224 | "codex-api" | ||
| 225 | "codex-experimental-api-macros" | ||
| 226 | "codex-secrets" | ||
| 227 | "codex-execpolicy-legacy" | ||
| 228 | "codex-debug-client" | ||
| 229 | ;;; Tier 2. | ||
| 230 | "codex-app-server-protocol" | ||
| 231 | "codex-rmcp-client" | ||
| 232 | "codex-otel" | ||
| 233 | "codex-state" | ||
| 234 | "codex-core" | ||
| 235 | "codex-linux-sandbox" | ||
| 236 | "codex-feedback" | ||
| 237 | ;;; Tier 3. | ||
| 238 | "codex-arg0" | ||
| 239 | "codex-lmstudio" | ||
| 240 | "codex-login" | ||
| 241 | "codex-ollama" | ||
| 242 | "codex-common" | ||
| 243 | "codex-mcp-server" | ||
| 244 | "codex-backend-client" | ||
| 245 | "codex-responses-api-proxy" | ||
| 246 | ;;; Tier 4. | ||
| 247 | "codex-cloud-requirements" | ||
| 248 | "codex-exec" | ||
| 249 | "codex-exec-server" | ||
| 250 | "codex-stdio-to-uds" | ||
| 251 | "codex-network-proxy" | ||
| 252 | "codex-chatgpt" | ||
| 253 | "codex-cloud-tasks-client" | ||
| 254 | ;;; Tier 5. | ||
| 255 | "codex-app-server" | ||
| 256 | "codex-app-server-test-client" | ||
| 257 | "codex-tui" | ||
| 258 | ;;; Tier 6. | ||
| 259 | "codex-cloud-tasks" | ||
| 260 | ;; The main executable. | ||
| 261 | "codex-cli") | ||
| 262 | #:phases | ||
| 263 | #~(modify-phases %standard-phases | ||
| 264 | (add-after 'unpack 'chdir-to-workspace | ||
| 265 | (lambda _ | ||
| 266 | (chdir "codex-rs"))) | ||
| 267 | (add-after 'chdir-to-workspace 'update-version-in-snapshots | ||
| 268 | (lambda _ | ||
| 269 | ;; Snapshot test files contain hardcoded v0.0.0 version strings. | ||
| 270 | ;; Update them to match the actual package version. | ||
| 271 | (let ((snap-files (find-files "." "\\.snap$"))) | ||
| 272 | (substitute* snap-files | ||
| 273 | (("\\(v0\\.0\\.0\\) ") "(v0.98.0)"))))) | ||
| 274 | (add-after 'chdir-to-workspace 'patch-git-deps-to-vendor | ||
| 275 | (lambda _ | ||
| 276 | ;; Replace git dependencies with version references so cargo | ||
| 277 | ;; resolves them from the vendored sources. | ||
| 278 | (substitute* "Cargo.toml" | ||
| 279 | (("nucleo = \\{ git = [^}]+\\}") | ||
| 280 | "nucleo = \"0.5.0\"") | ||
| 281 | (("runfiles = \\{ git = [^}]+\\}") | ||
| 282 | "runfiles = \"0.1.0\"")))) | ||
| 283 | (add-after 'chdir-to-workspace 'add-version-to-workspace-deps | ||
| 284 | (lambda _ | ||
| 285 | ;; cargo package requires all dependencies to have versions. | ||
| 286 | ;; cargo package requires all dependencies to have versions. | ||
| 287 | ;; Add version = "0.98.0" to internal path dependencies. | ||
| 288 | (let ((cargo-files (find-files "." "^Cargo\\.toml$"))) | ||
| 289 | (substitute* cargo-files | ||
| 290 | ;; Handle inline deps: name = { path = "..." } | ||
| 291 | (("(codex-[a-z0-9-]+) = \\{ path = " all name) | ||
| 292 | (string-append name " = { version = \"0.98.0\", path = ")) | ||
| 293 | ;; Handle inline deps with package: name = { package = "...", path = "..." } | ||
| 294 | (("(codex-[a-z0-9-]+) = \\{ package = " all name) | ||
| 295 | (string-append name " = { version = \"0.98.0\", package = ")) | ||
| 296 | ;; Handle section deps: [dependencies.X] with path = "..." | ||
| 297 | (("^(path = \"\\.\\./[^\"]*\")" all path-line) | ||
| 298 | (string-append path-line "\nversion = \"0.98.0\"")))))) | ||
| 299 | (add-after 'chdir-to-workspace 'patch-hardcoded-paths | ||
| 300 | (lambda* (#:key inputs #:allow-other-keys) | ||
| 301 | (let ((bash-bin (string-append | ||
| 302 | (assoc-ref inputs "bash-minimal") "/bin")) | ||
| 303 | (coreutils-bin (string-append | ||
| 304 | (assoc-ref inputs "coreutils") "/bin")) | ||
| 305 | (git-bin (string-append | ||
| 306 | (assoc-ref inputs "git-minimal") "/bin")) | ||
| 307 | (sed-bin (string-append | ||
| 308 | (assoc-ref inputs "sed") "/bin")) | ||
| 309 | ;; Include .policy files: the execpolicy-legacy | ||
| 310 | ;; crate embeds default.policy via include_str! | ||
| 311 | ;; at compile time, so its paths must also be | ||
| 312 | ;; patched. | ||
| 313 | (rs-files (find-files "." "\\.(rs|policy)$"))) | ||
| 314 | (substitute* rs-files | ||
| 315 | (("\"/bin/bash\"") | ||
| 316 | (string-append "\"" bash-bin "/bash\"")) | ||
| 317 | (("\"/bin/sh\"") | ||
| 318 | (string-append "\"" bash-bin "/sh\"")) | ||
| 319 | (("\"/usr/bin/bash\"") | ||
| 320 | (string-append "\"" bash-bin "/bash\"")) | ||
| 321 | (("\"/usr/bin/sh\"") | ||
| 322 | (string-append "\"" bash-bin "/sh\"")) | ||
| 323 | ;;; bash/sh with inline arguments, e.g. "/bin/bash -i". | ||
| 324 | (("\"/bin/bash ") | ||
| 325 | (string-append "\"" bash-bin "/bash ")) | ||
| 326 | (("\"/bin/sh ") | ||
| 327 | (string-append "\"" bash-bin "/sh ")) | ||
| 328 | ;; coreutils. | ||
| 329 | (("\"/bin/(cat|cp|date|echo|head|ls|rm|sleep|true|touch)\"" all cmd) | ||
| 330 | (string-append "\"" coreutils-bin "/" cmd "\"")) | ||
| 331 | ;; coreutils. | ||
| 332 | (("\"/usr/bin/(cat|cp|head|ls|touch|true)\"" all cmd) | ||
| 333 | (string-append "\"" coreutils-bin "/" cmd "\"")) | ||
| 334 | ;; coreutils with inline arguments | ||
| 335 | ;; like "/bin/echo END-EVENT". | ||
| 336 | (("\"/bin/(cat|cp|date|echo|head|ls|rm|sleep|true|touch) " all cmd) | ||
| 337 | (string-append "\"" coreutils-bin "/" cmd " ")) | ||
| 338 | (("\"/usr/bin/git\"") | ||
| 339 | (string-append "\"" git-bin "/git\"")) | ||
| 340 | (("\"/usr/bin/sed\"") | ||
| 341 | (string-append "\"" sed-bin "/sed\""))) | ||
| 342 | ;; @SHELL@ placeholder from test-shebangs patch | ||
| 343 | (substitute* | ||
| 344 | (list "rmcp-client/src/program_resolver.rs" | ||
| 345 | "tui/src/external_editor.rs") | ||
| 346 | (("@SHELL@") | ||
| 347 | (string-append bash-bin "/sh"))) | ||
| 348 | ;; shebang in test-only file | ||
| 349 | (substitute* | ||
| 350 | "core/tests/suite/user_notification.rs" | ||
| 351 | (("#!/bin/bash") | ||
| 352 | (string-append "#!" bash-bin "/bash")))))) | ||
| 353 | (add-before 'check 'set-home | ||
| 354 | (lambda _ | ||
| 355 | (setenv "HOME" "/tmp") | ||
| 356 | (setenv "USER" "nixbld")))))) | ||
| 357 | (native-inputs (list clang ;bindgen uses libclang to parse BoringSSL's C headers | ||
| 358 | cmake-minimal ;BoringSSL is compiled from C source | ||
| 359 | libunwind ;BoringSSL tests verify stack unwinding in assembly | ||
| 360 | perl python-minimal ;for tests | ||
| 361 | pkg-config)) | ||
| 362 | (inputs (cons* bash-minimal coreutils git-minimal sed | ||
| 363 | openssl sqlite `(,zstd "lib") | ||
| 364 | (cargo-inputs 'codex))) | ||
| 365 | (home-page "https://github.com/openai/codex") | ||
| 366 | (synopsis "AI-assisted coding CLI and TUI") | ||
| 367 | (description | ||
| 368 | "Codex is an AI-powered coding assistant that runs in the terminal. | ||
| 369 | It provides an interactive TUI for conversations with AI models, with | ||
| 370 | support for shell command execution, file editing, and code generation. | ||
| 371 | Configure providers via @file{~/.codex/config.toml}.") | ||
| 372 | (license license:asl2.0))) | ||
| 373 | |||
| 374 | (define-public codex-acp | ||
| 375 | (package | ||
| 376 | (name "codex-acp") | ||
| 377 | (version "0.9.2") | ||
| 378 | (source | ||
| 379 | (origin | ||
| 380 | (method git-fetch) | ||
| 381 | (uri (git-reference | ||
| 382 | (url "https://github.com/zed-industries/codex-acp") | ||
| 383 | (commit (string-append "v" version)))) | ||
| 384 | (file-name (git-file-name name version)) | ||
| 385 | (sha256 | ||
| 386 | (base32 "190sq6s6jfz8dkj1y8305r7x6ln86qqr2j1bnfjci7f1x2wyzmsj")) | ||
| 387 | (patches (search-patches "codex-acp-0.9.2-remove-patch-sections.patch" | ||
| 388 | "codex-acp-0.9.2-replace-result-flatten.patch")))) | ||
| 389 | (build-system cargo-build-system) | ||
| 390 | (arguments | ||
| 391 | (list | ||
| 392 | #:install-source? #f | ||
| 393 | #:phases | ||
| 394 | #~(modify-phases %standard-phases | ||
| 395 | (add-after 'unpack 'patch-codex-deps | ||
| 396 | (lambda _ | ||
| 397 | ;; Rewrite git dependencies to use vendored sources from rust-codex | ||
| 398 | (substitute* "Cargo.toml" | ||
| 399 | (("git = \"https://github.com/zed-industries/codex\", branch = \"acp\"") | ||
| 400 | "version = \"0.0.0\""))))))) | ||
| 401 | (native-inputs (list pkg-config)) | ||
| 402 | (inputs (cons* openssl sqlite `(,zstd "lib") (cargo-inputs 'codex-acp))) | ||
| 403 | (home-page "https://github.com/zed-industries/codex-acp") | ||
| 404 | (synopsis "ACP-compatible agent bridging Zed Codex with ACP clients") | ||
| 405 | (description | ||
| 406 | "This package provides an Agent Client Protocol (ACP) compatible agent | ||
| 407 | that bridges the Zed Codex runtime with ACP clients over stdio. It | ||
| 408 | supports multiple LLM providers through configuration in | ||
| 409 | @file{~/.codex/config.toml} and integrates with MCP servers for filesystem | ||
| 410 | operations.") | ||
| 411 | (license license:asl2.0))) | ||
