Hanzo Dev

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 = true

js_repl_tools_only can be enabled to force direct model tool calls through js_repl:

[features]
js_repl = true
js_repl_tools_only = true

When 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:

  1. CODEX_JS_REPL_NODE_PATH environment variable
  2. js_repl_node_path in config/profile
  3. node discovered on PATH

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:

  1. CODEX_JS_REPL_NODE_MODULE_DIRS (PATH-delimited list)
  2. js_repl_node_module_dirs in config/profile (array of absolute paths)
  3. 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_repl is 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 with await import("pkg").
  • Imported local files must be ESM .js / .mjs files 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 as file://..., bare package names, and node:fs.
  • Use js_repl_reset to 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 inside js_repl (including shell tools like shell / shell_command when available).
  • codex.emitImage(imageLike): adds one image to the outer js_repl function output.

Image Emission

codex.emitImage(...) accepts:

  • A data URL
  • A single input_image item
  • 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 at info level.
  • At trace level, 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.log
RUST_LOG=codex_core::tools::js_repl=trace \
LOG_FORMAT=json \
dev app-server \
2> /tmp/dev-app-server.log

Vendored 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

On this page