ego (lite) ist nur ein Browser, ego ist Ihr persönlicher Agent für alle Geräte.
Zur Warteliste anmelden
Deutsch

ego-browser

Die Browser-Automatisierungslaufzeit, die KI-Agenten verwenden, um die echte Chromium-Sitzung von ego (lite) zu steuern.

llms.txt

ego-browser ist die Browser-Automatisierungslaufzeit, die ego (lite) für KI-Agenten ausliefert. Es kommuniziert über das Chrome DevTools Protocol mit der echten Chromium-Sitzung innerhalb von ego (lite) und verwendet ein Node.js-Heredoc-Skript als Einstiegspunkt: Der KI-Agent schreibt den gesamten JS-Ablauf in einer einzigen stdin-Übergabe, alle Helper sind bereits in den Skript-Scope eingefügt und der Browserstatus bleibt innerhalb eines Space bestehen.

ego-browser ist nicht für die manuelle Browsersteuerung durch Menschen gedacht und ersetzt weder Playwright noch Puppeteer. Die Zielgruppe sind LLM-Agenten.

Für wen es ist

  • KI-Coding-Agenten, die einen Browser steuern müssen: Claude Code, Codex, Cursor und benutzerdefinierte SDK-Agenten.
  • Teams, die vertikale KI-Agenten entwickeln und Lark, Google Docs, Salesforce oder ähnliche Backoffices automatisieren.
  • Wiederholte feste Webabläufe: Anmelden, Ausfüllen, Exportieren, Suchen, Tabellen lesen.
  • Jeder, der versucht hat, ein vollständiges DOM oder eine HTML-Seite in ein LLM zu stopfen und dabei an die Token-Wall stößt.

Installieren

Im Lieferumfang ist ego (lite) enthalten – siehe Schnellstart. Führen Sie nach der Installation ego-browser in einem beliebigen Verzeichnis aus.

Sie können den Skill auch eigenständig installieren:

npx skills add github:CitroLabs/ego-lite/skills/ego-browser

Kernschleife

Der typische Rhythmus für KI-Agenten, die eine Seite steuern – alles in einem einzigen Heredoc:

ego-browser nodejs <<'EOF'
const task = await useOrCreateTaskSpace('GitHub-Issues durchsuchen')

await openOrReuseTab('https://github.com/issues', { wait: true, timeout: 20 })

cliLog(await snapshotText())

EOF
  1. Einen Task Space wiederverwenden oder erstellen (deklarieren Sie ihn in jedem Heredoc – siehe Space).
  2. Öffnen Sie die Zielseite.
  3. Lesen Sie den Snapshot (snapshotText()), um einen semantischen Baum mit [ref=N, loc=..., url=...] zu erhalten.
  4. Handeln Sie auf der Seite durch @N ref oder CSS-Selektor.
  5. Drucken Sie das Endergebnis mit cliLog(...) aus.

Im Heredoc befinden Sie sich in einem Node.js-Prozess; Innerhalb von js(...) befinden Sie sich im Seitenkontext. Mischen Sie sie nicht.

Helfer-Referenz

Jeder Helfer ist im Gültigkeitsbereich des Skripts über seinen CamelCase-Namen verfügbar. Kein import erforderlich.

Task Space

await listTaskSpaces()
const task = await useOrCreateTaskSpace('Aufgabe beschreiben')   // wiederverwenden oder erstellen
await completeTaskSpace(task.name)                         // erledigt; Tab geöffnet lassen
await closeTaskSpace(task.name)                            // Space schließen

name sollte eine aus 3 bis 6 Wörtern bestehende Beschreibung der Aufgabe in natürlicher Sprache sein. Verwenden Sie keine Platzhalter.

await listTabs()
await openOrReuseTab(url, { wait: true, timeout: 20 })
await gotoAndWait(url, { timeout: 20, settle: 1 })
await newTab(url)
await switchTab(tabId)
await currentTab()
await pageInfo()
await ensureRealTab()        // ein neuer Task Space hat möglicherweise noch keinen Tab

Beobachtung

await snapshotText()                              // semantischer Snapshot der ganzen Seite (Standard)
await snapshotText({ scope: 'only_within_viewport' })
await captureScreenshot('result.png')
await drainEvents()                               // Warteschlange der Navigations- und Netzwerkereignisse leeren

Maus und Scrollen

click, doubleClick, hover und dragMouse akzeptieren dasselbe Zielformat (CSS-Pixel):

  • 'string': CSS-Selektor oder @ref. Klickt auf die Elementmitte.
  • [x, y] oder {x, y}: Ansichtsfensterkoordinaten.
  • {selector, x, y}: relativer Versatz von der oberen linken Ecke des Elements.
  • options.label: Beschreibung mit 3 bis 6 Wörtern. Wenn Sie sie übergeben, hebt die Aktion das Zielelement visuell hervor.
await click('@21', { label: 'Anmeldestatus prüfen' })
await click('button.primary', { label: 'Senden-Schaltfläche anklicken' })
await click([420, 260])
await hover('@5', { label: 'Menü durch Hover einblenden' })
await dragMouse([from, to], { label: 'Karte ziehen' })

await scrollBy(900)
await scroll({ dy: 900 })
await scrollToBottomUntil(
  async () => await js(String.raw`document.querySelectorAll('article').length`) >= 20,
  { step: 900, wait: 1, maxSteps: 20 },
)

Tastatur und Eingabe

await typeText('hello world')
await fillInput('@2', 'user@test.com')
await pressKey('Enter')
await dispatchKey({ ... })

Dateien und Netzwerk

await uploadFile('input[type="file"]', '/absolute/path/to/file.pdf')
await httpGet('https://api.example.com/data')   // GET-Anfrage im Seitenkontext

Warten

await wait(1)                                    // Sekunden
await waitForLoad()
await waitForElement('@1')
await waitForNetworkIdle()

wait() und timeout werden in Sekunden angegeben. Nur Parameter, die mit Ms enden, sind Millisekunden.

Browserausführung

js(source) ist Runtime.evaluate unter der Haube und nimmt einen String. Übergeben Sie ihm keine Funktion und Argumente wie Puppeteer – das erzeugt eine Warnung, wird in .toString() eingeschlossen und die Abschlussvariablen und der Argumentkanal verschwinden beide.

Für eine mehrstufige Logik packen Sie sie in ein IIFE ein, das einmal zurückgibt:

const data = await js(String.raw`(() => {
  const items = [...document.querySelectorAll('article')]
  return items.map(el => ({
    text: el.innerText,
    links: [...el.querySelectorAll('a')].map(a => a.href),
  }))
})()`)

await elementEval('@1', el => el.getBoundingClientRect())
await cdp('Page.captureScreenshot', { format: 'png' })

Ausgabe und Selbstfindung

cliLog(value)                  // einziger Ausgabekanal in einem Heredoc
cliLog(help('click'))          // Verwendung eines Helpers nachschlagen

Empfohlener Arbeitsablauf

Beginnen Sie mit snapshotText plus ref / loc – dadurch bleibt die Semantik intakt und die Sprödigkeit der Koordinaten wird vermieden:

  1. Verwenden Sie den Task Space wieder oder erstellen Sie einen neuen.
  2. Öffnen oder wechseln Sie zur Seite (openOrReuseTab / gotoAndWait).
  3. snapshotText(), um den [ref=N, loc=..., url=...]-Baum zu erhalten. Refs werden automatisch in der refMap registriert.
  4. Reagieren Sie auf @N mit click / fillInput / elementEval oder führen Sie eine einmalige DOM-Extraktion innerhalb von js(...) durch.
  5. cliLog(...) das Endergebnis.

Weitere nützliche Wege zum Kombinieren:

  • captureScreenshot + click([x, y]): visuelle Layouts, Canvas-gesteuerte Benutzeroberflächen, virtuelle Listen, Seiten mit unvollständiger Barrierefreiheit.
  • js / elementEval / cdp: DOM direkt extrahieren, Browserstatus überprüfen oder alles, was nicht sauber in einen Standardhelfer passt.

