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 references
  • notes/*.md — Markdown documentation describing site behavior
  • tools/ — Node-side JavaScript/TypeScript modules
  • browser-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:

  • id and name — site identifiers
  • domains — 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 site
  • domain — the extracted hostname
  • knowledge — concatenated Markdown notes
  • tools — 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:

  1. findSiteSkill retrieves the manifest by siteId
  2. Validates that toolName exists in manifest.nodeTools
  3. Resolves the relative path to the tool module
  4. Dynamically imports via import(pathToFileURL(toolPath).href...)
  5. Calls the exported function named in manifest.nodeTools[toolName].callable with 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:

  1. loadBrowserToolSource reads raw JavaScript from the learning pack's browser-tools/ directory
  2. wrapBrowserTool injects the source into an async IIFE with argument binding
  3. evaluate executes 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: callable references, path existence
  • Note locations: valid notes/*.md references
  • 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: siteSkillsForUrlCore scans skills/ego-browser/learnings/ for manifests matching the target URL's domain
  • Loading: loadLearnedContext assembles Markdown notes and tool signatures into a LearnedContext
  • Node execution: runSiteTool dynamically imports and calls modules specified in manifest.nodeTools
  • Browser execution: runSiteBrowserTool fetches, wraps, and evaluates raw JavaScript in the active page
  • Validation: Schema checks via validate-learning-format.ts ensure 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →