How Site Skills (Learnings) Work in ego-lite: Discovery, Loading, and Validation
Site skills in ego-lite are reusable, per-site knowledge packs stored under skills/ego-browser/learnings/ that provide agents with contextual notes, selectors, and executable tools—all validated through a strict schema enforcement system before runtime use.
In ego-lite, site-specific intelligence isn't hardcoded. Instead, the framework uses a modular learning subsystem that lets you package knowledge for any website into version-controlled directories. This article explains how these learnings are structured, discovered, loaded into the agent runtime, and rigorously validated to ensure reliability.
What Site Skills (Learnings) Actually Are
A site learning is a directory named after its site ID (e.g., google, x-com) containing four core components:
| Component | Location | Purpose |
|---|---|---|
manifest.json |
learnings/<site>/manifest.json |
Declares site ID, human-readable name, domain patterns, note files, and tool definitions |
| Knowledge notes | learnings/<site>/notes/*.md |
Markdown documentation with site descriptions and selector hints |
| Node tools | learnings/<site>/tools/*.js |
Server-side JS modules with callable functions |
| Browser tools | learnings/<site>/browser-tools/*.js |
Client-side JS snippets executed via site.runBrowserTool |
The runtime discovers and loads these learnings dynamically through the learning subsystem in package/ego-browser/src/learning/.
How Site Skills Are Discovered and Loaded
The loading pipeline involves three distinct phases: domain matching, context assembly, and tool execution.
Domain Matching
When an agent requests knowledge for a URL, siteSkillsForUrl() in check-domain-learning.ts extracts the hostname and iterates over every learning directory via iterLearningDirs. It keeps only those learnings whose manifest.domains field matches the host—supporting both exact matches and wildcards like *.example.com.
// Discover learnings for a URL
const { siteSkillsForUrl } = await import('ego-browser');
const matches = await siteSkillsForUrl('https://news.x.com/articles/123');
console.log(matches.map(m => m.id)); // → ["x-com"]
The domainMatches function handles pattern evaluation, comparing the extracted urlHostname against each declared domain pattern.
Context Assembly
loadLearnedContext (exported from index.ts) orchestrates the full loading process. It calls siteSkillsForUrl() to gather matching learnings, then reads each note file and builds tool signatures for both node and browser tools. The result is a LearnedContext object consumed through helpers like site.runTool() and site.runBrowserTool().
// Load the full learned context (notes + tool signatures)
import { loadLearnedContext } from 'ego-browser';
const ctx = await loadLearnedContext('https://google.com');
if (ctx.exists) {
console.log('Site name:', ctx.siteName);
console.log('Available tools:', ctx.tools.map(t => t.toolName));
console.log('Notes files:', ctx.knowledge.map(n => n.fileName));
}
Tool Execution
- Node tools: Dynamically imported via
import()throughrunNodeSiteToolinindex.ts, then invoked with the exported callable function - Browser tools: Read as plain text via
loadBrowserToolSource(), wrapped in an async IIFE viawrapBrowserTool(), and executed viasite.runBrowserTool()
// Running a node-tool from a learning
await site.runTool('google', 'search', { query: 'open source AI' });
// Loads skills/ego-browser/learnings/google/tools/search.js and invokes the exported callable
All learning helpers are exposed to agents through helperContext() in src/helpers.ts.
The Site Skills Validation Process
Before any learning can be used, it must pass comprehensive schema validation implemented in validate-learning-format.ts. The validateLearning() and validateLearnings() functions enforce a strict contract across six validation layers.
Manifest Validation
The validator confirms:
manifest.jsonexists and parses as valid JSONidmatches the directory name exactlynameis non-emptydomainsis a non-empty array of well-formed patterns
Domain Pattern Checks
Each domain must be either:
- A plain hostname (
example.com) - A single leading wildcard (
*.example.com)
The isValidDomain() function rejects malformed patterns.
Note File Verification
Every entry in manifest.notes must:
- Use relative paths matching
notes/*.md - Point to existing files (verified via
requireFile) - Exclude temporary snapshot references (blocked by
rejectTemporaryRefs)
This prevents agents from relying on fragile, auto-generated selectors that break on page changes.
Tool Schema Enforcement
| Tool Type | Requirements |
|---|---|
| Node tools | Relative tools/*.js path, non-empty callable name, valid args/returns schema; JS file is imported to verify callable exists |
| Browser tools | Relative browser-tools/*.js path, valid argument/return schemas; source checked for temporary refs |
Value Type Constraints
Argument and return schemas are restricted to JSON-Schema primitives defined in TOOL_VALUE_TYPES. This ensures type-safe serialization between the agent runtime and tool implementations.
Safety Sanitization
Tool names and paths undergo isSafeToolName() and isSafeRelativePath() checks to prevent:
- Directory traversal attacks
- Malformed identifiers
- Path injection vulnerabilities
Running Validation
The top-level entry point validateLearnings() (exported as validateSiteSkills) walks all learning directories via iterLearningDirs() and aggregates errors. The repository includes a CLI convenience script:
# Validate all site skills in the repository
node package/ego-browser/scripts/validate-site-skills.ts
# Exits code 0 when all learnings pass; prints detailed errors otherwise
Why Site Skill Validation Matters
- Selector stability — Rejecting temporary refs (
@123orref=123) forces durable, maintainable locators - Runtime reliability — Catches missing files and malformed manifests before deployment
- Deterministic contracts — Tool argument/return schemas enable automatic documentation generation via
site.runTool().help()
Summary
- Site skills in ego-lite are modular knowledge packs under
skills/ego-browser/learnings/<site-id>/ - Discovery uses hostname matching against
manifest.domainspatterns incheck-domain-learning.ts - Full context loading combines notes and tool signatures via
loadLearnedContext()inindex.ts - Node tools execute server-side via dynamic
import(); browser tools inject into page context - Six-layer validation in
validate-learning-format.tsenforces manifest integrity, domain correctness, file existence, schema compliance, type safety, and path sanitization - Use
validateLearnings()orscripts/validate-site-skills.tsto verify learnings before runtime use
Frequently Asked Questions
How do I create a new site skill for ego-lite?
Create a directory under skills/ego-browser/learnings/ named with your site ID (e.g., my-site). Add a manifest.json declaring id, name, and domains. Place Markdown notes in notes/ and JavaScript tools in tools/ (server-side) or browser-tools/ (client-side). Run the validation script to verify your learning passes all checks before committing.
What happens if a learning fails validation?
validateLearnings() collects all errors and returns them in detail—manifest syntax failures, missing files, invalid domain patterns, schema mismatches, or temporary snapshot references. The CLI script exits with a non-zero status code, blocking CI/CD pipelines from deploying broken learnings.
Can site skills use wildcards in domain patterns?
Yes. The domainMatches function supports *.example.com patterns for subdomain matching. However, wildcards are restricted to a single leading asterisk—patterns like example.*.com are rejected by isValidDomain() to prevent ambiguous matching.
Where does ego-lite load site skills from at runtime?
The iterLearningDirs() function scans skills/ego-browser/learnings/ relative to the working directory. This discovery happens dynamically in siteSkillsForUrl() and loadLearnedContext(), allowing hot-reloading of learnings without restarting the agent runtime.
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 →