# How the Site Skill Manifest Defines Reusable Tools and Browser Tools in Ego‑Lite

> Discover how the site skill manifest in ego-lite defines reusable Node.js utilities with nodeTools and browser helpers using browserTools for efficient automation.

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

---

**The site skill manifest declares reusable Node.js utilities and browser‑side helpers through two top‑level JSON objects: `nodeTools` for server‑side execution and `browserTools` for in‑page Chromium automation.**

In the **citrolabs/ego-lite** framework, site skills bundle domain‑specific logic for automating websites like X (Twitter). The manifest file serves as the single source of truth that registers these capabilities with the Ego Browser runtime. This article breaks down how `nodeTools` and `browserTools` work, using the actual X‑com skill implementation as a reference.

---

## Understanding the Site Skill Manifest Structure

Each site skill lives in a directory like `skills/ego-browser/learnings/x-com/` and contains a [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json) file. This manifest declares two distinct categories of reusable tools.

### Node Tools: Server‑Side Utilities

The `nodeTools` object maps tool names to Node.js functions that execute inside the skill's server context. According to the source code in [`skills/ego-browser/learnings/x-com/manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/learnings/x-com/manifest.json), each entry requires:

- `description` — Human‑readable purpose for documentation
- `path` — Relative path to the implementing JavaScript file
- `callable` — Name of the exported function to invoke
- `args` — JSON schema for parameter validation
- `returns` — JSON schema for the result type

When an agent script calls `runSiteTool(siteId, toolName, args)`, the runtime loads the file at `path`, imports the `callable` function, validates arguments against the `args` schema, executes the function, and returns the typed result.

### Browser Tools: In‑Page Automation

The `browserTools` object declares utilities that run inside the active Chromium page. As implemented in the same manifest structure, each entry contains:

- `description` — Purpose statement for help generation
- `path` — Relative path to a script injected into the page
- `returns` — Schema for the extracted data

The helper `runSiteBrowserTool(siteId, toolName)` injects the script into the browser context, runs the exported function, and returns the result. Arguments are optional unless explicitly defined.

---

## Real‑World Example: The X (Twitter) Site Skill

The X‑com skill demonstrates both tool types in practice. Here are excerpts from [[`skills/ego-browser/learnings/x-com/manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/learnings/x-com/manifest.json)](https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/learnings/x-com/manifest.json):

**Node tool** `search_users`:
- Points to [`tools/search-users.js`](https://github.com/citrolabs/ego-lite/blob/main/tools/search-users.js)
- Exposes callable `searchUsers`
- Accepts a `query` parameter and returns user objects

**Browser tool** `post_from_active_element`:
- Points to [`browser-tools/extract-post.js`](https://github.com/citrolabs/ego-lite/blob/main/browser-tools/extract-post.js)
- Extracts tweet data from the currently focused timeline element
- Returns `{ text, author, timestamp }`

At build time, the runtime scans this manifest, registers both tool types, and makes them available to agent scripts without additional wiring.

---

## Calling Tools from Agent Scripts

The [[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) file exposes two functions for tool invocation.

### Using a Node‑Side Tool

```javascript
// Manifest entry for "search_users":
// {
//   "search_users": {
//     "description": "Search for users on X.",
//     "path": "tools/search-users.js",
//     "callable": "searchUsers",
//     "args": { "type": "object", "properties": { "query": { "type": "string" } } },
//     "returns": { "type": "array", "items": { "type": "object" } }
//   }
// }

const users = await runSiteTool(
  'x-com',               // site‑skill id
  'search_users',        // tool name from manifest
  { query: 'openai' }    // validated against args schema
);

console.log(users);      // typed array per returns schema

```

The implementation in [[`tools/search-users.js`](https://github.com/citrolabs/ego-lite/blob/main/tools/search-users.js)](https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/learnings/x-com/tools/search-users.js) handles the actual API interaction.

### Using a Browser‑Side Tool

```javascript
// Manifest entry for "post_from_active_element":
// {
//   "post_from_active_element": {
//     "description": "Extract tweet data from the currently focused element",
//     "path": "browser-tools/extract-post.js",
//     "returns": { "type": "object" }
//   }
// }

const tweet = await runSiteBrowserTool(
  'x-com',                     // site‑skill id
  'post_from_active_element'   // browser‑tool name
);

console.log(tweet);            // { text, author, timestamp }

```

The [[`browser-tools/extract-post.js`](https://github.com/citrolabs/ego-lite/blob/main/browser-tools/extract-post.js)](https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/learnings/x-com/browser-tools/extract-post.js) implementation runs directly in the page's JavaScript context.

### Combining Both Tool Types

```javascript
// Fetch timeline server‑side, then extract details from active element
const timeline = await runSiteTool('x-com', 'get_timeline_posts', { maxPosts: 5 });
const firstTweet = await runSiteBrowserTool('x-com', 'post_from_active_element');

console.log({ serverData: timeline, browserData: firstTweet });

```

---

## Internal Runtime Mechanics

Behind the helper functions, two internal modules handle tool execution:

| Module | Responsibility |
|--------|---------------|
| [`src/learning/run-site-tool.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/run-site-tool.ts) | Loads Node tool files, validates arguments against schemas, executes callables |
| [`src/learning/run-browser-tool.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/run-browser-tool.ts) | Injects browser tool scripts into Chromium pages, captures return values |

Both modules read the site skill manifest to resolve tool paths and enforce type safety. The manifest's JSDoc‑compatible descriptions enable automatic `help()` generation at runtime.

---

## Summary

- The **site skill manifest** ([`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json)) centrally declares reusable tools through `nodeTools` and `browserTools` objects
- **Node tools** run server‑side via `runSiteTool()`, with full argument validation and typed returns
- **Browser tools** execute in‑page via `runSiteBrowserTool()`, enabling DOM interaction without exposing selectors to agent code
- Both tool types follow identical JSON schema patterns, making manifests self‑documenting
- The X‑com skill demonstrates production usage with `search_users` (Node) and `post_from_active_element` (browser)

---

## Frequently Asked Questions

### What file format does the site skill manifest use?

The manifest is a **JSON file** located at the root of each site skill directory, typically named [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json). It declares `nodeTools` and `browserTools` as top‑level objects mapping tool names to their specifications.

### Can browser tools accept arguments like Node tools?

**Yes, but optionally.** The `browserTools` schema supports an `args` property identical to `nodeTools`, though many browser tools rely on page state rather than explicit parameters. The `runSiteBrowserTool()` function accepts an optional third argument when the manifest defines an input schema.

### How does the runtime validate tool arguments?

Arguments are validated against the **JSON schema** defined in each tool's `args` property before execution. The [`run-site-tool.ts`](https://github.com/citrolabs/ego-lite/blob/main/run-site-tool.ts) module performs this validation for Node tools; browser tools receive the same treatment in [`run-browser-tool.ts`](https://github.com/citrolabs/ego-lite/blob/main/run-browser-tool.ts) when arguments are provided.

### Where are tool implementations stored relative to the manifest?

Tool implementations reside in subdirectories referenced by relative `path` values. In the X‑com skill, Node tools live in `tools/` and browser tools in `browser-tools/`, both sibling directories to [`manifest.json`](https://github.com/citrolabs/ego-lite/blob/main/manifest.json).