# How Ego‑Lite Handles Site Skill Discovery and Execution

> Learn how Ego-Lite handles site skill discovery and execution by scanning directories, matching domains, and running tools in Node.js or the browser.

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

---

**Ego‑Lite discovers site skills by scanning the `skills/ego-browser/learnings` directory, matching URL hostnames against [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) domains, and executes tools either in Node.js via dynamic imports or in the browser via Chrome DevTools Protocol (CDP) evaluation.**

Ego‑Lite, an open-source browser automation framework from CitroLabs, implements a modular **site skill discovery and execution** system that allows AI agents to load domain-specific knowledge and tooling at runtime. By treating each website as a self-contained learning pack with a declarative manifest, the runtime can dynamically match URLs to capabilities and invoke specialized automation scripts on either the Node.js side or directly within the browser page.

## Understanding Site Skills in Ego‑Lite

### What Is a Site Skill?

A **site skill** is a self-contained learning pack stored under `skills/ego-browser/learnings/<siteId>/`. According to the source code in [`package/ego-browser/src/learning/check-domain-learning.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/learning/check-domain-learning.ts), each pack represents a reusable automation module for a specific domain, containing structured knowledge and executable tools.

### Directory Structure and Manifest

Every skill pack requires a **[`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json)** that declares supported domains, tool schemas, and note files. The structure includes optional markdown notes in `notes/*.md` and implementation files in `tools/*`, supporting both **Node-side** and **browser-side** execution contexts. The manifest's `domains` array determines which URLs trigger the skill's discovery.

## The Discovery Pipeline: From URL to LearnedContext

### Resolving the Learning Root

The discovery process begins with **`learningsRoot()`** in [`package/ego-browser/src/learning/check-domain-learning.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/learning/check-domain-learning.ts), which constructs the absolute path to the `learnings` folder based on the agent's workspace configuration. The **`iterLearningDirs(root)`** function then walks each subdirectory, while **`learningEntry(siteDir, manifest)`** instantiates a `LearningEntry` object containing the parsed manifest, notes, and tool definitions.

### Matching Domains to Skills

To match a URL to relevant skills, **`siteSkillsForUrlCore(url, {agentWorkspace})`**—wrapped by the public `siteSkillsForUrl` helper in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) (lines 64‑68)—extracts the hostname and returns all `LearningEntry` objects whose `manifest.domains` array includes that domain.

### Loading Knowledge and Tool Schemas

The **`loadLearnedContext(url)`** function in [`package/ego-browser/src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/learning/index.ts) (lines 46‑118) orchestrates the loading phase. It calls `siteSkillsForUrl` to retrieve matching entries, reads each markdown note file, and builds tool signatures. The result is a **`LearnedContext`** object containing:

- **`knowledge`**: An array of `{siteId, fileName, content}` objects parsed from the markdown notes
- **`tools`**: An array of `{siteId, toolName, toolType, description, args, returns, example}` objects describing available capabilities

## Executing Site Skills: Node vs. Browser Contexts

### Running Node-Side Tools

