ego (lite) is just a browser, ego is your personal agent across devices.
Join waitlist
हिन्दी

ego-browser

AI agents के लिए browser automation runtime, जो ego lite के असली Chromium session को चलाता है।

llms.txt

ego-browser, ego lite द्वारा AI agents के लिए दिया गया browser automation runtime है। यह Chrome DevTools Protocol के ज़रिए ego lite के असली Chromium session से जुड़ता है, और entry point के तौर पर Node.js heredoc script लेता है: agent एक ही stdin delivery में पूरा JS flow लिखता है, सभी helpers पहले से script के scope में inject रहते हैं, और browser का state Space में बना रहता है।

ego-browser का मक़सद यह नहीं है कि कोई इंसान browser को हाथ से चलाए, और यह Playwright या Puppeteer का विकल्प भी नहीं है। इसका पाठक LLM agent है।

किसके लिए है

  • ऐसे AI coding agents के लिए जिन्हें browser चलाना है: Claude Code, Codex, Cursor, custom SDK agents।
  • वर्टिकल agents बनाने वाली टीमें: Lark, Google Docs, Salesforce जैसे back-offices को automate करने वाले।
  • दोहराव वाले web flows: login, form filling, export, search, table reading।
  • वे लोग जिन्होंने कभी पूरा DOM या पूरा HTML page LLM में डाला और token limit से टकराए।

Install करें

ego lite के साथ ही आता है—देखें त्वरित आरंभ। Install के बाद आप किसी भी directory में ego-browser कमांड चला सकते हैं।

Skill अकेले भी install हो सकती है:

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

मुख्य loop

Agent द्वारा page चलाने का सामान्य ढाँचा—सब कुछ एक ही heredoc में:

ego-browser nodejs <<'EOF'
const task = await useOrCreateTaskSpace('search github issues')

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

cliLog(await snapshotText())

EOF
  1. Task Space reuse करें या नया बनाएँ (हर heredoc में ज़रूरी—देखें Space)।
  2. लक्ष्य page खोलें।
  3. Snapshot पढ़ें (snapshotText()) और [ref=N, loc=..., url=...] वाला semantic tree पाएँ।
  4. @N ref या CSS selector से page पर action करें।
  5. cliLog(...) से अंतिम परिणाम print करें।

Heredoc के अंदर आप Node.js process में हैं; js(...) के अंदर ही browser page context में हैं। इन दोनों को न मिलाएँ।

Helper reference

सभी helpers script के scope में camelCase नाम से उपलब्ध हैं, import की ज़रूरत नहीं।

Task Space

await listTaskSpaces()
const task = await useOrCreateTaskSpace('describe task')   // reuse करें या बनाएँ
await completeTaskSpace(task.name)                         // पूरा हुआ, tab रहने दें
await closeTaskSpace(task.name)                            // अब ज़रूरत नहीं, space बंद करें

name को 3–6 शब्दों में, सामान्य भाषा में task describe करें। Placeholder न इस्तेमाल करें।

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()        // नया task space तब बना हो जब tab अभी न हो

Observation

await snapshotText()                              // पूरी page का semantic snapshot (default)
await snapshotText({ scope: 'only_within_viewport' })
await captureScreenshot('result.png')
await drainEvents()                               // navigation / network events queue clear करें

Mouse और scroll

click / doubleClick / hover / dragMouse एक ही target format (CSS pixels) लेते हैं:

  • 'string': CSS selector या @ref। Element के बीच में click करता है।
  • [x, y] या {x, y}: viewport coordinates।
  • {selector, x, y}: element के top-left से relative offset।
  • options.label: 3–6 शब्दों का description; देने पर visual highlight animation चलती है।
await click('@21', { label: 'login state देखें' })
await click('button.primary', { label: 'Submit button पर click करें' })
await click([420, 260])
await hover('@5', { label: 'menu पर hover करें' })
await dragMouse([from, to], { label: 'card को drag करें' })

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 },
)

Keyboard और input

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

Files और network

await uploadFile('input[type="file"]', '/absolute/path/to/file.pdf')
await httpGet('https://api.example.com/data')   // page context से किया गया GET

Wait करना

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

wait() और timeout seconds में हैं। केवल Ms से खत्म होने वाले parameters milliseconds में हैं।

Browser में execute

