# Two Startup Paths for the ego-browser Package: CLI vs SDK Explained

> Explore the two startup paths for the ego-browser package: use it directly via CLI or import it as an SDK. Learn how to integrate ego-browser into your projects.

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

---

**The `ego-browser` package can be started as a direct CLI via `runMain()` or imported as a module to run `installEgoSdk()`, as implemented in [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts).**

The `ego-browser` entry point from the [citrolabs/ego-lite](https://github.com/citrolabs/ego-lite) repository dynamically detects its execution context and branches into one of two initialization flows. This dual-mode design allows the same package to function both as a standalone script executor and as a programmable SDK for agent automation.

---

## Detecting the Startup Mode in [`index.ts`](https://github.com/citrolabs/ego-lite/blob/main/index.ts)

The branching logic resides in [[`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts)](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts). At runtime, the module checks `isDirectCli()` to determine whether it was invoked directly from the command line or loaded via `import`/`require`.

```typescript
// Simplified flow from index.ts
if (isDirectCli()) {
  runMain();   // CLI execution path
} else {
  installEgoSdk();  // SDK installation path
}

```

*Source:* [`index.ts:55-59`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts#L55-L59) (imports) and the conditional block around [`index.ts:62-66`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts#L62-L66).

---

## Path 1: Direct CLI Execution via `runMain()`

When `ego-browser` is executed directly—such as `node package/ego-browser/src/index.js` or piped input—it follows the **CLI startup path**. This path:

- Reads JavaScript source code from **stdin**
- Executes the script within a prepared browser context
- Exits the process with the appropriate status code

The heavy lifting is delegated to `runMain()`, defined in [[`package/ego-browser/src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/run.ts)](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/run.ts).

### CLI Usage Example

```bash

# Execute a one-liner from stdin

echo "await page.goto('https://example.com'); console.log(await page.title());" \
  | node package/ego-browser/src/index.js

```

*Source:* Entry point conditional at [`index.ts:62-63`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts#L62-L63) invoking [`runMain()`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/run.ts).

---

## Path 2: Module Import via `installEgoSdk()`

When `ego-browser` is imported as a dependency, it follows the **SDK startup path**. This path:

- Calls `installEgoSdk()` to inject helper methods onto a target object (typically `globalThis`)
- Configures structured logging handlers
- Patches the host `ego` runtime with additional browser automation utilities
- **Does not** read from stdin or exit the process

This mode is designed for long-running agent processes that programmatically control browser sessions.

### SDK Usage Example

```javascript
// my-automation-script.mjs
import { installEgoSdk } from 'ego-browser';

// Install helpers onto the global object
installEgoSdk(globalThis);

// Helpers are now available without explicit imports
await page.goto('https://example.com');
const title = await page.title();
console.log(`Page title: ${title}`);

// Script continues executing; process does not auto-exit

```

*Source:* SDK installation block at [`index.ts:64-66`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts#L64-L66).

---

## How `isDirectCli()` Determines the Path

The runtime detection relies on inspecting `require.main` and `process.argv[1]` to check if the current module matches the entry point. When true, the CLI path executes; otherwise, the module assumes SDK mode. This heuristic ensures `import` statements in other files never accidentally trigger `runMain()`.

---

## Summary

- **`runMain()`** — Activated when `ego-browser` is run directly as a CLI; reads stdin, executes scripts, and exits.
- **`installEgoSdk()`** — Activated when `ego-browser` is imported as a module; injects helpers and prepares the runtime for programmatic use.
- Both paths originate from [[`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts)](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts), with `isDirectCli()` as the decision gate.
- The dual-path architecture is documented in [[`AGENTS.md`](https://github.com/citrolabs/ego-lite/blob/main/AGENTS.md)](https://github.com/citrolabs/ego-lite/blob/main/AGENTS.md), which identifies [`index.ts`](https://github.com/citrolabs/ego-lite/blob/main/index.ts) as the entry point with these two startup modes.

---

## Frequently Asked Questions

### What triggers the CLI mode versus SDK mode in ego-browser?

CLI mode triggers when the module is executed directly—`node package/ego-browser/src/index.js` or equivalent—causing `isDirectCli()` to return `true`. SDK mode triggers on any `import` or `require` statement from another module, where `isDirectCli()` returns `false` and `installEgoSdk()` runs instead.

### Can I use ego-browser in a Node.js script without it exiting automatically?

Yes. Import `installEgoSdk` and call it explicitly. This SDK path does not invoke `runMain()`, so your script maintains control of the event loop and must manage its own process lifecycle. See the SDK usage example above.

### Where is the `runMain()` function defined?

The `runMain()` function is implemented in [[`package/ego-browser/src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/run.ts)](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/run.ts). It handles stdin reading, script execution, and coordinated exit codes. The entry point imports it at [`index.ts:55`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts#L55).

### Is there documentation explaining these startup paths?

Yes. The repository's [[`AGENTS.md`](https://github.com/citrolabs/ego-lite/blob/main/AGENTS.md)](https://github.com/citrolabs/ego-lite/blob/main/AGENTS.md) file explicitly states that [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts) serves as the entry point with two startup paths, though the detailed implementation requires examining the source code directly.