# How ego-lite's `help()` Function Uses Runtime JSDoc Parsing for Live API Documentation

> Discover how ego-lite's help() function uses runtime JSDoc parsing for live API documentation. Learn how build-time comments become on-demand help.

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

---

**The `help()` function in ego-lite is powered by JSDoc comments extracted at build time, embedded as JSON into the runtime bundle, and parsed on-demand when agents call `help()`.**

The `ego-lite` browser automation framework exposes a `help()` helper that lets agents discover available APIs without leaving the execution context. Unlike typical documentation systems that read source files at runtime, this implementation pre-compiles JSDoc metadata during the build process and injects it directly into the bundle. This design works within browser sandbox constraints while delivering accurate, up-to-date documentation derived from source code annotations.

## Build-Time JSDoc Extraction with Acorn

The documentation pipeline starts in `scripts/build.mjs`, where the entire bundle is parsed using the **Acorn** JavaScript parser. The build script walks the AST to collect JSDoc comments attached to every exported helper function.

Once collected, this documentation is serialized to JSON and injected into [`src/help-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/help-runtime.ts) by replacing the placeholder `__EGO_EMBEDDED_HELP_DOCS__`. This transformation happens before the TypeScript compiler processes the file, ensuring the final JavaScript bundle contains a complete, self-contained documentation payload.

The placeholder replacement is documented in the file header comment of [`src/help-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/help-runtime.ts), which warns that any manual edits to the placeholder will be overwritten during subsequent builds.

## Embedded Documentation Storage

The constant `EMBEDDED_DOCS_JSON` at line 26 of [`src/help-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/help-runtime.ts) holds the injected JSON string. This string contains an array of `HelperDoc` objects, each representing a single exported function with its JSDoc-derived metadata:

```javascript
{
  name: 'click',
  signature: 'click(selector, options?)',
  description: 'Click the element matching the selector',
  params: [
    { name: 'selector', type: 'string', description: 'CSS selector' },
    { name: 'options', type: 'object', optional: true }
  ],
  returns: null,
  async: false
}

```

The build-time injection approach eliminates filesystem dependencies. Since ego-lite runs from an `ego://` URL inside a browser sandbox without readable source access, pre-embedding the documentation is the only viable architecture.

## Runtime JSDoc Parsing and Caching

When the runtime initializes, the embedded JSON remains unparsed until first use. The function `parseEmbeddedDocs()` (lines 88-96) handles the initial JSON parse and constructs a `Map<string, HelperDoc>` for fast lookups.

Caching occurs in two stages:

- **Parsed JSON cache** — The `Map` is built once and stored in module scope (lines 28-30)
- **Getter memoization** — `getDocsMap()` (lines 79-86) ensures repeated calls return the same map instance

This lazy parsing strategy keeps startup overhead minimal for agents that never invoke `help()`.

## The Public `help()` API Surface

The `help()` method exposed to agents is constructed by `helperContext()` in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) (lines 22-49). This factory builds a façade object containing all helper functions plus the special `help` method at line 44:

```javascript
// From src/helpers.ts
help: (...names: string[]) => helpRuntime(all, ...names)

```

`helpRuntime()` (lines 30-55 in [`src/help-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/help-runtime.ts)) implements the query logic:

| Call Pattern | Return Value |
|-------------|--------------|
| `help()` | Array of all `HelperDoc` objects |
| `help('click')` | Single `HelperDoc` for named helper |
| `help('click', 'type')` | Array of matching `HelperDoc` objects |
| `help('page')` | Plain-text overview string for façade objects |
| `help('nonexistent')` | Error string indicating unknown helper |

The façade-aware routing distinguishes between function helpers (returning structured docs) and object façades like `"page"` or `"locator"` (returning pre-written summaries from an internal `FACADE_HELP` mapping).

## Formatting Human-Readable Output

Raw `HelperDoc` objects are converted to markdown-style strings by `formatHelp()` (lines 57-77). The formatter constructs output sections:

```javascript
// Example formatted output from formatHelp(clickDoc)
console.log(formatHelp(clickDoc));
/*
Click the element matching the selector
@param selector: string — CSS selector of the element to click
@param options?: object — Click options (button, clickCount, ...)
@returns: Promise<void>

click(selector, options?)
*/

```

The formatter handles optional parameters with `?` notation, includes type annotations from JSDoc `@param` tags, and preserves `@returns` documentation when present.

## Why This Architecture Enables "Runtime" JSDoc

The term "runtime JSDoc parsing" describes this system accurately despite the build-time extraction step. From the agent's perspective, documentation queries resolve dynamically during execution. The key distinction: **the runtime parses pre-generated JSON rather than source files**.

This design satisfies three constraints simultaneously:

- **Security** — No filesystem access required inside the browser sandbox
- **Freshness** — Documentation always matches the compiled bundle version
- **Performance** — Single JSON parse with cached Map lookup for subsequent queries

## Practical Usage Examples

Agents interact with `help()` through the context object:

```javascript
// List all available helpers
const all = await help();   
// → [ { name: 'click', ... }, { name: 'type', ... }, ... ]

// Get documentation for specific helpers
const [clickDoc, typeDoc] = await help('click', 'type');

// Access formatted string directly
console.log(formatHelp(await help('navigate')));

// Query a façade overview
console.log(await help('page'));   
// → "The page object provides methods for navigation, evaluation, and screenshot capture..."

```

The async signature accommodates potential future extensions, though current implementations resolve synchronously from cached data.

## Summary

- **`scripts/build.mjs`** extracts JSDoc using Acorn and injects JSON into [`src/help-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/help-runtime.ts)
- **`EMBEDDED_DOCS_JSON`** holds the serialized documentation string at line 26
- **`parseEmbeddedDocs()`** and **`getDocsMap()`** implement lazy parsing with Map caching
- **`helpRuntime()`** routes queries to single docs, arrays, façade overviews, or error strings
- **`formatHelp()`** converts structured docs to readable markdown-style output
- The architecture enables runtime documentation discovery without filesystem access

## Frequently Asked Questions

### Does `help()` read source files from disk at runtime?

No. The runtime never accesses source files. All documentation is embedded as JSON during the build process in `scripts/build.mjs`. This allows `help()` to function inside browser sandboxes where the `ego://` protocol provides no readable file access.

### What happens if I call `help()` multiple times?

The embedded JSON is parsed only on first invocation. `getDocsMap()` caches the resulting `Map<string, HelperDoc>` in module scope, making subsequent calls O(1) lookups without re-parsing.

### Can `help()` document custom helper functions I add?

Only if your custom helpers are exported from the main bundle and annotated with JSDoc comments that the Acorn parser in `scripts/build.mjs` can discover. The build-time extraction limits runtime extensibility but ensures documentation accuracy.

### Why does `help('page')` return a string instead of a `HelperDoc` object?

Façade objects like `"page"` and `"locator"` are compound objects containing multiple methods rather than single functions. `helpRuntime()` routes these to `FACADE_HELP`, a hardcoded mapping of overview strings, because their JSDoc spans multiple underlying functions with no single representative signature.