How Ego-Lite Discovers and Executes Site Skills (Learnings)
Ego-Lite discovers and executes site skills by scanning skills/ego-browser/learnings/<site>/ for manifests matching a URL's domain, then dynamically loads notes and tool signatures into a LearnedContext for Node-side import or browser-side evaluation.
Site skills—called "learnings" in the ego-lite codebase—are reusable, site-specific automation packs that agents can invoke without hard-coded logic. This article explains the complete discovery and execution pipeline implemented in the ego-browser package, from domain matching to runtime tool invocation.
What Are Site Skills (Learnings)?
A learning pack is a directory under skills/ego-browser/learnings/<site-id>/ containing:
manifest.json— domain patterns, tool definitions, and note referencesnotes/*.md— Markdown documentation describing site behaviortools/— Node-side JavaScript/TypeScript modulesbrowser-tools/— raw JavaScript for in-page execution
The runtime treats these as pluggable expertise that agents retrieve on demand based on the current URL.
Step 1: Locating the Correct Learning Pack
The discovery pipeline starts with siteSkillsForUrl in src/helpers.ts. This helper calls siteSkillsForUrlCore (defined in src/learning/check-domain-learning.ts) to scan the learnings directory for matching manifests.
// helpers.ts – locate site skills for a URL
export async function siteSkillsForUrl(url) {
return siteSkillsForUrlCore(url, { agentWorkspace: state.agentWorkspace() });
}
The learnings root defaults to skills/ego-browser/learnings relative to the agent workspace, as implemented in src/learning/check-domain-learning.ts. The core function iterates site directories, parses each manifest.json, and returns LearningEntry objects whose domains array matches the target URL's hostname.
Each LearningEntry contains:
idandname— site identifiersdomains— matching hostname patterns- Paths to notes and declared tools
Step 2: Loading the Learned Context
Once matches are found, learnContext(url?) (in src/helpers.ts) forwards to loadLearnedContext in src/learning/index.ts to build a structured knowledge object.
// learning/index.ts – create the learned context
export async function loadLearnedContext(url: string, options = {}): Promise<LearnedContext> {
const matches = await siteSkillsForUrl(url, options);
// ... reads notes, builds tool signatures
return {
exists: true,
siteId: matches[0].id,
siteName: matches[0].name,
domain: urlHostname(url),
knowledge: knowledgeNotes, // content of notes/*.md
tools: toolSignatures, // from manifest.nodeTools + manifest.browserTools
};
}
The resulting LearnedContext provides:
- Boolean
exists— whether a matching pack was found siteId/siteName— identifiers for the matched sitedomain— the extracted hostnameknowledge— concatenated Markdown notestools— complete signatures with descriptions, argument schemas, return schemas, and usage examples
Tool signatures are derived from both nodeTools and browserTools sections in the manifest, enabling the agent to understand available capabilities before invocation.
Step 3: Running Node-Side Tools
For server-side execution, runSiteTool(siteId, toolName, args?) in src/helpers.ts invokes runNodeSiteTool:
// helpers.ts – execute a Node tool
export async function runSiteTool(siteId, toolName, args = {}) {
return runNodeSiteTool(siteId, toolName, args, helperContext(), {
agentWorkspace: state.agentWorkspace(),
});
}
The execution flow:
findSiteSkillretrieves the manifest bysiteId- Validates that
toolNameexists inmanifest.nodeTools - Resolves the relative path to the tool module
- Dynamically imports via
import(pathToFileURL(toolPath).href...) - Calls the exported function named in
manifest.nodeTools[toolName].callablewith helper context and supplied arguments
This dynamic import pattern allows learning packs to ship arbitrary Node.js logic without recompiling the core framework.
Step 4: Running Browser-Side Tools
For DOM manipulation within the active page, runSiteBrowserTool(siteId, toolName, args?) provides a different execution model:
// helpers.ts – execute a browser tool
export async function runSiteBrowserTool(siteId, toolName, args = {}) {
const source = await loadBrowserToolSource(siteId, toolName, {
agentWorkspace: state.agentWorkspace(),
});
return evaluate(wrapBrowserTool(source, args));
}
The pipeline:
loadBrowserToolSourcereads raw JavaScript from the learning pack'sbrowser-tools/directorywrapBrowserToolinjects the source into an async IIFE with argument bindingevaluateexecutes the wrapped code in the current browser context
This source-wrapping approach avoids module bundling constraints and lets learning packs inject arbitrary page scripts dynamically.
Validation and Schema Enforcement
The validateLearning, validateLearnings, and validateSiteSkills utilities in src/learning/validate-learning-format.ts ensure manifest integrity. These power the CLI command:
npm run validate:site-skills
Validation checks:
- Required fields:
domains,id,name - Tool definitions:
callablereferences, path existence - Note locations: valid
notes/*.mdreferences - Schema compliance for arguments and returns
Complete Execution Flow
URL → siteSkillsForUrlCore → LearningEntry[] → loadLearnedContext
├─► learnContext() → LearnedContext (knowledge + tool signatures)
├─► runSiteTool() → dynamic import → Node tool execution
└─► runSiteBrowserTool() → load source → wrap → evaluate in page
Key Source Files
| File | Purpose |
|---|---|
src/learning/index.ts |
Core discovery, note loading, tool signature building, Node tool execution |
src/learning/check-domain-learning.ts |
Learnings directory location, site iteration, domain matching |
src/helpers.ts |
Public API: siteSkillsForUrl, learnContext, runSiteTool, runSiteBrowserTool |
src/learning/validate-learning-format.ts |
Manifest schema validation |
Summary
- Discovery:
siteSkillsForUrlCorescansskills/ego-browser/learnings/for manifests matching the target URL's domain - Loading:
loadLearnedContextassembles Markdown notes and tool signatures into aLearnedContext - Node execution:
runSiteTooldynamically imports and calls modules specified inmanifest.nodeTools - Browser execution:
runSiteBrowserToolfetches, wraps, and evaluates raw JavaScript in the active page - Validation: Schema checks via
validate-learning-format.tsensure pack integrity
Frequently Asked Questions
What directory structure is required for a site skill?
A learning pack requires skills/ego-browser/learnings/<site-id>/ containing manifest.json with domains, nodeTools, and/or browserTools arrays, plus referenced notes/*.md and tool directories. The manifest.json is the single source of truth for discovery and execution.
How does ego-lite match a URL to the correct learning pack?
The siteSkillsForUrlCore function in src/learning/check-domain-learning.ts compares the URL's hostname against each manifest's domains array. First match wins; the function returns a LearningEntry with paths and tool metadata for that site.
Can a learning pack contain both Node and browser tools?
Yes. The manifest.json supports both nodeTools (dynamically imported server-side modules) and browserTools (raw JavaScript evaluated in-page). The LearnedContext aggregates signatures from both sections for agent consumption.
How are tool arguments validated at runtime?
Argument schemas are declared in the manifest for each tool. While the core helpers don't enforce runtime validation automatically, the validate:site-skills CLI command ensures schemas are present and well-formed. Tool implementations handle their own argument parsing and error handling.
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 →