# How the Site Skills System in Ego-Browser Discovers and Executes Site-Specific Tools

> Discover how ego-browsers site skills system matches URLs with manifest.json patterns to dynamically execute site-specific Node.js or browser JavaScript for automation.

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

---

**The site skills system in ego-browser matches URLs against domain patterns defined in [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) files, then dynamically loads and executes either Node.js modules or browser-context JavaScript to provide site-specific automation capabilities.**

The **citrolabs/ego-lite** repository includes a powerful **site skills (learnings) subsystem** that enables any website to expose reusable automation tools to Ego-Browser agents. This architecture allows developers to place site-specific logic under a `learnings/` directory, where the **site skills system in ego-browser** automatically discovers, validates, and executes these tools without modifying core browser code.

## Site Skill Discovery via Domain Matching

Ego-Browser initiates tool discovery when a script invokes `site.runTool` or `site.runBrowserTool`. The system first identifies which site skill corresponds to the current page by matching the URL's hostname against declared domain patterns.

### Scanning the Learnings Directory

The discovery process begins in [`src/learning/check-domain-learning.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/check-domain-learning.ts), where the `siteSkillsForUrl()` function (lines 6-32) enumerates all subdirectories under `learnings/`. For each folder, it loads the [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) file using `loadLearningManifest()` and checks the `manifest.domains` array against the URL hostname using `domainMatches()`.

### Matching Domains to URLs

When a match is found, the system creates a `LearningEntry` object containing the site ID, directory path, and parsed manifest. This entry serves as the foundation for subsequent loading and execution stages.

## Loading Tool Definitions and Context

Once a matching site skill is identified, Ego-Browser aggregates the tool definitions and contextual notes required for execution.

### Resolving Site Directories and Manifests

The `findSiteSkill()` function (lines 31-42 in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts)) walks the learning directories to locate the specific site by ID. It returns the `siteDir` path and parsed `manifest`, which contains tool schemas for both Node.js and browser implementations.

### Building Tool Signatures

The `loadLearnedContext()` function (lines 42-118 in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts)) constructs an array of `LearnedToolSignature` objects by reading note files and parsing tool definitions from the manifest. Each signature includes the tool name, description, argument schema, and usage examples such as `await site.runTool("mySite", "myNodeTool", { ... })`.

## Executing Site-Specific Tools

Ego-Browser supports two execution environments: Node.js for server-side logic and browser context for DOM manipulation.

### Running Node.js Tools

For **node tools**, the `runNodeSiteTool()` function (lines 45-76 in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts)) handles execution:

1. Retrieves the tool schema from `manifest.nodeTools`
2. Validates the `path` and `callable` fields
3. Resolves the absolute file path using `relativeSitePath()`
4. Dynamically imports the module using `import()` with a file URL and cache-busting timestamp
5. Invokes the exported function: `tool(ctx, args)`

### Running Browser Tools

For **browser tools**, the system uses a different approach:

1. `loadBrowserToolSource()` reads the raw JavaScript source file
2. `wrapBrowserTool()` (lines 94-96 in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts)) wraps the source in an async IIFE: `(async () => { const __egoBrowserTool = /* source */; return await __egoBrowserTool({ /* args */ }); })()`
3. The wrapped code is evaluated via the CDP `js()` helper, executing directly in the page context with full DOM access

## Validation and Error Handling

The system includes robust validation to prevent runtime failures. The `validateLearning()`, `validateLearnings()`, and `validateSiteSkills()` functions exported from [`src/learning/validate-learning-format.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/validate-learning-format.ts) enforce schema compliance for manifests and tool definitions. The CLI script [`scripts/validate-site-skills.ts`](https://github.com/citrolabs/ego-lite/blob/main/scripts/validate-site-skills.ts) runs these validators against the entire `learnings/` directory during development.

## Practical Code Examples

### Discovering Skills for a URL

```typescript
import { loadLearnedContext } from "ego-browser/src/learning";

const url = "https://example.com/product/123";
const ctx = await loadLearnedContext(url);

if (ctx.exists) {
  console.log("Found site skill:", ctx.siteName);
  console.log("Available tools:", ctx.tools.map(t => t.toolName));
}

```

### Running a Node Tool

```typescript
// Manifest defines a node tool "addToCart"
await site.runTool("exampleSite", "addToCart", {
  productId: "123",
  quantity: 2,
});

```

### Running a Browser Tool

```typescript
await site.runBrowserTool("exampleSite", "extractPrice", {
  selector: ".price"
});

```

### Validating Site Skills via CLI

```bash
cd package/ego-browser
node scripts/validate-site-skills.ts

```

## Summary

- **Discovery**: The `siteSkillsForUrl()` function in [`check-domain-learning.ts`](https://github.com/citrolabs/ego-lite/blob/main/check-domain-learning.ts) matches URLs against `manifest.domains` patterns to identify applicable site skills.
- **Loading**: `loadLearnedContext()` and `findSiteSkill()` in [`index.ts`](https://github.com/citrolabs/ego-lite/blob/main/index.ts) resolve directories, parse manifests, and build tool signatures with complete schemas.
- **Execution**: Node tools are dynamically imported and executed via `runNodeSiteTool()`, while browser tools are wrapped in async IIFEs and evaluated through CDP using `wrapBrowserTool()`.
- **Validation**: Schema validation functions in [`validate-learning-format.ts`](https://github.com/citrolabs/ego-lite/blob/main/validate-learning-format.ts) ensure manifest integrity before runtime.

## Frequently Asked Questions

### How does ego-browser determine which site skill to use for a given URL?

Ego-browser extracts the hostname from the URL and compares it against the `domains` array in each site's [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) using the `domainMatches()` utility in [`check-domain-learning.ts`](https://github.com/citrolabs/ego-lite/blob/main/check-domain-learning.ts). The first matching manifest becomes the active site skill for that session.

### What is the difference between node tools and browser tools in the site skills system?

**Node tools** execute in the Node.js runtime and are suitable for API calls, data processing, or server-side logic; they are dynamically imported from the `learnings/` directory. **Browser tools** execute as JavaScript within the page context via Chrome DevTools Protocol (CDP), giving them direct access to the DOM and browser APIs for tasks like element extraction or form manipulation.

### Can site skills be hot-reloaded during development?

Yes. The `runNodeSiteTool()` function appends a cache-busting timestamp (`?t=${Date.now()}`) to the file URL when importing Node.js modules, ensuring the latest code is loaded on each invocation during development.

### How do I validate my site skill configuration before deployment?

Run the [`scripts/validate-site-skills.ts`](https://github.com/citrolabs/ego-lite/blob/main/scripts/validate-site-skills.ts) CLI script from the `package/ego-browser` directory. This executes the `validateLearning()` and `validateSiteSkills()` functions from [`validate-learning-format.ts`](https://github.com/citrolabs/ego-lite/blob/main/validate-learning-format.ts) to check all manifests and tool schemas for structural correctness.