# How to Implement Custom Agent Helpers Using the agent_helpers.js Extension System in ego-browser

> Learn to implement custom agent helpers in ego-browser using the agent_helpers.js extension system by creating a file in your agent's workspace and leveraging the helperContext function.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: how-to-guide
- Published: 2026-07-26

---

**In ego-browser, custom agent helpers are implemented by creating an [`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js) file in the agent's workspace directory, which the `helperContext()` function in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) automatically imports and merges into the helper surface.**

The [citrolabs/ego-lite](https://github.com/citrolabs/ego-lite) repository provides an extension system that allows developers to augment the agent's capabilities without modifying core source code. By leveraging the **[`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js)** extension system, you can inject bespoke JavaScript functions directly into the helper context, making them available to agent scripts alongside built-in methods like `click()` and `navigate()`.

## How the Extension System Works

According to the source code in **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)** (around line 853), the **`helperContext()`** function automatically checks for an [`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js) file within the current agent workspace before executing user scripts. If present, it dynamically imports the module and assigns its exported members to the helpers object.

The loading logic implements this pattern:

```typescript
// src/helpers.ts (excerpt)
const path = join(state.agentWorkspace(), "agent_helpers.js");
if (await exists(path)) {
  const mod = await import(path);
  Object.assign(helpers, mod);
}

```

This evaluation occurs **once per agent session**, executing before any user-provided script code runs. The custom helpers become first-class citizens in the agent environment, accessible with the same `await helperName()` syntax used for native helpers.

## Creating the agent_helpers.js File

To implement custom agent helpers, create a file named exactly **[`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js)** in the root of the agent's workspace directory (the path returned by `state.agentWorkspace()`).

You can structure your exports using either **named exports** or a **default export**:

- **Named exports**: Each exported function becomes available as a standalone helper callable by name.
- **Default export**: An object containing helper methods is merged into the context, exposing all its properties as helpers.

## Practical Implementation Examples

### Example 1: Named Export Helpers

Create `<workspace>/agent_helpers.js` with asynchronous helper functions:

```javascript
// agent_helpers.js
/**
 * Returns the title of the current page in uppercase.
 */
export async function pageTitleUpper() {
  const title = await ego.eval(`document.title`);
  return String(title).toUpperCase();
}

/**
 * Clicks the first element matching a CSS selector, waiting for navigation.
 */
export async function clickAndWait(selector) {
  await ego.click(selector);
  await ego.waitForNavigation({ timeout: 30 });
}

```

Use these custom helpers in your agent script exactly like built-in methods:

```javascript
// Agent script
await clickAndWait('a.login');
const title = await pageTitleUpper();
console.log('PAGE TITLE:', title);

```

### Example 2: Default Export Pattern

Alternatively, export an object containing multiple utility functions:

```javascript
// agent_helpers.js
export default {
  /** Returns the current URL without query parameters. */
  async cleanUrl() {
    const url = await ego.eval('window.location.href');
    return url.split('?')[0];
  },
  
  /** Checks if an element exists on the page. */
  async exists(selector) {
    return await ego.eval(`!!document.querySelector('${selector}')`);
  }
};

```

After loading, both `await cleanUrl()` and `await exists()` are available throughout the agent session.

## Technical Reference and Key Constraints

When implementing custom agent helpers according to the [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) implementation, observe the following technical details:

- **File Location**: The file must reside at the workspace root as [`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js), resolved via `state.agentWorkspace()`.
- **Sandbox Environment**: Code executes in the same sandbox as built-in helpers with no host filesystem access beyond the workspace directory.
- **Reload Behavior**: Changes take effect only on the next session initialization; the file loads once per agent lifecycle and is not hot-reloaded during execution.
- **API Access**: Custom helpers can invoke built-in helpers like `ego.click()`, `ego.navigate()`, and `ego.cdp()`, composing high-level automation primitives from existing methods.

Key files in the repository:
- **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)**: Contains `helperContext()` and the dynamic import logic for extensions.
- **[`AGENTS.md`](https://github.com/citrolabs/ego-lite/blob/main/AGENTS.md)**: Documents the helper surface architecture and extension system integration.
- **`src/helpers.test.mjs`**: Provides test coverage verifying the loading behavior of custom helpers.

## Summary

- Create an [`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js) file in the agent workspace directory to extend functionality without core modifications.
- Export functions using named exports (`export function`) or default exports (`export default`).
- The `helperContext()` function in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) automatically loads and merges these helpers before script execution begins.
- Custom helpers run in the same secure sandbox as built-in methods and are accessed identically in agent scripts.
- Changes require a session restart to take effect, as the extension system evaluates [`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js) once per agent lifecycle.

## Frequently Asked Questions

### Where must the agent_helpers.js file be located?

The file must be placed in the agent's workspace directory, specifically at the path constructed by `join(state.agentWorkspace(), "agent_helpers.js")` as implemented in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts). The system checks for existence at this exact location before attempting to import the module.

### Can I use TypeScript instead of JavaScript for custom helpers?

The extension system specifically searches for [`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js). While the ego-browser source uses TypeScript, the dynamic import in `helperContext()` expects a JavaScript module. You must compile TypeScript to JavaScript before the agent session starts, ensuring the output is named [`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js) and placed in the workspace root.

### Do custom helper changes take effect immediately during debugging?

No. The [`agent_helpers.js`](https://github.com/citrolabs/ego-lite/blob/main/agent_helpers.js) file is evaluated **once per agent session** during the initialization phase within `helperContext()`. To see modifications reflected, you must restart the agent workspace or trigger a new session, which reloads the module from disk.

### Are there limitations on what APIs can be used inside custom helpers?

Custom helpers execute within the same sandbox constraints as built-in helpers, meaning they cannot access the host filesystem beyond the workspace directory. However, they have full access to the `ego` object and other built-in helpers, allowing you to compose complex automation logic using `ego.eval()`, `ego.click()`, `ego.waitForNavigation()`, and similar methods.