# How Ego‑Lite Distinguishes Between CLI Mode and SDK Mode at Runtime

> Discover how ego-lite runtime determines CLI vs SDK mode by examining its entry script. Learn the logic behind routing to runMain or installEgoSdk.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: internals
- Published: 2026-08-26

---

**Ego‑Lite detects its execution context by checking whether [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts) is the entry script or an imported module, routing to `runMain()` for CLI mode or `installEgoSdk()` for SDK mode.**

The **citrolabs/ego-lite** repository provides a lightweight browser automation runtime that adapts its behavior based on how the code is invoked. When the entry point at [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts) is executed directly, it operates as a command-line tool; when imported as a library, it exposes the runtime as an embeddable SDK.

## Runtime Mode Detection Mechanism

The runtime distinguishes between **CLI mode** and **SDK mode** by evaluating whether the current file represents the application’s entry point. In CommonJS environments, this corresponds to the check `require.main === module`; in ES Module contexts, an equivalent determination identifies whether the file was imported or executed directly.

When [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts) is the entry script, the runtime immediately invokes **CLI mode** by calling `runMain()`. Conversely, if another module imports the file, the runtime enters **SDK mode** and exposes `installEgoSdk()` for the host application to initialize manually.

## CLI Mode: Direct Execution with runMain()

In **CLI mode**, the `runMain()` function orchestrates the execution of automation scripts provided via **STDIN**. This function reads JavaScript code from standard input, constructs a helper context using the shared infrastructure, and immediately executes the supplied script for ad‑hoc automation tasks.

The stream processing logic resides in [`package/ego-browser/src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/run.ts), which `runMain()` delegates to for consuming input and invoking the appropriate helpers. This design allows users to pipe scripts directly into the runtime without writing a custom entry point.

```bash
echo "await nav('https://example.com');" | node -e "import('./package/ego-browser/src/index.js').then(m => m.runMain())"

```

## SDK Mode: Library Integration with installEgoSdk()

When imported as a module, ego‑lite exposes **SDK mode** through the `installEgoSdk(globalThis)` function. Instead of executing a script automatically, this function installs the Ego SDK onto the provided global object, exposing methods like `nav`, `click`, and `js` without assuming control of the execution flow.

This mode is utilized by the closed‑source Ego Lite application and other host programs that embed the runtime. The host supplies its own global object—typically `globalThis`—and manually initializes the SDK to make automation helpers available within its own managed context.

```javascript
import { installEgoSdk } from './package/ego-browser/src/index.js';

// The host supplies its own global (e.g., the Ego Lite app)
installEgoSdk(globalThis);

// Now helpers like `nav`, `click`, `js` are available on the global object
await globalThis.nav('https://example.com');

```

## Shared Infrastructure Across Both Modes

Both execution paths rely on identical underlying components to ensure consistent automation behavior. The **helper context** built in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) provides the same API surface regardless of invocation method, while [`package/ego-browser/src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/browser-runtime.ts) handles the core Chrome DevTools Protocol (CDP) transport and session management.

This architectural approach guarantees that scripts written for **CLI mode** execute identically when run through **SDK mode**, as both utilize the same browser automation primitives and context isolation strategies.

## Summary

- **Mode Detection**: Ego‑Lite checks if [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts) is the entry script to determine whether to invoke `runMain()` (CLI) or export `installEgoSdk()` (SDK).
- **CLI Operation**: Reads JavaScript from STDIN and executes immediately via `runMain()`, utilizing [`package/ego-browser/src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/run.ts) for stream handling.
- **SDK Operation**: Registers helpers on a provided global object through `installEgoSdk()`, enabling embedding in host applications like the Ego Lite app.
- **Unified Runtime**: Both modes share [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) for context construction and [`package/ego-browser/src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/browser-runtime.ts) for CDP communication.

## Frequently Asked Questions

### How does ego‑lite detect if it's running in CLI mode?

Ego‑lite checks whether the current module is the application entry point using `require.main === module` in CommonJS or an equivalent ES Module check. When this condition is true, the runtime calls `runMain()` to process STDIN; otherwise, it exports `installEgoSdk()` for library usage.

### What is the difference between `runMain()` and `installEgoSdk()`?

**`runMain()`** is activated in CLI mode and immediately reads JavaScript code from STDIN, builds a helper context, and executes the script. **`installEgoSdk()`** is called in SDK mode and attaches the automation API to a provided global object without executing any script, allowing host applications to control when and how helpers are invoked.

### Can I use ego‑lite helpers in a custom host application?

Yes, by importing `installEgoSdk` from [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts) and passing your desired global object—typically `globalThis`—you can expose all ego‑lite helpers within your application's runtime environment. This pattern is used by the Ego Lite app to integrate the automation SDK into its own execution context.

### Is the underlying browser runtime the same for both CLI and SDK modes?

Yes, both modes utilize [`package/ego-browser/src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/browser-runtime.ts) for CDP transport and session handling, and both construct their execution context using [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts). This ensures that automation scripts behave identically regardless of whether they are piped through the CLI or executed within an embedded SDK context.