Bewahren Sie Navigation, Beobachtung, Scrollen, Extraktion, Filterung, Aggregation und Ausgabe in einem einzigen ego-browser nodejs-Heredoc auf. Leiten Sie die Daten nicht über ein zweites lokales node-Skript weiter.

Ref-Bereich

@N ist nur für die refMap des aktuellsten snapshotText gültig. Jeder snapshotText() erstellt die refMap neu. Ref-Nummern stammen aus dem CDP backendNodeId des Elements, sodass dasselbe Element in der Regel über alle Snapshots hinweg dieselbe Nummer trägt – damit @N jedoch funktionsfähig ist, muss N in der neuesten Snapshot-Ausgabe erscheinen.

Häufige Ursachen für Unknown ref:

  • Das Element wurde aus dem Ansichtsfenster gescrollt.
  • Das DOM wurde neu gerendert.
  • In einer vorherigen Runde wurde scope: 'only_within_viewport' verwendet und in der nächsten Runde wurde das Element nicht abgedeckt.

Wenn Sie über mehrere Runden hinweg einen stabilen Verweis auf dasselbe Element benötigen, verwenden Sie den Selektor loc=... aus dem Snapshot oder schreiben Sie direkt einen CSS-Selektor. Dies ist auch die Grundlage für gesammelte Erfahrung – siehe Skills.

Arbeitsbereich des Skills

ego-browser verwaltet nicht selbstständig die veränderbare Experience eines KI-Agenten. Standardmäßig lädt es Helper-Erweiterungen und erlernte Website-Experience aus dem Skill-Bundle des Repositories:

../../skills/ego-browser

Überschreiben über env var:

EGO_BROWSER_AGENT_WORKSPACE=/path/to/ego-browser ego-browser nodejs <<'EOF'
cliLog(await siteSkills())
EOF

Die Website-Experience unter learnings/ ist immer aktiv; jeder Helper-Aufruf liest sie. Das Schreib- und Erkennungsmodell für Experience wird unter Skills beschrieben.

Gelernte Erfahrung validieren:

npm run validate:learnings

Verzeichnislayout

package/ego-browser/
├── src/                      # browser-runtime / helpers / run.js
│   ├── browser-runtime.js    # ego runtime bridge on the browser side
│   ├── helpers.js            # helpers exposed to the agent script
│   ├── run.js                # CLI entry point (executes stdin)
│   └── learning/             # experience index, domain check, format check
├── artifacts/ego-browser/    # build output; npm bin points here
└── test/                     # unit tests

skills/ego-browser/
├── SKILL.md / SKILL.zh.md    # entry point for the agent
└── learnings/                # site experience directory

Notizen

  • snapshotText() ist standardmäßig scope: 'full_page'. Übergeben Sie 'only_within_viewport' nur, wenn Sie wirklich nur den sichtbaren Bereich benötigen.
  • js() gibt das Auswertungsergebnis direkt zurück. Wenden Sie darauf nicht erneut JSON.parse(...) an.
  • Wenn Sie einen regulären Ausdruck in eine js()-Vorlagenzeichenfolge schreiben, verdoppeln Sie die Backslashes (\\d, \\s) oder wechseln Sie zu String.raw.
  • Ein return der obersten Ebene wird automatisch in ein IIFE eingeschlossen. Ein return innerhalb eines verschachtelten Rückrufs kann dies ebenfalls auslösen. Schreiben Sie daher komplexe Ausdrücke im Voraus als (() => { ... })().
  • Wenn der Benutzer explizit nach ego-browser gefragt hat, ist die Laufzeit bereit. Führen Sie keinen Preflight mit which ego-browser / node -v / einem Hilfe-Dump durch – tun Sie dies nur, wenn bei der ersten Ausführung tatsächlich ein Fehler auftritt.