How Lightpanda Implements JavaScript Execution via the CDP Runtime Domain

Lightpanda executes JavaScript through the CDP Runtime domain by routing Runtime.evaluate commands from the CDP dispatcher through a V8 inspector session to the Zig-based Local.compileAndRun function, which compiles and executes scripts using V8's ScriptCompiler API.

Lightpanda is a lightweight, Zig-based browser engine that implements the Chrome DevTools Protocol (CDP) to enable remote debugging and automation. Its JavaScript execution capabilities are exposed through the CDP Runtime domain, providing full compatibility with standard DevTools clients while leveraging the V8 JavaScript engine embedded within its architecture.

Architecture Overview of Lightpanda JavaScript Execution

The implementation spans multiple layers, from CDP message parsing to V8 script compilation.

CDP Runtime Domain Entry Point

The Runtime domain dispatcher resides in src/cdp/domains/runtime.zig. The processMessage function maps incoming action strings (such as "evaluate") to internal enums. For actions other than runIfWaitingForDebugger, it invokes sendInspector to forward the request.

Inspector Session Routing

The sendInspector function retrieves the current BrowserContext and forwards the raw CDP JSON payload to the inspector session via bc.callInspector. This function, defined in src/cdp/cdp.zig, writes the message to the V8 inspector and immediately triggers runMicrotasks() to process the command.

Tool Handler Integration

The actual JavaScript execution is handled as a tool in src/mcp/tools.zig. The handleEvaluate function receives the EvaluateParams, obtains the current page's JavaScript context, and prepares the execution environment before invoking the V8 binding layer.

Execution Flow from CDP to V8

The complete execution path transforms a CDP command into a V8 script evaluation:

  1. Client Request: The DevTools client sends a Runtime.evaluate command:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "Runtime.evaluate",
  "params": {
    "expression": "2 + 2"
  }
}
  1. CDP Parsing: runtime.processMessage in src/cdp/domains/runtime.zig identifies the action as .evaluate and calls sendInspector.

  2. Inspector Forwarding: The callInspector method in src/cdp/cdp.zig passes the JSON to the V8 inspector session and runs microtasks.

  3. Tool Dispatch: The inspector routes to handleEvaluate in src/mcp/tools.zig, which:

    • Parses EvaluateParams (script and optional URL)
    • Optionally navigates to a URL first (performGoto)
    • Retrieves the current page (server.session.currentPage)
    • Creates a js.Local.Scope for the page's JavaScript context
    • Sets up js.TryCatch to capture V8 exceptions
  4. V8 Compilation: handleEvaluate calls ls.local.compileAndRun(args.script, null) defined in src/browser/js/Local.zig. This function:

    • Builds a V8 ScriptOrigin and ScriptCompilerSource
    • Calls v8__ScriptCompiler__Compile to compile the source
    • Executes via v8__Script__Run
    • Returns a js.Value wrapping the V8 handle
  5. Module Evaluation: For ES modules, src/browser/js/Module.zig provides module.evaluate(), used internally by the Local APIs when a script imports modules.

  6. Response Serialization: The result is converted to a string (js_result.toStringSliceWithAlloc) and wrapped in a CDP-compliant JSON response:

{
  "id": 1,
  "result": {
    "value": "4"
  }
}

Error Handling and Exception Management

Lightpanda captures JavaScript exceptions using V8's TryCatch mechanism before they propagate back to the CDP client.

In src/mcp/tools.zig, the handleEvaluate function wraps the compileAndRun call with js.TryCatch. If V8 throws an exception during compilation or execution, caught.format serializes the exception details. The response is then sent with .isError = true and the serialized error message, maintaining CDP compatibility for runtime exceptions.

Key Source Files and Functions

Purpose File Path Key Functions
CDP Runtime domain dispatcher src/cdp/domains/runtime.zig processMessage, sendInspector
Inspector session forwarding src/cdp/cdp.zig callInspector
Tool handling for evaluation src/mcp/tools.zig handleEvaluate, EvaluateParams
V8 script compilation/execution src/browser/js/Local.zig compileAndRun
ES module evaluation src/browser/js/Module.zig evaluate
Page context management src/browser/Page.zig Context retrieval for JS scope
Browser environment src/browser/Browser.zig Inspector and microtask management

Summary

Lightpanda's JavaScript execution via the CDP Runtime domain follows a tightly integrated pipeline:

  • CDP Runtime domain in src/cdp/domains/runtime.zig parses incoming Runtime.evaluate requests and forwards them to the V8 inspector session.
  • Inspector session in src/cdp/cdp.zig routes commands to the embedded V8 engine and triggers immediate microtask processing.
  • Tool handler in src/mcp/tools.zig prepares the page context, sets up exception handling, and invokes the V8 binding layer.
  • V8 binding in src/browser/js/Local.zig compiles scripts using ScriptCompiler and executes them, returning results or capturing exceptions via js.TryCatch.

This architecture enables Lightpanda to provide full CDP-compatible JavaScript evaluation, including ES module support, while maintaining the performance benefits of Zig and V8 integration.

Frequently Asked Questions

How does Lightpanda handle JavaScript exceptions during Runtime.evaluate?

Lightpanda wraps the V8 execution in a js.TryCatch block within the handleEvaluate function in src/mcp/tools.zig. If the script throws an exception, caught.format serializes the error details, and the response is sent with .isError = true to maintain CDP compatibility for error reporting.

What is the difference between Local.zig and Module.zig in Lightpanda's JavaScript execution?

src/browser/js/Local.zig provides the compileAndRun function for traditional script evaluation using V8's ScriptCompiler, while src/browser/js/Module.zig implements module.evaluate() for ES module execution. The Local APIs internally use Module functionality when scripts contain ES module imports.

How does Lightpanda ensure CDP compatibility for the Runtime domain?

Lightpanda implements the CDP Runtime domain by parsing standard CDP messages in src/cdp/domains/runtime.zig, forwarding them through the V8 inspector session in src/cdp/cdp.zig, and formatting responses according to the CDP specification in src/mcp/tools.zig. This ensures compatibility with standard DevTools clients and automation tools.

Where does the actual V8 script compilation happen in Lightpanda?

The actual V8 compilation occurs in src/browser/js/Local.zig within the compileAndRun function. This function constructs a V8 ScriptOrigin and ScriptCompilerSource, calls v8__ScriptCompiler__Compile to compile the source code, and then executes it via v8__Script__Run.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →