# How Site Skills and Learnings Accumulation Work in ego-browser

> Discover how ego-browser manages site skills and learnings accumulation. Explore metadata, notes, Node.js tools, and scripts for agent discovery and serving based on URL matching within the learnings directory.

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

---

**ego-browser stores reusable "site skills" in a learnings directory, where each skill bundles metadata, markdown notes, Node.js tools, and browser-injected scripts that are discovered, validated, and served to agents based on URL matching.**

The **ego-browser** package in the [citrolabs/ego-lite](https://github.com/citrolabs/ego-lite) repository implements a modular system for accumulating and executing site-specific knowledge. Rather than hard-coding selectors or scripts, agents dynamically load capabilities from a structured learnings directory. This article explains the complete pipeline—from discovery to execution—based on the source code in `package/ego-browser/src/learning/`.

## Anatomy of a Site Skill

Every site skill is a self-contained bundle at `skills/ego-browser/learnings/<site>/` containing four components:

- **[`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json)** — Metadata with `id`, `name`, `domain`, plus lists of notes, node tools, and browser tools
- **`notes/*.md`** — Human-readable knowledge that agents surface to users
- **`node-tools/*.js`** — Functions executing in the agent's Node.js environment
- **`browser-tools/*.js`** — Functions injected and executed in the page context

The manifest declares what the skill provides, while the runtime in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts) orchestrates how these components are loaded and invoked.

## URL Matching and Context Loading

The **site skills accumulation process** begins when an agent requests knowledge for a specific URL. Two core functions handle this in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts):

### Finding Relevant Skills

`siteSkillsForUrl(url, options)` scans the learnings directory and returns matching site skills. The implementation in [`src/learning/check-domain-learning.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/check-domain-learning.ts) loads each manifest via `loadLearningManifest` and filters by `domain` or explicit URL matchers.

### Building the Learned Context

`loadLearnedContext(url, options)` (lines 46–118 in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts)) iterates over matched entries to:

1. Read every markdown note file
2. Construct tool signatures for both node and browser tools
3. Return a context object with `knowledge` (notes) and `tools` (callable signatures)

```javascript
// Load the learned context for a page
const ctx = await loadLearnedContext('https://example.com/dashboard');
// ctx.knowledge → array of markdown note objects
// ctx.tools    → array of tool signatures you can call

```

## Executing Node and Browser Tools

Site skills expose two execution environments with distinct loading mechanisms.

### Node-Side Tools

`runNodeSiteTool(siteId, toolName, args, ctx, options)` loads the tool module, validates its `callable` export, and invokes it directly in the Node.js environment.

```javascript
// Run a Node-side tool defined by a site skill
await runNodeSiteTool('example-site', 'downloadCsv', { fileId: 42 }, ctx);

```

### Browser-Side Tools

`loadBrowserToolSource(siteId, toolName, options)` reads the JavaScript source, then `wrapBrowserTool` creates an async wrapper for page injection.

```javascript
// Execute a browser-side tool
const source = await loadBrowserToolSource('example-site', 'fillForm');
await eval(wrapBrowserTool(source, { fieldValues: { name: 'Bob' } }));

```

## The Accumulation Pipeline

The **site skills accumulation** process follows four stages orchestrated from [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts):

| Stage | Function | Purpose |
|-------|----------|---------|
| Discovery | `iterLearningDirs(root)` | Walks `siteSkillsRoot` yielding every site-skill folder |
| Validation | `validateLearning()` / `validateSiteSkills()` | Schema checks via [`validate-learning-format.ts`](https://github.com/citrolabs/ego-lite/blob/main/validate-learning-format.ts); invalid entries rejected early |
| Caching | Internal cache in `siteSkillsForUrl` | Results cached for process lifetime; same-domain calls are fast |
| Dynamic Reload | Timestamp suffix `?t=${Date.now()}` | Bypasses Node's module cache when tool files change |

This pipeline ensures that **ego-browser** continuously accumulates, validates, and serves per-site knowledge without requiring code changes or redeployment.

## Validation and Testing

Build-time and runtime integrity are enforced through:

- **[`src/learning/validate-learning-format.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/validate-learning-format.ts)** — Schema validation for manifests, notes, and tool definitions
- **`src/learning/index.test.mjs`** — Unit tests covering loading, URL matching, and tool execution

Validation helpers are re-exported from [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts) for use when new learnings are added programmatically.

## Introspecting Site Skills

For debugging or dynamic discovery, `findSiteSkill(siteId)` returns the skill's directory path and parsed manifest:

```javascript
// Find a site-skill by its ID (useful for introspection)
const { siteDir, manifest } = await findSiteSkill('example-site');
// manifest.nodeTools, manifest.browserTools, manifest.notes …

```

## Summary

- **ego-browser** accumulates site skills in `skills/ego-browser/learnings/<site>/` with standardized manifest, notes, and tool directories
- `siteSkillsForUrl()` and `loadLearnedContext()` in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts) match URLs and assemble callable knowledge
- Node tools execute directly via `runNodeSiteTool()`; browser tools are wrapped and evaluated in page context
- The accumulation pipeline includes discovery, validation, caching, and dynamic reload with cache busting
- Schema validation and comprehensive tests in [`validate-learning-format.ts`](https://github.com/citrolabs/ego-lite/blob/main/validate-learning-format.ts) and `index.test.mjs` ensure reliability

## Frequently Asked Questions

### How does ego-browser determine which site skills apply to a URL?

`siteSkillsForUrl()` in [`src/learning/check-domain-learning.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/check-domain-learning.ts) scans all manifests and matches based on the `domain` field or explicit URL matchers defined in each manifest. Matches are cached for the process lifetime to avoid repeated filesystem operations.

### What happens if a site skill manifest is malformed?

The `validateLearning()` and `validateSiteSkills()` functions from [`src/learning/validate-learning-format.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/validate-learning-format.ts) reject invalid manifests during the discovery phase. The skill is excluded from the accumulation results, and errors are typically surfaced at build time or during dynamic loading.

### Can site skills be updated without restarting the agent?

Yes. The `runNodeSiteTool()` implementation appends a timestamp query parameter (`?t=${Date.now()}`) to tool import URLs, bypassing Node's module cache. This enables dynamic reload when tool source files change on disk.

### What is the difference between node tools and browser tools in ego-browser?

**Node tools** run in the agent's Node.js environment with full system access, suitable for file operations or API calls. **Browser tools** are JavaScript functions injected into the page context via `loadBrowserToolSource()` and `wrapBrowserTool()`, designed for DOM manipulation and page interaction.