Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
},
env: {
node: true,
es2020: true,
},
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
ignorePatterns: ['dist/', 'node_modules/'],
};
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]

steps:
- uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint --if-present

- name: Build
run: npm run build

- name: Test
run: npm test --if-present
51 changes: 51 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Release to npm

on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version to publish (without v prefix)'
required: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm test --if-present

- name: Build
run: npm run build

- name: Publish to npm
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

create-release:
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
steps:
- uses: actions/checkout@v4

- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
179 changes: 149 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,143 @@
# Predicate Snapshot Skill for OpenClaw

ML-powered DOM pruning that reduces browser prompt tokens by **95%** while preserving actionable elements.
ML-powered DOM pruning that reduces browser prompt tokens by **up to 99.8%** while preserving actionable elements.

## Overview

This OpenClaw skill replaces the default accessibility tree snapshot with Predicate's ML-ranked DOM elements. Instead of sending 800+ elements (~18,000 tokens) to the LLM, it sends only the 50 most relevant elements (~800 tokens).
This OpenClaw skill replaces the default accessibility tree snapshot with Predicate's ML-ranked DOM elements. Instead of sending 800+ elements (~18,000 tokens) to the LLM, it sends only the 50 most relevant elements (configurable) (~500 tokens).

| Approach | Tokens | Elements | Signal Quality |
### Real-World Demo Results

Tested with the included demo (`npm run demo`):

| Site | OpenClaw Snapshot (A11y Tree) | Predicate Snapshot | Savings |
|------|-----------|-----------|---------|
| slickdeals.net | 598,301 tokens (24,567 elements) | 1,283 tokens (50 elements) | **99.8%** |
| news.ycombinator.com | 16,484 tokens (681 elements) | 587 tokens (50 elements) | **96%** |
| example.com | 305 tokens (12 elements) | 164 tokens (4 elements) | **46%** |
| httpbin.org/html | 1,590 tokens (34 elements) | 164 tokens (4 elements) | **90%** |
| **Total** | **616,680 tokens** | **2,198 tokens** | **99.6%** |

> Ad-heavy sites like slickdeals.net show the most dramatic savings—from 598K tokens down to just 1.3K tokens. Simple pages like example.com have minimal elements, so savings are lower.

### Why Fewer Elements Is Better

You might wonder: "Isn't 50 elements vs 24,567 elements comparing apples to oranges?"

**No—and here's why:**

1. **Most elements are noise.** Of those 24,567 elements on slickdeals.net, the vast majority are:
- Ad iframes and tracking pixels
- Hidden elements and overlays
- Decorative containers (`<div>`, `<span>`)
- Non-interactive text nodes
- Duplicate/redundant elements

2. **LLMs need actionable elements and enough context to reason.** For browser automation, the agent needs to:
- Click buttons and links
- Fill form fields
- Read key content for decision-making

Predicate's ML ranking identifies the ~50 most relevant elements—including both interactive controls and contextual text—while filtering out the noise.

3. **More elements = worse performance.** Sending 600K tokens to an LLM causes:
- Higher latency (slower responses)
- Higher cost ($11K+/month vs $5/month)
- Context window overflow on complex pages
- More hallucinations from irrelevant context

4. **Quality over quantity.** Predicate's snapshot includes:
- ML-ranked importance scores
- Dominant group detection (for ordinal tasks like "click 3rd item")
- Visual cues (is_primary, position)
- Semantic role information

This structured context helps LLMs make better decisions than a raw element dump.

**The goal isn't to preserve all elements—it's to preserve the right elements.**

### Proven in Production

- **Small local LLM model (3B) success**: The Predicate Snapshot engine powered a complex browser automation task using only a 3B parameter local model—[featured on Hacker News front page](https://news.ycombinator.com/item?id=46790127)
- **Deep dive**: Read why the accessibility tree alone isn't enough for web automation: [Why A11y Alone Isn't Enough](https://predicatesystems.ai/blog/why-ax-alone-isnt-enough)

### Summary

| Approach | Tokens (avg) | Elements | Signal Quality |
|----------|--------|----------|----------------|
| Accessibility Tree | ~18,000 | ~800 | Low (noise) |
| Predicate Snapshot | ~800 | 50 | High (ML-ranked) |
| Accessibility Tree | ~150,000+ | ~6,000+ | Low (noise) |
| Predicate Snapshot | ~500-1,300 | 50 | High (ML-ranked) |

## Installation
## Quick Start

### Via ClawHub (Recommended)
### 1. Install the Skill

**Via ClawHub (Recommended):**
```bash
npx clawdhub@latest install predicate-snapshot
```

### Manual Installation

**Manual Installation:**
```bash
git clone https://github.com/predicate-systems/predicate-snapshot-skill ~/.openclaw/skills/predicate-snapshot
git clone https://github.com/PredicateSystems/openclaw-predicate-skill ~/.openclaw/skills/predicate-snapshot
cd ~/.openclaw/skills/predicate-snapshot
npm install
npm run build
```

## Configuration

### API Key
### 2. Get Your API Key

Get your free API key at [predicate.systems/keys](https://predicate.systems/keys)
1. Go to [PredicateSystems.ai](https://www.PredicateSystems.ai)
2. Sign up for a **free account (includes 500 free credits/month)**
3. Navigate to **Dashboard > API Keys**
4. Click **Create New Key** and copy your key (starts with `sk-...`)

Set via environment variable:
### 3. Configure the API Key

**Option A: Environment Variable (Recommended)**
```bash
export PREDICATE_API_KEY="sk-..."
# Add to your shell profile (~/.bashrc, ~/.zshrc, etc.)
export PREDICATE_API_KEY="sk-your-key-here"
```

Or in `~/.openclaw/config.yaml`:
**Option B: OpenClaw Config File**

Add to `~/.openclaw/config.yaml`:
```yaml
skills:
predicate-snapshot:
api_key: "sk-..."
max_credits_per_session: 100
api_key: "sk-your-key-here"
max_credits_per_session: 100 # Optional: limit credits per session
```

### 4. Verify Installation

```bash
# In OpenClaw, run:
/predicate-snapshot
```

If configured correctly, you'll see a ranked list of page elements.

## How It Works

### Does This Replace the Default A11y Tree?

**No, this skill does not automatically replace OpenClaw's default accessibility tree.** Instead, it provides an alternative snapshot command that you can use when you want better element ranking.

| Command | What It Does |
|---------|--------------|
| Default OpenClaw | Uses raw accessibility tree (~18,000 tokens) |
| `/predicate-snapshot` | Uses ML-ranked Predicate snapshot (~500 tokens) |
| `/predicate-snapshot-local` | Uses local heuristic ranking (free, no API) |

**To use Predicate snapshots in your workflow:**
1. Use `/predicate-snapshot` instead of the default page observation
2. Use `/predicate-act click <ID>` to interact with elements by their ID
3. The element IDs from Predicate snapshots work with `/predicate-act`

**Future:** OpenClaw may add configuration to set Predicate as the default snapshot provider.

## Usage

### Capture Snapshot
Expand Down Expand Up @@ -105,16 +194,6 @@ Uses heuristic ranking without ML API calls. Lower accuracy but no credits consu
| DG | Dominant group identifier |
| href | Link URL if applicable |

## Pricing

| Tier | Credits/Month | Price |
|------|---------------|-------|
| Hobby | 500 | Free |
| Builder | 20,000 | $19/mo |
| Pro | 40,000 | $49/mo |
| Teams | 120,000 | $149/mo |
| Enterprise | Custom | Contact us |

Each ML-powered snapshot consumes 1 credit. Local snapshots are free.

## Development
Expand All @@ -123,10 +202,50 @@ Each ML-powered snapshot consumes 1 credit. Local snapshots are free.

Compare token usage between accessibility tree and Predicate snapshot:

Get free credits for testing at https://www.PredicateSystems.ai

```bash
# With API key (REAL ML-ranked snapshots)
PREDICATE_API_KEY=sk-... npm run demo

# Without API key (uses extension's local ranking)
npm run demo
```

Example output:
```
======================================================================
TOKEN USAGE COMPARISON: Accessibility Tree vs. Predicate Snapshot
======================================================================
Mode: PredicateBrowser with extension loaded
Snapshots: REAL (API key detected)
======================================================================

Analyzing: https://news.ycombinator.com
Capturing accessibility tree...
Capturing Predicate snapshot (REAL - ML-ranked via API)...

======================================================================
RESULTS
======================================================================

news.ycombinator.com (REAL)
+---------------------------------------------------------+
| Accessibility Tree: 16,484 tokens (681 elements) |
| Predicate Snapshot: 587 tokens (50 elements) |
| Savings: 96% |
+---------------------------------------------------------+

======================================================================
TOTAL: 616,680 -> 2,198 tokens (99.6% reduction)
======================================================================

MONTHLY COST PROJECTION (5,000 tasks × 5 snapshots = 25,000 snapshots)
Accessibility Tree: $11,562.75 (LLM tokens only)
Predicate Snapshot: $5.12 ($1.37 LLM + $3.75 API)
Monthly Savings: $11,557.63
```

### Build

```bash
Expand Down Expand Up @@ -165,5 +284,5 @@ predicate-snapshot-skill/
## Support

- Documentation: [predicate.systems/docs](https://predicate.systems/docs)
- Issues: [GitHub Issues](https://github.com/predicate-systems/predicate-snapshot-skill/issues)
- Issues: [GitHub Issues](https://github.com/PredicateSystems/openclaw-predicate-skill/issues)
- Discord: [Predicate Community](https://discord.gg/predicate)
Loading
Loading