Ego-Lite Entry Points Explained: CLI vs. Module API for Browser Automation
Ego-Lite exposes two main entry points—runMain() for command-line execution and installEgoSdk() for programmatic embedding—both defined in src/index.ts and sharing the same helper surface built by helperContext().
The citrolabs/ego-lite repository provides the core browser automation runtime that powers the Ego-Lite agent platform. Understanding how to invoke this runtime is essential whether you're running scripts from the terminal or embedding automation capabilities into a host application. The entire surface is implemented in TypeScript within the package/ego-browser/ directory, with clear separation between CLI orchestration and SDK installation.
The Two Main Entry Points for Ego-Lite
Ego-Lite's runtime is designed to work in both standalone and embedded contexts. The src/index.ts file detects its execution environment and branches accordingly, ensuring the same capabilities are available regardless of how you access them.
CLI Entry Point: runMain()
When the module is executed directly—either by the bundled ego-browser binary or via node dist/out/index.js—the runMain() function handles script execution.
# Direct Node execution with inline JavaScript
node dist/out/index.js <<'JS'
await nav('https://example.com')
await click('text=Login')
await waitFor('selector=#dashboard')
JS
The runMain() function, imported from src/run.ts, performs three critical operations:
- Reads JavaScript code from stdin
- Wraps the code in an asynchronous function context
- Injects the helper surface from
helperContext()before execution
This path is what the ego-browser binary uses internally, making it the primary entry point for headless automation workflows and CI/CD pipelines.
Module Entry Point: installEgoSdk()
For embedding scenarios—such as the closed-source Ego-Lite desktop application importing the runtime—installEgoSdk() provides programmatic access.
import { installEgoSdk } from 'ego-browser'
// Install the SDK onto the global object
installEgoSdk(globalThis)
// Helpers become available via globalThis.ego
await globalThis.ego.nav('https://example.com')
await globalThis.ego.click('text=Login')
The installEgoSdk() function attaches the entire helper surface to globalThis.ego, enabling host applications to drive browser automation without spawning a separate CLI process.
How the Entry Points Share Implementation
Both entry points converge on the same core implementation, ensuring behavioral consistency across invocation methods.
The helperContext() Factory
The src/helpers.ts file exports helperContext(), which constructs the public API surface. This factory returns an object containing all automation primitives:
| Helper Category | Examples |
|---|---|
| Navigation | nav(), goBack(), reload() |
| Interaction | click(), type(), press() |
| Waiting | waitFor(), waitForSelector(), waitForFunction() |
| Inspection | snapshot(), text(), attribute() |
| CDP Access | cdp(), js() |
When runMain() executes a script, it destructures these helpers into the global scope. When installEgoSdk() is called, it attaches the same object to globalThis.ego.
Environment Detection in src/index.ts
The branching logic is straightforward and explicit:
// From src/index.ts — simplified structure
if (require.main === module) {
// Running as script → CLI mode
runMain()
} else {
// Running as module → export SDK installer
module.exports = { installEgoSdk }
}
This pattern allows the same built artifact to serve dual purposes without configuration files or environment variables.
Low-Level Access: Direct Helper Context Usage
For testing or advanced scenarios, you can import helperContext() directly and invoke helpers without either entry point:
import { helperContext } from 'ego-browser/src/helpers.js'
const { nav, click, waitFor } = await helperContext()
await nav('https://example.com')
await click('#submit')
await waitFor('#thank-you')
This bypasses both runMain() and installEgoSdk(), giving you fine-grained control over helper instantiation while still leveraging the full runtime implementation from src/browser-runtime.ts and src/cdp-eval.ts.
Key Source Files Supporting Entry Points
| File | Responsibility |
|---|---|
src/index.ts |
Entry point detection and routing |
src/run.ts |
Script execution wrapper for CLI mode |
src/helpers.ts |
Helper surface construction via helperContext() |
src/browser-runtime.ts |
CDP transport layer and session management |
src/cdp-eval.ts |
cdp() and js() evaluation primitives |
src/nav.ts, src/pointer.ts, src/keyboard.ts |
Domain-specific driver implementations |
Summary
- Two entry points serve all Ego-Lite use cases:
runMain()for CLI execution andinstallEgoSdk()for programmatic embedding - Single source of truth: both entry points use
helperContext()fromsrc/helpers.tsto build the identical public API - Environment auto-detection in
src/index.tseliminates configuration—running as script triggers CLI mode, importing as module exports the SDK installer - Direct helper access via
helperContext()enables testing and custom integration scenarios
Frequently Asked Questions
How do I run Ego-Lite scripts from the command line?
Use the ego-browser binary or execute the built module with Node, passing your script via stdin. The runMain() function in src/run.ts handles stdin reading, async wrapping, and helper injection automatically. This is the standard approach for automation tasks and scheduled jobs.
Can I use Ego-Lite inside my own Node.js application?
Yes—import installEgoSdk from the ego-browser package and call it with globalThis. This embeds the entire automation surface without requiring CLI invocation. The closed-source Ego-Lite app uses this exact pattern to host the runtime internally.
What helpers are available through both entry points?
Both expose the complete set: navigation (nav, goBack), interaction (click, type, press), waiting primitives (waitFor, waitForSelector), inspection methods (snapshot, text), and raw CDP access (cdp, js). The full list is constructed by helperContext() in src/helpers.ts and documented in the source.
Why does Ego-Lite use require.main === module for detection?
This is the idiomatic Node.js pattern for distinguishing direct execution from module import. It allows src/index.ts to serve dual purposes—running as a standalone process or exporting installable functions—without external configuration, keeping the deployment artifact simple and predictable.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →