# How Site Skills Are Structured in ego-lite and Where They Are Stored

> Discover how ego-lite structures site skills. Learn where these self-contained bundles are stored and what components they include for runtime discovery.

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

---

**Site skills in ego-lite are self-contained bundles stored under `skills/ego-browser/learnings/`, each containing a [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json), markdown notes, Node tools, and browser tools that the runtime discovers through domain matching.**

The **ego-lite** framework by Citrolabs implements site-specific automation through modular skill bundles. Understanding how site skills are structured and where they are stored is essential for extending the agent's capabilities to new websites. Each skill bundle maps to a specific domain and encapsulates the knowledge and executable tools required to interact with that site.

## Physical Storage Location and Bundle Components

Site skills reside in the filesystem under `skills/ego-browser/learnings/`. Each subdirectory represents a single website identified by a unique ID such as `"google"` or `"x-com"`.

### The Manifest File

Every skill requires a [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) file that declares the **ID**, **name**, target **domains**, **notes** (markdown knowledge files), and **tool** definitions. Node-side tools are listed under the `nodeTools` key, while browser-side tools appear under `browserTools`.

### Knowledge Notes

The `notes/` directory contains markdown files providing human-readable context that agents retrieve via `site.learnContext`. These files contain examples, tips, and structural information about the target website.

### Tool Implementations

- **`tools/*.js`**: JavaScript modules implementing Node-side tools referenced in the manifest.
- **`browser-tools/*.js`**: Scripts that execute within the page context for browser-side tools.

The complete bundle structure resembles this layout:

```text
skills/
└─ ego-browser/
   └─ learnings/
      ├─ google/
      │   ├─ manifest.json
      │   ├─ notes/
      │   │   └─ overview.md
      │   └─ browser-tools/
      │       └─ autocomplete.js
      └─ x-com/
          ├─ manifest.json
          ├─ notes/
          │   └─ overview.md
          └─ tools/
              └─ timeline.js

```

## Runtime Discovery and Domain Matching

The discovery process begins when an agent calls `site.skills(url)` or `site.skillsForUrl(url)`. In [`/package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main//package/ego-browser/src/helpers.ts), the `siteSkillsForUrl` function forwards requests to `siteSkillsForUrlCore` in [`/package/ego-browser/src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main//package/ego-browser/src/learning/index.ts).

The matching process follows these steps:

1. **Directory Traversal**: `siteSkillsForUrlCore` utilizes `iterLearningDirs` from [`/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) to walk the `learningsRoot` directory (defaulting to `skills/ego-browser/learnings`).

2. **Manifest Validation**: Each discovered directory's [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) is parsed by `loadLearningManifest`. If the requested URL's hostname matches any entry in `manifest.domains`, the skill is returned to the agent.

3. **Facade Exposure**: The `createSiteFacade` function in [`/package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main//package/ego-browser/src/helpers.ts) exposes these capabilities to agent scripts through the `site` object.

## Tool Execution Architecture

Once discovered, site skills expose two distinct tool types with different execution environments.

### Node-Side Tools

Node tools run in the Node.js runtime environment. The system invokes them via `runNodeSiteTool`, which loads the module specified by `manifest.nodeTools[tool].path` and executes the exported `callable` function.

### Browser-Side Tools

Browser tools execute within the actual web page context. The runtime fetches the script source using `loadBrowserToolSource`, then injects it via `evaluate(wrapBrowserTool(...))` to run inside the browser environment with access to the DOM.

## Working with Site Skills in Agent Scripts

### Listing Available Skills for the Current Page

```javascript
const skills = await site.skills();   // Uses current page URL
console.log(skills);                  // → [{id:'google', name:'Google Search', ...}]

```

### Executing Node-Side Tools

```javascript
const results = await site.runTool(
  'google',                     // siteId from manifest
  'search_and_extract',         // tool name defined in manifest
  { query: 'ego lite', maxResults: 5 }
);
console.log(results);           // [{title, url, snippet}, …]

```

### Running Browser-Side Tools

```javascript
await page.goto('https://x.com');
const suggestions = await site.runBrowserTool(
  'x-com',
  'post_from_active_element',
  {}
);
console.log(suggestions);      // {text, author, timestamp}

```

### Retrieving Knowledge Context

```javascript
const ctx = await site.learnContext('https://google.com');
ctx.knowledge.forEach(note => {
  console.log(`--- ${note.fileName} ---`);
  console.log(note.content);
});

```

## Summary

- Site skills are stored as self-contained bundles in `skills/ego-browser/learnings/<site-id>/`
- Each bundle requires a [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) declaring domains, tools, and references to markdown notes
- Discovery occurs through `siteSkillsForUrlCore` by matching URL hostnames against manifest `domains` arrays
- Node tools execute in the Node.js runtime via `runNodeSiteTool` using modules from `tools/*.js`
- Browser tools execute in page context via `evaluate(wrapBrowserTool(...))` using scripts from `browser-tools/*.js`
- The `site` facade in [`/package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main//package/ego-browser/src/helpers.ts) provides the public API (`site.skills`, `site.runTool`, etc.) for agent scripts

## Frequently Asked Questions

### What file format defines a site skill's capabilities?

The [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) file defines the skill's **ID**, display **name**, applicable **domains**, references to markdown **notes**, and **tool** signatures for both Node and browser environments. This file must exist in the skill's root directory for the runtime to recognize the bundle.

### How does ego-lite match a URL to the correct site skill?

The `siteSkillsForUrlCore` function in [`/package/ego-browser/src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main//package/ego-browser/src/learning/index.ts) traverses all learning directories and uses `loadLearningManifest` to parse each manifest. It returns the skill if the URL's hostname matches any domain listed in the manifest's `domains` array, enabling automatic skill selection based on the current website.

### Can I add a new site without modifying the core source code?

Yes. Create a new directory under `skills/ego-browser/learnings/` with a valid [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) and optional `notes/` and `tools/` directories. The runtime automatically discovers new skills during the directory traversal performed by `iterLearningDirs`, requiring no changes to [`/package/ego-browser/src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main//package/ego-browser/src/learning/index.ts) or other core files.

### What is the difference between Node tools and browser tools?

**Node tools** execute in the Node.js runtime environment and are loaded from `tools/*.js` via `runNodeSiteTool`, suitable for API calls and data processing. **Browser tools** execute in the actual browser page context, loaded from `browser-tools/*.js` and injected using `evaluate(wrapBrowserTool(...))` to interact with the DOM and access JavaScript variables on the page.