Lightpanda Agent and PandaScript – LLM at buildtime, not runtime Lightpanda launched Lightpanda Agent and PandaScript, a native browser agent that collapses Chrome, CDP, LLM, and agent framework into a single binary. The LLM runs at buildtime to generate a deterministic PandaScript, eliminating model calls at runtime for reproducible automation. This approach reduces complexity and cost for tasks like web scraping and browser automation. Introducing Lightpanda Agent and PandaScript: LLM at buildtime not runtime Francis Bouvier Cofounder & CEO TL;DR A browser agent today is four separate tools wired together: Chrome, a CDP library, an LLM, and an agent framework. Our native agent collapses those four layers into one binary. You talk to it in natural language and it does the work against a real browser. “Go to this website”, “login”, “extract this data”, “tell me that”: language is the new native interface for the browser. And if you want to replay your session, it hands you a reproducible script. No CDP, no heavy browser server, no complex setup, no LLM at runtime: everything is built in into Lightpanda. Your browser agent is four tools. It should be one. To run a browser agent today, you install Chrome, drive it over CDP with Puppeteer or Playwright, wire in an LLM to make decisions, then wrap the whole thing in an agent framework to orchestrate the calls. It works. Well, kind of: it’s a lot of moving parts for what’s often, “load a page and read some elements off it.” Each of those layers exists to translate between a human-facing browser and a machine that wants to drive it. CDP the Chrome DevTools Protocol was built so a developer could inspect a running browser from the outside, not so a program could operate one. And to wire an LLM, you need an MCP-to-CDP layer. The agent wraps a model around a tool that was never meant to be driven by a model. You are paying a translation tax at every layer. When we started Lightpanda four years ago, the question was: “what would a browser look like if you built it for machines instead of people looking at a screen?” lightpanda agent is that bet applied to the agentic stack. It is one binary that contains the browser, the runtime, and the agent. The browser is the same engine behind lightpanda serve and lightpanda fetch : it loads webpages, runs JavaScript, and handles the DOM. The runtime consists of a small set of native tools goto , click , fill , extract , evaluate , search , that let you drive the browser slash commands . The LLM that reads your request and picks tools is optional. It runs against Anthropic, OpenAI, Gemini, Hugging Face or local Ollama, or with no key at all in slash-only mode. The LLM runs at buildtime, not runtime This is the idea that everything else hangs off. Every other browser agent is a black box that calls a model on every step. With lightpanda agent , the model figures out the task, we capture that work as code, and generate a script we call it PandaScript that is reproducible and deterministic. When you replay it, you don’t need a model and the LLM is gone from the loop. There’s no model call sitting between you and the next action at replay time, no Chrome process to host, no NodeJS/Python environment to setup, and no Playwright/Puppeteer code to write. You just pass the script to Lightpanda binary, so a run is bound only by how fast the engine drives the page. And because nothing non-deterministic runs at replay, the same script produces the same result every time. You pay the model once to write the file. After that, it’s plain JavaScript that you own. Here’s what that PandaScript looks like. This script grabs the top 3 Hacker News stories, then visits each thread for its top comments: js const HN ORIGIN = "https://news.ycombinator.com"; const page = new Page ; await page.goto HN ORIGIN ; const stories = page.extract { selector: "tr.athing", limit: 3, fields: { id: { attr: "id" }, rank: ".rank", title: ".titleline a", url: { selector: ".titleline a", attr: "href" } } } ; for const story of stories { await page.goto HN ORIGIN + "/item?id=" + story.id ; try { story.comments = page.extract { selector: "tr.athing.comtr:has .commtext ", limit: 3, fields: { author: ".hnuser", text: ".commtext" } } ; } catch { story.comments = ; } } return stories; Readable vanilla JavaScript with loops, map, filter, and try/catch. And a few built-in primitives for our native tools. That’s it. The last top-level expression auto-prints as JSON. And of course you can also write or edit a PandaScript manually, or ask your AI coding assistant to do so if you prefer. PandaScript doesn’t use CDP, by design Lightpanda browser still speaks CDP with lightpanda serve , and we are actively developing it. The decision here is narrower: we chose not to put CDP inside the agent. Traditional headless automation marshals every action across CDP, with hundreds of methods running against a browser in a separate process.. Our agent skips that. It runs in-process against Lightpanda’s engine and calls a small set of native commands directly. This gives you two things: There is no serialization overhead , because a native in-process call replaces marshalling every click and fill across a wire protocol. Setup is easier , because one binary drives itself: there is no separate browser to launch, no debugging port to wire up, no NodeJS/Python environment to setup, and no CDP client to manage. As a bonus, the native commands are the same tool surface whether you drive them with natural language instructions, with commands, or with an external LLM through lightpanda mcp . That’s one of many advantages of developing a browser from scratch instead of forking Chromium: it allows us to build new AI features natively. Get started Point an API key at it, or run it with none: export ANTHROPIC API KEY=sk-ant-... or OPENAI API KEY / GOOGLE API KEY / HF TOKEN; or none for local LLM lightpanda agent interactive REPL lightpanda agent --task "top story on news.ycombinator.com?" one-shot lightpanda agent --no-llm slash commands only, no LLM lightpanda agent hn.js replay a saved script, no LLM, no key In the REPL, explore in English or with /goto , /extract , and the rest. You can generate a reproducible PandaScript from the current session with /save