For Node.js execution, the **`runSiteTool(siteId, toolName, args)`** helper in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) (lines 87‑89) delegates to the internal `runNodeSiteTool` function. The execution flow in [`package/ego-browser/src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/learning/index.ts) performs the following steps:

1. **Finding the pack**: **`findSiteSkill(siteId, options)`** (lines 31‑42) loads the specific manifest for the requested site ID
2. **Resolving the schema**: **`toolSchemas(manifest, "nodeTools")[toolName]`** extracts the tool definition including file path and exported callable name
3. **Dynamic import**: The implementation uses cache-busting dynamic imports via `import(\`${pathToFileURL(toolPath).href}?t=${Date.now()}\`)` (lines 60‑63) to ensure fresh code execution without module caching
4. **Invocation**: The exported callable is invoked with the current helper context from `helperContext()` and the provided arguments

If the manifest does not declare the tool or the exported callable is missing, the runtime throws descriptive errors (lines 54‑58, 64‑68).

### Running Browser-Side Tools

Browser-side execution uses **`runSiteBrowserTool(siteId, toolName, args)`** in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) (lines 99‑105). This process:

1. **Loads source**: **`loadBrowserToolSource`** in [`package/ego-browser/src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/learning/index.ts) (lines 78‑92) reads the JavaScript file specified in `manifest.browserTools`
2. **Wraps execution**: **`wrapBrowserTool(source, args)`** (lines 94‑96) generates an async immediately-invoked function expression (IIFE) that injects the arguments object
3. **Evaluates in page**: The `evaluate()` function executes the wrapped code within the browser page via CDP, allowing direct DOM manipulation and data extraction

## Practical Implementation Examples

**Discovering a site’s knowledge and tools:**

```typescript
// Load everything the agent knows about the current page
const ctx = await learnContext();   // calls helpers.learnContext()
console.log(ctx.siteName);          // e.g., "github"
console.log(ctx.knowledge);        // array of markdown notes
console.log(ctx.tools);            // array of tool signatures

```

**Running a Node-side tool:**

```typescript
// Execute a Node tool defined by the "google" site skill
const result = await runSiteTool("google", "search", {
  query: "ego-lite repository",
});
console.log(result);

```

**Running a browser-side tool:**

```javascript
// Execute a tool that runs inside the page context
await runSiteBrowserTool("example.com", "clickLogin", {
  selector: "#login-button",
});

```

**Fetching skills for a specific URL:**

```typescript
// Manually retrieve matching site skills
const skills = await siteSkillsForUrl("https://github.com/citrolabs/ego-lite");
console.log(skills.map(s => s.id));   // ["github"]

```

**Loading a specific learning pack:**

```typescript
const { siteDir, manifest } = await findSiteSkill("google");
console.log(manifest.name);   // "Google Search Automation"

```

## Summary

- **Site skills** are self-contained packs in `skills/ego-browser/learnings/` containing [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json), markdown notes, and tool implementations
- **Discovery** relies on `siteSkillsForUrlCore` matching URL hostnames against manifest domains, orchestrated through `loadLearnedContext` in [`learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/learning/index.ts)
- **Node-side execution** uses dynamic imports with cache-busting timestamps to invoke tools defined in `manifest.nodeTools`
- **Browser-side execution** wraps tool source in async IIFEs and evaluates them via CDP within the page context
- The architecture separates declarative manifests from imperative tool logic, enabling hot-reloading and domain-specific automation

## Frequently Asked Questions

### What is the difference between Node-side and browser-side tools in Ego‑Lite?

**Node-side tools** execute within the Node.js runtime where the Ego‑Lite agent runs, ideal for API calls, file system operations, or complex data processing. **Browser-side tools** execute within the actual browser page via CDP evaluation, enabling direct DOM manipulation, form filling, and extraction of rendered content. The manifest distinguishes these via the `nodeTools` and `browserTools` schema definitions.

### How does Ego‑Lite handle hot-reloading of site skills during development?

The `runNodeSiteTool` function implements cache-busting by appending a timestamp query parameter (`?t=${Date.now()}`) to the dynamic import URL when loading tool modules from disk. This ensures that changes to tool implementations in `skills/ego-browser/learnings/<site>/tools/` are reflected immediately without restarting the agent process.

### Where does Ego‑Lite store site skill definitions and manifests?

Site skills are stored in the file system under `skills/ego-browser/learnings/<siteId>/`, where `<siteId>` is a unique identifier. Each directory contains a [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) defining domains and tool schemas, a `notes/` folder containing markdown knowledge files, and a `tools/` folder containing JavaScript implementations for Node-side or browser-side execution.

### Can multiple site skills match a single URL?

Yes. The `siteSkillsForUrlCore` function returns an array of all `LearningEntry` objects whose `manifest.domains` include the extracted hostname. This allows Ego‑Lite to aggregate knowledge and tools from multiple relevant skills when processing a page, merging their notes and available automation capabilities into a single `LearnedContext`.