Skip to content

vardhin/lexicon

Repository files navigation

LSD Architecture

LSD — Lexicon Shell Daemon

A transparent, fullscreen overlay OS layer for Linux — triggered by a hotkey, driven by natural language, rendered as floating glass widgets.

"It's a shell that lives on top of your entire screen — like a heads-up display for your desktop. You press a key, a transparent layer appears, you type what you want in plain English, and it just… does it."

What is LSD?ArchitectureStatusGetting StartedAdding ExtensionsWidget ConventionsEntity ResolutionAutomationsRoadmap


What is LSD?

LSD stands for Lexicon Shell Daemon — but in plain terms, it's a see-through layer that sits on top of your entire Linux desktop. Think of it like a HUD in a video game, except it's for your real computer.

Here's what that means in practice:

  1. You press a hotkey (like Super + `` ) and a transparent fullscreen window instantly appears over whatever you were doing — your browser, your code editor, everything stays visible underneath.
  2. You type in plain English into a bar at the bottom (the "Synapse Bar"): things like "clock", "timer 5m", "what's the date", "theme cyberpunk", or even shell commands like ls and git status.
  3. Floating glass widgets appear on the overlay — a clock, a timer, a sticky note, a system monitor — whatever you asked for.
  4. Press Escape and the whole thing vanishes. Zero CPU when hidden. Your desktop is untouched.

It's not a terminal emulator. It's not an app launcher. It's a daemon (a background process) that gives your desktop a programmable glass nervous system you can talk to in natural language.

The name is a triple meaning:

  • Lexicon Shell Daemon — what it literally is
  • LSD — because it puts a trippy transparent layer over your reality
  • It's also just a daemon (lexicond) — it runs silently in the background, always listening

Architecture

LSD is a multi-layer system with body-inspired naming:

Layer Name Tech Role
0 The Body Tauri + Bun + SvelteKit Transparent fullscreen window, Rust IPC, WebView rendering
0+ Organs Playwright ghost browser + DOM scraping + automation Real web apps (GitHub, WhatsApp, etc.) as headless tabs — scraped and automated, not embedded
1 The Brain Python + FastAPI + uv Rule-based grammar engine, WebSocket hub, extension loader, organ orchestration, automation executor
1+ The Shell Python PTY microservice Real pseudo-terminal sessions (zsh/bash), full interactive shell over WebSocket
2 The Spine ZeroMQ (pyzmq) PUSH/PULL + PUB event bus between all layers
3 The Memory SurrealDB (embedded) Persistent document storage — UI state, history, workspaces, scraped data, automations, themes
4 External Sensors CLI scripts, daemons System monitors, ad-hoc data pushers via Spine

Data Flow