js(source) असल में Runtime.evaluate है और string लेता है। Puppeteer की तरह function + arguments मत भेजें—warning आती है, सब .toString() में लिपट जाता है, closure variables और arguments channel दोनों खो जाते हैं।

Multi-step logic को एक ही IIFE में लपेटें और एक बार return करें:

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' })

Output और self-discovery

cliLog(value)                  // heredoc में output का एकमात्र चैनल
cliLog(help('click'))          // किसी helper का इस्तेमाल देखें

अनुशंसित workflow

पहले snapshotText + ref / loc से शुरू करें—यह semantic structure बनाए रखता है और coordinates की नज़ाक़त से बचाता है:

  1. Task Space reuse करें या नया बनाएँ।
  2. Page खोलें या switch करें (openOrReuseTab / gotoAndWait)।
  3. snapshotText() से [ref=N, loc=..., url=...] tree लें। Refs अपने आप refMap में register हो जाते हैं।
  4. @N के साथ click / fillInput / elementEval use करें, या js(...) के अंदर एक बार में DOM extract कर लें।
  5. cliLog(...) से अंतिम result print करें।

मिलाने योग्य अन्य रास्ते:

  • captureScreenshot + click([x, y]): visual layouts, canvas UIs, virtual lists, अधूरी accessibility वाले pages।
  • js / elementEval / cdp: सीधे DOM extract करना, browser state देखना, या जब standard helper काफ़ी न हो।

Navigation, observation, scrolling, extraction, filtering, aggregation और output—सब एक ही ego-browser nodejs heredoc में रखें। उसी data के लिए दूसरा local node script न चलाएँ।

Ref का दायरा

@N केवल नवीनतम snapshotText के refMap के लिए valid है। हर snapshotText() refMap नए सिरे से बनाता है। Ref numbers element के CDP backendNodeId से आते हैं, इसलिए वही element अक्सर कई snapshots में एक ही number रखता है—लेकिन @N operate करने के लिए N का नवीनतम snapshot output में होना ज़रूरी है।

Unknown ref के सामान्य कारण:

  • Element viewport से बाहर चला गया।
  • DOM फिर से render हुआ।
  • पिछली बार scope: 'only_within_viewport' था और इस बार वह element cover नहीं हुआ।

कई rounds तक एक ही element को स्थिर रूप से refer करना हो, तो snapshot output के loc=... को stable selector की तरह उपयोग करें या सीधा CSS selector लिखें। यही Experience संचय का आधार भी है (देखें Skills)।

Skill workspace

ego-browser खुद कोई परिवर्तनशील agent experience नहीं रखता। Default में यह repo के skill bundle से helper extensions और सीखे हुए site experience load करता है:

../../skills/ego-browser

Environment variable से override करें:

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

learnings/ के अंदर का site experience हमेशा सक्रिय रहता है; हर helper call पर पढ़ा जाता है। Experience के लिखने और खोजने का तरीक़ा Skills में है।

सीखी हुई experience verify करें:

npm run validate:learnings

Directory structure

package/ego-browser/
├── src/                      # browser-runtime / helpers / run.js
│   ├── browser-runtime.js    # browser side का ego runtime bridge
│   ├── helpers.js            # agent script को दिखाई जाने वाली helpers
│   ├── run.js                # CLI entry (stdin execute करता है)
│   └── learning/             # experience index, domain validation, format validation
├── artifacts/ego-browser/    # build artifacts; npm bin यहाँ इशारा करता है
└── test/                     # unit tests

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

ध्यान देने योग्य बातें

  • snapshotText() का default scope: 'full_page' है (पूरा page)। केवल visible area चाहिए हो तभी 'only_within_viewport' पास करें।
  • js() expression का सीधा result लौटाता है; इस पर फिर से JSON.parse(...) न करें।
  • js() की template string में regex लिखते समय backslash double करें (\\d, \\s), या String.raw use करें।
  • Top-level return अपने आप IIFE में लिप्त हो जाता है। Nested callback में लिखा return भी यही trigger कर सकता है, इसलिए complex expressions शुरू से ही (() => { ... })() के रूप में लिखें।
  • जब user ने स्पष्ट रूप से ego-browser माँगा है, runtime पहले से तैयार है। पहली बार run में error आने तक which ego-browser / node -v / help dump न चलाएँ।