How to Add Custom Agent Helpers to ego-browser Using `agent_helpers.js`
To extend ego-browser with custom helpers, create an agent_helpers.js file in your agent workspace directory—the helperContext() function in src/helpers.ts automatically loads and merges its exports into the agent's available helper functions.
The ego-browser package from the citrolabs/ego-lite repository provides a clean extension system for adding domain-specific automation utilities. By placing a specially-named JavaScript file in your agent workspace, you can expose custom functions that agents invoke using the same ergonomic syntax as built-in helpers like click() and navigate().
Understanding the Extension System Architecture
The helper loading mechanism resides in src/helpers.ts at line 853. The helperContext() function constructs the complete set of available helpers by:
- Building a base helpers object with built-in functions
- Checking for
agent_helpers.jsin the agent workspace directory - Dynamically importing and merging any exported members
// src/helpers.ts (line 853 vicinity)
const path = join(state.agentWorkspace(), "agent_helpers.js");
if (await exists(path)) {
const mod = await import(path);
Object.assign(helpers, mod);
}
This design means custom helpers become first-class citizens—indistinguishable from native helpers in usage patterns.
Creating Your agent_helpers.js File
Required Location
Place agent_helpers.js in the root of your agent workspace. The exact path resolves via state.agentWorkspace(), which typically maps to your configured task directory.
your-workspace/
├── agent_helpers.js ← Your extension file
├── task-description.md
└── (other assets)
Export Patterns That Work
Named exports (recommended for multiple helpers):
// agent_helpers.js
/**
* Returns the current page title in uppercase.
*/
export async function pageTitleUpper() {
const title = await ego.eval(`document.title`);
return String(title).toUpperCase();
}
/**
* Clicks an element and waits for navigation with custom timeout.
*/
export async function clickAndWait(selector) {
await ego.click(selector);
await ego.waitForNavigation({ timeout: 30 });
}
Default export (useful for namespaced collections):
// agent_helpers.js
export default {
/** Returns current URL without query parameters. */
async cleanUrl() {
const url = await ego.eval('window.location.href');
return url.split('?')[0];
},
/** Checks if element exists without throwing. */
async hasElement(selector) {
try {
await ego.querySelector(selector);
return true;
} catch {
return false;
}
}
};
Both patterns merge cleanly into the helper context. The default export's members flatten into the top-level helper namespace.
Using Custom Helpers in Agent Scripts
Once agent_helpers.js exists in your workspace, any agent script can call your functions directly:
// Example agent script passed to ego-browser
await clickAndWait('a.login-button');
const title = await pageTitleUpper();
console.log(`Logged into: ${title}`);
const baseUrl = await cleanUrl();
console.log(`Canonical URL: ${baseUrl}`);
No import statements required—the helpers are pre-bound to the execution context before your script runs.
Understanding Load Timing and Lifecycle
The extension system follows predictable lifecycle rules:
| Aspect | Behavior |
|---|---|
| Load frequency | Once per agent session initialization |
| Cache invalidation | Changes require task-space reset or new session |
| Error handling | Import failures throw during helper context construction |
| Scope isolation | Custom helpers execute in same sandbox as built-ins |
If agent_helpers.js contains syntax errors, helperContext() will propagate the exception during session startup—fail fast, fix early.
Security and Sandboxing Considerations
Custom helpers inherit the same security boundary as native helpers. They cannot:
- Access the host filesystem outside the workspace directory
- Execute shell commands or spawn processes
- Break out of the browser automation sandbox
This preserves ego-browser's security guarantees while enabling powerful domain-specific extensions.
Practical Implementation Checklist
- Verify workspace path—confirm
state.agentWorkspace()resolves to your expected directory - Use
.jsextension—the loader specifically checks foragent_helpers.js, not.mjsor.ts - Export async functions—match the Promise-based pattern of built-in helpers for consistency
- Document your helpers—JSDoc comments improve maintainability and IDE support
- Test incrementally—start with one helper, verify it loads, then expand
Summary
agent_helpers.jsin your workspace root auto-loads viahelperContext()insrc/helpers.ts- Export functions using named exports or default export—both merge into the helper namespace
- Custom helpers execute with identical privileges and syntax as built-ins like
click()andnavigate() - The system loads once per session; changes require session reset to take effect
- Security sandboxing prevents filesystem or process escape regardless of helper provenance
Frequently Asked Questions
What happens if agent_helpers.js is missing or has syntax errors?
If the file doesn't exist, ego-browser proceeds with built-in helpers only—no error. Syntax errors or import failures throw during helperContext() execution, halting session initialization with a stack trace pointing to your file.
Can I use TypeScript for my custom helpers?
No—the loader specifically targets agent_helpers.js and uses dynamic import() on that exact filename. Compile TypeScript to JavaScript beforehand, or use JSDoc type annotations for editor support while keeping the .js extension.
How do I debug why my custom helper isn't appearing?
Verify three things: file is named exactly agent_helpers.js (case-sensitive), file resides in the workspace root returned by state.agentWorkspace(), and you've restarted the agent session since last edit. Add console.log() inside your helper to confirm execution.
Can multiple agent workspaces share the same custom helpers?
Each workspace loads its own agent_helpers.js independently. For shared utilities, maintain a common module elsewhere and re-export from each workspace's agent_helpers.js, or symlink the file across workspaces if your filesystem permits.
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 →