Boot                  →  dev.sh starts Brain + Shell + Spine + Tauri client
                      →  Tauri window opens briefly (WebView boots, JS connects)
                      →  Svelte connects to WebSocket (ws://127.0.0.1:8000/ws)
                      →  Brain sends RESTORE_STATE (widgets) + active theme from Memory
                      →  Rust auto-hides the window after 2s (WebView stays alive)
                      →  LSD is now idle — zero CPU, no taskbar icon

User presses Super+`  →  lexicon-toggle PUSHes "lexicon/toggle" to Spine (:5557)
                      →  Spine dispatches to Brain handler
                      →  Brain broadcasts TOGGLE_VISIBILITY over WebSocket
                      →  Svelte calls invoke("toggle_window") → Rust IPC
                      →  Rust shows window + sets fullscreen + focuses
                      →  Saved widgets reappear instantly (already in memory)

User presses Escape   →  Svelte calls invoke("toggle_window") → Rust hides window
                      →  Window vanishes instantly, WebView stays connected

User types "clock"    →  Svelte sends { type: "query", text: "clock" } via WebSocket
                      →  Brain logs command to Memory, runs GrammarEngine
                      →  extensions/clock.py match() hits → action() returns RENDER_WIDGET
                      →  Sent back over WebSocket
                      →  Svelte looks up registry["clock"], renders <ClockWidget>
                      →  Widget appears at (x, y) with glass blur frame

User types "!ls"      →  Svelte detects shell prefix, sends shell_spawn + shell_input
                      →  Brain relays to Shell microservice (ws://127.0.0.1:8765)
                      →  Shell service spawns real PTY zsh session
                      →  Output streams back: Shell → Brain → WebSocket → xterm.js widget
                      →  Full-screen terminal widget with colors, scrollback, resize

User types            →  Svelte sends { type: "apply_theme", name: "cyberpunk" }
  "theme cyberpunk"   →  Brain looks up CSS from Memory (SurrealDB)
                      →  Broadcasts APPLY_THEME { css: "..." } to ALL connected clients
                      →  Svelte injects <style id="lexicon-theme"> into <head>
                      →  Every widget, bar, sidebar re-skins instantly via lx-* classes

User types "organs"   →  OrganManagerWidget spawns on canvas
                      →  Register any URL as an "organ" (e.g. github.com, web.whatsapp.com)
                      →  Brain's OrganManager opens a tab in a Playwright ghost browser
                      →  User pastes outer HTML of a page element → names it → scrapes
                      →  Playwright deep-scrapes all matching elements with field extraction
                      →  Structured data stored in Memory, viewable in DataViewWidget

User types            →  AutomationWidget spawns on canvas
  "automations"       →  Select an organ (must be running)
                      →  Build step sequences: click, scroll, type, wait, navigate, extract
                      →  Save automation → run it → watch step-by-step progress
                      →  Extracted data auto-stored in Memory, auto-resolved to entities
                      →  One-shot actions: click/type/scroll any element, take screenshots

Status

Current phase: All core layers functional — Body + Brain + Shell + Spine + Organs + Automations + Theming.

✅ Implemented

Component Status Details
Tauri shell (Layer 0) ✅ Complete Transparent, borderless, always-on-top, fullscreen. Boots visible (WebView boots + WebSocket connects), Rust auto-hides after 2s. Toggle via lexicon-toggle (ZeroMQ → Spine → Brain → WS → Svelte → Rust IPC). Escape hides. Builds to ~16MB release binary.
Svelte frontend (Layer 0) ✅ Complete SPA with static adapter, frost-glass overlay, Synapse Bar with command history (↑↓), feedback toasts, connection status dot, lx-* CSS anchor classes for theming.
Paged workspace (Layer 0) ✅ Complete Vertically scrolling canvas divided into pages by thin divider lines. Sidebar with page numbers for smooth scroll navigation. Auto-expands as content grows. Widgets freely span across dividers.
Widget system (Layer 0) ✅ Complete Dynamic render list driven by WebSocket. Absolute positioning at (x, y, w, h). Glass-blur frames, pop-in animation, per-widget dismiss. Pointer-based dragging via handle strip. Corner resize handle. All positions/sizes persist to Memory.
Widget registry (Layer 0) ✅ Complete src/lib/widgets/index.js — maps widget_type → Svelte component. 13 widgets: clock, timer, date, note, calculator, sysmon, weather, help, terminal, organmanager, dataview, person, automation.
Multi-session shell (Layer 0+1) ✅ Complete Full PTY shell via dedicated Shell microservice (:8765). Multiple concurrent sessions — each is a real zsh/bash PTY with colors, env persistence, interactive programs. Rendered in xterm.js TerminalWidgets on the canvas. Ctrl+C, resize, signals all work natively. Synapse Bar routes to active session or spawns new ones (Ctrl+`, Ctrl+Tab).
Workspaces (Layer 0+3) ✅ Complete Named workspaces in SurrealDB. ✦ logo → workspace menu: create, switch, delete. Each workspace has independent widgets, shell state. 🧹 clear button wipes canvas + DB. Auto-saves on switch, auto-restores on load.
WebSocket protocol (Layer 0↔1) ✅ Complete Auto-reconnect with exponential backoff (2s → 30s). Message types: RENDER_WIDGET, REMOVE_WIDGET, CLEAR_WIDGETS, CLEAR_SHELL, FEEDBACK, RESTORE_STATE, SHELL_SPAWNED, SHELL_OUTPUT, SHELL_EXITED, SHELL_ERROR, WORKSPACE_INFO, TOGGLE_VISIBILITY, ORGAN_STATUS, ORGAN_LIST, APPLY_THEME, THEME_LIST, THEME_INFO, AUTOMATION_PROGRESS.
FastAPI Brain (Layer 1) ✅ Complete WebSocket at /ws, health at /health, toggle at POST /toggle, system stats at /system. Organ CRUD: POST/GET/DELETE /organs, /organs/:id/launch, /organs/:id/kill, /organs/:id/match, /organs/:id/scrape, /organs/:id/rescrape, /organs/:id/data. Automation CRUD: POST/GET/DELETE /organs/:id/automations, /organs/:id/automations/:name/run. One-shot actions: /organs/:id/actions/{click,type,scroll,navigate,screenshot,eval,extract,paginate}. Entity endpoints: GET /entities, GET /entities/:id, GET /entities/search/:q, POST /entities/resolve, DELETE /entities, GET /entities/stats/summary. Connection manager with broadcast. CORS enabled. Workspace CRUD + theme CRUD over WebSocket.
Grammar engine (Layer 1) ✅ Complete Dynamically loads every .py from extensions/, runs match()action() pipeline. 15 extensions loaded. Fallback feedback for unknown commands. Help entries auto-collected.
Shell microservice (Layer 1+) ✅ Complete Standalone Python PTY server on :8765. Auto-detects user's default shell. Real PTY with TIOCSWINSZ resize, SIGHUP/SIGINT/SIGTSTP signals. Raw byte streaming. Multiple concurrent sessions.
Organ system (Layer 0+) ✅ Complete Generic organ framework — any URL can be an organ. Single headed Playwright Chromium browser (off-screen, persistent cookies). Organs are tabs. Deep structural scraping: paste outer HTML → tree parser discovers fields → CSS selector extraction → structured objects per match. 3-stage pipeline: similarity → structural validation → deduplication. OrganManagerWidget for CRUD. DataViewWidget for recursive layout rendering.
Automation engine (Layer 0+1) ✅ Complete Programmable browser automation — goes beyond static scraping. Build named step sequences: click, type, scroll, wait, navigate, extract, paginate, eval_js, screenshot, conditional, loop. Saved to Memory per organ. Run automations with step-by-step progress broadcast. One-shot actions for ad-hoc interaction. Paginate across multiple pages with auto-extraction. Extracted data auto-stored and auto-resolved to entity nodes. AutomationWidget for visual workflow building + execution.
Entity resolver (Layer 1+3) ✅ Complete Multi-strategy consensus identity resolution — zero external dependencies (except spaCy NER). Scraped data from any organ is automatically resolved into person-entity nodes. 5 voting strategies: fingerprint (phone/email exact), name similarity (Jaro-Winkler + Soundex + Double Metaphone), username correlation (cross-platform handle matching), token overlap (IDF-weighted + substring containment), contextual (avatar URL + phone digit matching). Only applicable strategies vote — absent signals don't dilute strong matches. Entities stored in SurrealDB with full source provenance.
Person widget (Layer 0) ✅ Complete PersonWidget — searchable grid of all resolved people, click-to-expand detail profiles with avatar, name, aliases, handles, contact info, source provenance. Built entirely from DataView meta node primitives. Full lx-person-* theme anchors. Search via "people", "person Rishi", "who is Mehta", "contacts".
Theming (Layer 0+3) ✅ Complete Full theme system with CSS injection. 4 built-in themes: cyberpunk, midnight, rose-pine, ember. Themes stored in SurrealDB Memory, auto-seeded from themes/*.css on boot. Apply via natural language ("theme cyberpunk"), WebSocket messages, or Spine channel (lexicon/theme). Active theme persists across restarts and broadcasts to all connected clients. Every UI element has lx-* anchor classes for granular styling. Reset to default with "reset theme".
SurrealDB Memory (Layer 3) ✅ Complete Embedded file-backed SurrealDB (surrealkv://). Persists: UI state (widgets), command history, shell sessions, named workspaces, organ registrations, scrape patterns, scraped data, automations, themes, active theme. All widget/shell data is workspace-scoped. Auto-restores on reconnect. No external server needed.
ZeroMQ Spine (Layer 2) ✅ Complete PUSH/PULL on :5557 + PUB on :5556. Channels: lexicon/toggle (show/hide), lexicon/theme (apply theme by name). External scripts PUSH commands → Brain dispatches → WebSocket broadcast. HTTP fallback at POST /toggle.
Dev tooling ✅ Complete dev.sh — menu-driven launcher (build / preview / dev mode). Starts Brain + Shell + Spine + Tauri. One command for everything. lexicon-toggle for hotkey binding.

Extensions

Extension Command Examples What it does
clock clock, time, what time is it Live-updating HH:MM:SS with gradient text
timer timer 5m, countdown 1h30m, set timer 30s Countdown with progress bar, pause/reset controls
date date, what day is it, today Weekday, date, year, day-of-year, week number, year-progress bar
note note buy groceries, remind me to call bob Sticky notes with click-to-edit
calculator calc 2+2, = pi * 2, math sqrt(144) Safe math eval with trig, log, constants
sysmon system, stats, cpu Live CPU/RAM/disk bars polling from /proc
weather weather, forecast Weather widget (demo mode, ready for API)
help help, commands, ? Auto-generated guide from all extensions
clear clear, dismiss all, close Wipe all widgets from canvas
organ organs, scrape, organ manager Opens the Organ Manager widget
view view github, dashboard, show data Data view — renders scraped organ data
theme theme cyberpunk, themes, reset theme Apply, list, or reset visual themes
person people, person Rishi, who is Mehta, contacts Person dashboard — resolved entity identity graph
automation automations, automate, crawl, workflow Programmable browser automation — build, save, run crawl sequences

🔲 Not Yet Implemented

Component Layer Notes
Scheduled Automations 1 Cron-like scheduling — run automations on a timer automatically.
More Organs 0+ Discord, Gmail, etc. — same Playwright tab + scrape pattern.
CLI event tool 4 lexicon push "meeting in 5min" from terminal via ZeroMQ PUSH to Spine.
SysMon daemon 4 Push system metrics on schedule via Spine.

Getting Started

Prerequisites

  • Linux (any desktop environment — GNOME, KDE, Hyprland, Sway, etc.)
  • Rust + Cargo
  • Bun
  • uv (Python package manager)
  • Python 3.13+

Setup

git clone https://github.com/vardhin/lexicon.git
cd lexicon

# Backend — install Python deps
cd lexicon-backend
uv sync
cd ..

# Shell microservice
cd lexicon-shell
uv sync
cd ..

# Frontend — install JS deps
cd lexicon-frontend
bun install
cd ..

Build & Run

./dev.sh

This will:

  1. Build the Svelte static site (bun run build)
  2. Build the Tauri release binary (bun run tauri build)
  3. Start the Brain (FastAPI :8000) + Shell microservice (:8765) + ZeroMQ Spine (:5557/:5556)
  4. Launch the Tauri client in the background (hidden until toggled)

Toggle the overlay

Bind lexicon-toggle to your preferred hotkey:

DE How to bind
GNOME Settings → Keyboard → Custom Shortcuts → Super+`` /path/to/lexicon/lexicon-toggle
KDE System Settings → Shortcuts → Custom Shortcuts → add lexicon-toggle
Hyprland bind = $mainMod, grave, exec, /path/to/lexicon/lexicon-toggle
Sway bindsym $mod+grave exec /path/to/lexicon/lexicon-toggle

Or toggle manually:

# Via ZeroMQ (instant, <5ms round-trip)
./lexicon-toggle

# Via HTTP (works from anywhere)
curl -X POST localhost:8000/toggle

Press Escape (with empty input) to hide the overlay.

How it works: lexicon-toggle PUSHes "lexicon/toggle" via ZeroMQ to the Spine (:5557). The Brain receives it, broadcasts TOGGLE_VISIBILITY over WebSocket to the Svelte frontend, which calls invoke("toggle_window") — a Rust IPC command that does the actual window.show() / window.hide(). This bypasses Wayland permission issues. The entire toggle round-trip is <5ms.


Theming

LSD ships with 4 built-in themes. Type themes to list them, theme <name> to apply:

Theme Vibe
cyberpunk Neon green on deep black, scanline overlay, terminal hacker aesthetic
midnight Deep navy blue with soft purple accents, calm and focused
rose-pine Warm muted tones — salmon, gold, teal from the Rosé Pine palette
ember Amber and orange on dark charcoal, warm and cozy
theme cyberpunk     ← apply a theme
themes              ← list all themes
reset theme         ← revert to default

Themes are stored in SurrealDB and persist across restarts. The active theme auto-restores on reconnect and broadcasts to all connected clients. You can also trigger themes externally via the Spine: push "lexicon/theme cyberpunk" to :5557.

Custom themes: drop a .css file in themes/ — it's auto-seeded on next boot. Target lx-* classes (lx-widget, lx-bar, lx-input, lx-sidebar, etc.) to style any element.


Adding Extensions

Each extension is a single Python file in extensions/ with a standard interface:

1. Create the backend logic

# extensions/timer.py
import re, uuid

def match(text):
    m = re.search(r"timer\s+(\d+)\s*(m|min|s|sec)?", text)
    if m:
        amount = int(m.group(1))
        unit = (m.group(2) or "s")[0]
        return amount * (60 if unit == "m" else 1)
    return None

def action(original_text, seconds):
    return {
        "type": "RENDER_WIDGET",
        "widget_id": f"timer-{uuid.uuid4().hex[:6]}",
        "widget_type": "timer",
        "x": 100, "y": 100, "w": 300, "h": 180,
        "props": {"duration_seconds": seconds},
    }

EXTENSION = {
    "name": "timer",
    "match": match,
    "action": action,
    "help": {
        "title": "Timer",
        "icon": "⏱",
        "description": "Set a countdown timer",
        "examples": ["timer 5m", "countdown 30s"],
    },
}

2. Create the frontend widget

<!-- lexicon-frontend/src/lib/widgets/TimerWidget.svelte -->
<script>
  export let props = {};
  export let onDismiss = () => {};
  // ... timer logic
</script>
<div class="timer-widget lx-timer">
  <!-- ... timer UI with lx-* classes for theming -->
</div>

3. Register it

// lexicon-frontend/src/lib/widgets/index.js
import TimerWidget from './TimerWidget.svelte';

const registry = {
  // ...
  timer: TimerWidget,  // ← add here
};

Restart the backend (it auto-reloads via uvicorn), rebuild the frontend (./dev.sh). Done.

Extensions can also return custom action types (not just RENDER_WIDGET) — the Brain's WebSocket handler intercepts them. See extensions/theme.py for an example that returns THEME_APPLY / THEME_RESET / THEME_LIST_REQUEST.


Widget Conventions

Every widget in LSD follows a strict set of conventions so that theming, layout, and composability work uniformly across the system.

Required exports

Every widget Svelte component must export exactly two props:

<script>
  export let props = {};      // Data/config from the backend (RENDER_WIDGET.props)
  export let onDismiss = () => {};  // Called when the user clicks the ✕ dismiss button
</script>

Root element structure

The outermost <div> must:

  1. Have a widget-specific CSS class: e.g., clock-widget, person-widget
  2. Have a lx-* theme anchor class: e.g., lx-clock, lx-person, lx-widget
  3. Fill its container: width: 100%; height: 100%;
  4. Include a dismiss button with class dismiss lx-dismiss
<div class="my-widget lx-mywidget lx-widget">
  <button class="dismiss lx-dismiss" on:click={onDismiss}>✕</button>
  <!-- widget content -->
</div>

Theme anchor classes (lx-*)

Every significant element should have an lx-* class so themes can target it. The convention:

Scope Class Pattern Example
Widget root lx-{widget} lx-clock, lx-person, lx-sysmon
Generic widget lx-widget All widgets
Dismiss button lx-dismiss close button
Label/header lx-label "CLOCK", "SYSTEM" section labels
Input fields lx-input Search bars, text inputs
Sub-elements lx-{widget}-{part} lx-person-header, lx-clock-time, lx-person-card

Themes target these via CSS:

/* themes/cyberpunk.css */
.lx-person-card { border-color: rgba(0, 255, 65, 0.2); }
.lx-person-name { color: #00ff41; }
.lx-dismiss:hover { color: #ff0040; }

Styling conventions

/* Standard glass widget styling */
.my-widget {
  position: relative; width: 100%; height: 100%;
  display: flex; flex-direction: column;
  color: rgba(255,255,255,0.92);
  font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
  padding: 10px 14px;
  box-sizing: border-box;
  overflow: hidden;
}

/* Standard dismiss button */
.dismiss {
  position: absolute; top: 6px; right: 10px;
  background: none; border: none;
  color: rgba(255,255,255,0.3); font-size: 14px;
  cursor: pointer; z-index: 10;
  padding: 2px 6px; border-radius: 4px;
}
.dismiss:hover { color: #ff5f57; background: rgba(255,95,87,0.12); }

Backend → Frontend contract

The backend action() returns a RENDER_WIDGET message:

{
    "type": "RENDER_WIDGET",
    "widget_id": "unique-id",
    "widget_type": "mywidget",          # Must match registry key in index.js
    "x": 100, "y": 100,
    "w": 400, "h": 300,
    "props": { ... },                   # Passed to the Svelte component as `props`
}

Checklist for new widgets

  • Backend extension in extensions/ with match(), action(), EXTENSION dict, and help entry
  • Frontend widget in src/lib/widgets/ with export let props + export let onDismiss
  • Root element has widget-specific class + lx-* theme anchor(s)
  • Dismiss button with lx-dismiss
  • Registered in src/lib/widgets/index.js
  • All interactive elements have lx-* classes for theme injection
  • Widget fills container (width: 100%; height: 100%)
  • Scrollable content areas use scrollbar-width: thin

Entity Resolution

LSD includes a built-in identity resolution engine that automatically merges scraped data from different organs (WhatsApp, GitHub, etc.) into unified person nodes.

How it works

When you scrape data from an organ (manually or via automation), the Brain's entity resolver automatically:

  1. Extracts identity signals from each scraped item — names, usernames, phone numbers, emails, avatar URLs (using spaCy NER for classification)
  2. Compares signals against all existing entity nodes using 5 independent voting strategies
  3. Merges or creates — if the consensus score exceeds the threshold, the item is merged into an existing entity; otherwise a new entity is created

The 5 voting strategies

Strategy Weight What it matches Example
Fingerprint 5.0 Exact phone/email match (deterministic) +91-9876543210 = +91 9876 543210 → auto-merge
Name Similarity 2.5 Jaro-Winkler + Soundex + Double Metaphone "Rishi Metha" ~ "Rishi Mehta" → 0.95
Username Match 2.0 Cross-platform handle correlation rishimehta04 ~ rishi_mehta → 0.90
Token Overlap 1.5 IDF-weighted Jaccard + substring containment "rishimehta" contains {"rishi", "mehta"}
Contextual 4.5 Same avatar URL, phone digit patterns Shared avatar → 0.85

The consensus engine only averages strategies that are applicable — if neither side has a phone number, the fingerprint strategy is excluded rather than dragging the score to zero.

Natural language commands

people              ← show all resolved person nodes
person Rishi        ← search for a specific person
who is Mehta        ← search by name
contacts            ← alias for people

Automations

LSD's automation engine goes beyond static scraping — it lets you dynamically crawl through Playwright tabs by executing programmable action sequences.

What are automations?

An automation is a named sequence of steps. Each step is an action that runs against an organ's live Playwright page. Steps execute in order, and extracted data is automatically stored and resolved into entity nodes.

Available step types

Step What it does Key params
click Click an element selector, button, count, wait_after
type Type text into an input selector, text, clear, press_enter, delay
scroll Scroll the page or element direction (down/up/bottom/top), amount, selector
wait Wait for a condition selector + state, or delay (ms), or network idle
navigate Go to a URL url (absolute or relative), wait_until
extract Scrape data from the page outer_html (full structural) or selector + attribute
paginate Click through pages, extracting each next_selector, extract, max_pages, stop_if_empty
eval_js Run arbitrary JavaScript js (must return a value)
screenshot Capture the page full_page, selector, quality
conditional Run sub-steps if selector exists selector, then, otherwise
loop Repeat sub-steps N times count, steps, stop_selector, stop_if_no_change

Example: Crawl GitHub trending repos

{
  "name": "github_trending",
  "description": "Scroll through GitHub trending and extract all repos",
  "steps": [
    { "type": "navigate", "url": "https://github.com/trending" },
    { "type": "wait", "delay": 2000 },
    { "type": "scroll", "direction": "bottom", "wait_after": 1500 },
    { "type": "extract", "selector": "article.Box-row h2 a", "attribute": "href" }
  ]
}

Example: Search and paginate

{
  "name": "search_python_repos",
  "steps": [
    { "type": "navigate", "url": "https://github.com/search?q=python&type=repositories" },
    { "type": "wait", "selector": "[data-testid='results-list']" },
    { "type": "paginate",
      "next_selector": "a.next_page",
      "extract": { "selector": "div.search-title a", "attribute": "textContent" },
      "max_pages": 3 }
  ]
}

Example: Infinite scroll extraction

{
  "name": "scroll_and_extract",
  "steps": [
    { "type": "loop", "count": 5, "stop_if_no_change": true, "steps": [
      { "type": "scroll", "direction": "down", "amount": 1200, "wait_after": 2000 },
      { "type": "extract", "selector": ".feed-item h3", "attribute": "textContent" }
    ]}
  ]
}

One-shot actions

For quick ad-hoc interactions without building a full automation:

Endpoint Method Description
/organs/{id}/actions/click POST Click an element
/organs/{id}/actions/type POST Type into an input
/organs/{id}/actions/scroll POST Scroll the page
/organs/{id}/actions/navigate POST Navigate to a URL
/organs/{id}/actions/screenshot POST Take a screenshot
/organs/{id}/actions/eval POST Evaluate JavaScript
/organs/{id}/actions/extract POST Extract data with a pattern
/organs/{id}/actions/paginate POST Paginate + extract

Natural language commands

automations         ← open the automation builder widget
automate            ← same
crawl               ← same
workflow            ← same

Project Structure

lexicon/
├── dev.sh                          # Menu-driven launcher (build / preview / dev)
├── lexicon-toggle                  # Toggle script — bind to your DE hotkey
├── lexicon-toggle.sh               # Alternative toggle script
│
├── extensions/                     # Backend extensions (Python, auto-loaded)
│   ├── automation.py               #   Automation manager widget trigger
│   ├── calculator.py               #   Inline math evaluator
│   ├── clear.py                    #   Clear all widgets
│   ├── clock.py                    #   Clock widget
│   ├── date.py                     #   Date display widget
│   ├── help.py                     #   Help guide (auto-collects from all extensions)
│   ├── note.py                     #   Sticky notes
│   ├── organ.py                    #   Organ Manager widget trigger
│   ├── person.py                   #   Person dashboard — entity identity graph
│   ├── sysmon.py                   #   System monitor widget
│   ├── theme.py                    #   Theme apply / list / reset
│   ├── timer.py                    #   Countdown timer widget
│   ├── view.py                     #   Data view / dashboard widget
│   └── weather.py                  #   Weather widget (demo)
│
├── themes/                         # Built-in themes (auto-seeded to SurrealDB)
│   ├── cyberpunk.css
│   ├── ember.css
│   ├── midnight.css
│   └── rose-pine.css
│
├── lexicon-backend/                # Layer 1: The Brain
│   ├── pyproject.toml
│   ├── run.sh
│   └── src/
│       ├── main.py                 #   FastAPI + WS + organ + automation + entity endpoints
│       ├── engine.py               #   Grammar engine (auto-loads extensions/)
│       ├── automation.py           #   Automation engine — programmable browser actions
│       ├── entity_resolver.py      #   Multi-strategy identity resolution (spaCy NER)
│       ├── memory.py               #   SurrealDB embedded memory (Layer 3)
│       ├── spine.py                #   ZeroMQ event bus (Layer 2)
│       ├── shell.py                #   Shell session manager
│       ├── organ_manager.py        #   Playwright ghost browser + deep structural scraping
│       └── connection_manager.py   #   WebSocket connection tracking + broadcast
│
├── lexicon-shell/                  # Layer 1+: Shell Microservice
│   ├── pyproject.toml
│   ├── run.sh
│   └── shell_server.py             #   PTY server on :8765
│
├── lexicon-frontend/               # Layer 0: The Body
│   ├── package.json
│   ├── src/
│   │   ├── app.html
│   │   ├── routes/+page.svelte
│   │   └── lib/
│   │       ├── ws.js               #   WebSocket client (auto-reconnect)
│   │       └── widgets/
│   │           ├── index.js            # Widget registry (13 widgets)
│   │           ├── AutomationWidget.svelte
│   │           ├── ClockWidget.svelte
│   │           ├── TimerWidget.svelte
│   │           ├── DateWidget.svelte
│   │           ├── NoteWidget.svelte
│   │           ├── CalculatorWidget.svelte
│   │           ├── SysMonWidget.svelte
│   │           ├── WeatherWidget.svelte
│   │           ├── HelpWidget.svelte
│   │           ├── TerminalWidget.svelte
│   │           ├── OrganManagerWidget.svelte
│   │           ├── DataViewWidget.svelte
│   │           └── PersonWidget.svelte
│   └── src-tauri/
│       ├── tauri.conf.json
│       └── src/
│           ├── main.rs
│           └── lib.rs
│
├── infra/
│   └── data/                       #   SurrealDB file store (auto-created)
│
└── architecture/                   # Architecture diagram (Mermaid)

Roadmap

  • SurrealDB Memory — persist UI state, command history, auto-restore on launch
  • Extensions — clock, timer, date, weather, notes, calculator, system monitor, help, clear, organ manager, data view, theme, person, automation
  • Widget dragging + resizing — pointer-based repositioning, corner resize, persisted
  • Paged workspace — scrollable multi-page canvas with sidebar navigation
  • Multi-session shell — real PTY sessions via Shell microservice, xterm.js rendering, multiple terminals
  • ZeroMQ Spine — PUSH/PULL + PUB event bus, lexicon-toggle, lexicon/theme channels
  • Named workspaces — create, switch, delete workspaces with independent state
  • Generic organ system — any URL as a Playwright ghost browser tab, deep structural HTML scraping, pattern matching, field extraction
  • Theming — 4 built-in themes, SurrealDB persistence, lx-* CSS anchors, Spine channel, natural language control
  • Entity resolver — multi-strategy consensus identity resolution (spaCy NER), auto-resolves scraped data into person nodes, PersonWidget dashboard
  • Automation engine — programmable browser automation: click, scroll, type, wait, navigate, extract, paginate, eval, conditional, loop. Saved workflows per organ. One-shot actions. Auto-entity-resolution on extracted data
  • Scheduled automations — cron-like scheduling for automations to run on a timer
  • More Organs — Discord, Gmail, etc.
  • CLI event toollexicon push "reminder text" from terminal via Spine
  • SysMon daemon — push system metrics on schedule via Spine

License

MIT


Built by @vardhin

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors