JavaScript REPL
Run JavaScript in a persistent Node-backed kernel with top-level await.
js_repl runs JavaScript in a persistent Node-backed kernel with top-level await.
Feature Gate
js_repl is disabled by default and only appears when enabled:
[features]
js_repl = truejs_repl_tools_only can be enabled to force direct model tool calls through js_repl:
[features]
js_repl = true
js_repl_tools_only = trueWhen enabled, direct model tool calls are restricted to js_repl and js_repl_reset; other tools remain available via await codex.tool(...) inside js_repl.
Node Runtime
js_repl requires a Node version that meets or exceeds codex-rs/node-version.txt.
Runtime resolution order:
CODEX_JS_REPL_NODE_PATHenvironment variablejs_repl_node_pathin config/profilenodediscovered onPATH
Configure an explicit runtime path:
js_repl_node_path = "/absolute/path/to/node"Module Resolution
js_repl resolves bare specifiers (e.g. await import("pkg")) using an ordered search path. Local file imports are also supported for relative paths, absolute paths, and file:// URLs that point to ESM .js / .mjs files.
Module resolution order:
CODEX_JS_REPL_NODE_MODULE_DIRS(PATH-delimited list)js_repl_node_module_dirsin config/profile (array of absolute paths)- Thread working directory (cwd, always included as the last fallback)
Bare package imports always use this REPL-wide search path, even when they originate from an imported local file. They are not resolved relative to the imported file's location.
Usage
js_replis a freeform tool: send raw JavaScript source text.- Optional first-line pragma:
// codex-js-repl: timeout_ms=15000 - Top-level bindings persist across calls.
- If a cell throws, prior bindings remain available. Lexical bindings whose initialization completed before the throw stay available in later calls.
- Top-level static import declarations (
import x from "pkg") are currently unsupported; use dynamic imports withawait import("pkg"). - Imported local files must be ESM
.js/.mjsfiles and run in the same REPL VM context. - Local file modules reload between execs, so a later
await import("./file.js")picks up edits. import.meta.resolve()returns importable strings such asfile://..., bare package names, andnode:fs.- Use
js_repl_resetto clear the kernel state.
Helper APIs
js_repl exposes these globals inside the kernel:
codex.tmpDir: per-session scratch directory path.codex.tool(name, args?): executes a normal tool call from insidejs_repl(including shell tools likeshell/shell_commandwhen available).codex.emitImage(imageLike): adds one image to the outerjs_replfunction output.
Image Emission
codex.emitImage(...) accepts:
- A data URL
- A single
input_imageitem - An object like
{ bytes, mimeType } - A raw tool response object that contains exactly one image and no text
Call it multiple times for multiple images. It rejects mixed text-and-image content.
Examples:
// Playwright screenshot
await codex.emitImage({
bytes: await page.screenshot({ type: "jpeg", quality: 85 }),
mimeType: "image/jpeg"
});
// Local image via tool
await codex.emitImage(codex.tool("view_image", { path: "/absolute/path" }));Prefer JPEG at ~85 quality when lossy compression is acceptable; use PNG when transparency or lossless detail matters.
Nested Tool Calls
- Nested
codex.tool(...)outputs stay inside JavaScript unless you emit them explicitly. - Each
codex.tool(...)call emits a bounded summary atinfolevel. - At
tracelevel, the exact raw response object or error string is also logged.
Avoid writing directly to process.stdout / process.stderr / process.stdin; the kernel uses a JSON-line transport over stdio.
Debug Logging
Nested codex.tool(...) diagnostics are emitted through normal tracing output.
RUST_LOG=codex_core::tools::js_repl=info \
LOG_FORMAT=json \
dev app-server \
2> /tmp/dev-app-server.logRUST_LOG=codex_core::tools::js_repl=trace \
LOG_FORMAT=json \
dev app-server \
2> /tmp/dev-app-server.logVendored Parser
The kernel embeds a vendored Meriyah bundle at codex-rs/core/src/tools/js_repl/meriyah.umd.min.js (source: meriyah@7.0.0 from npm). Licensing is tracked in third_party/meriyah/LICENSE and NOTICE.
Last updated on