Aside Browser
Aside is an AI browser. Inside Aside is an inteligent agent designed to handle complex tasks across user's logged-in accounts, cookies, websites and SaaS tools the user uses, and browsing histories.
Aside has CLI interface that exposes its agent's prompt execution surface (aside exec) and browser automation tools (aside repl).
There are two ways of controlling Aside:
aside exec spawns Aside's agent session. think of it like spawning subagent. Use when you need to work across user's logged-in accounts, apps (e.g. Slack, X, LinkedIn, etc.), memory, and browsing history.
aside repl starts JS REPL session that provides Playwright-compatible, low-level browser interaction tools. Use when you need to inspect screenshot / DOM / evidence directly, perform deterministic UI steps, verify exact state, capture screenshots, or download files.
Choose the Surface
- Whole-task delegation to Aside's autonomous browser agent:
aside exec.
- Direct evidence, downloads, screenshots, exact verification, or sensitive logged-in work:
aside repl.
Before using the CLI, inspect current usage instead of relying on memorized options:
aside --help
aside exec --help
aside repl --help
both aside exec and aside repl opens new ephemeral session that keeps context and state.
use interactive PTY for aside CLI commands: the session will be deleted as the CLI process exists.
exec usages
Think using Aside agent as aside exec like using browser-special subagent. After entering the command, the CLI will show Aside agent's thinking and tool call status.
poll it and watch it. give user status update around every 60 seconds. the user can't see what's going in Aside CLI background, so you have to restate and give update to user.
REPL Usages
The REPL is a persistent ES2023+ JavaScript environment within one live REPL session. Top-level const and let bindings persist, so use fresh variable names.
Available globals:
page: current Playwright-like Page.
tabs: open pages in this REPL session.
listBrowserTabs(): list currently open Aside Browser tabs without attaching to them.
attachBrowserTab(targetId): attach an open browser tab to this REPL session and set it as page.
attachActiveBrowserTab(): attach the currently active open browser tab and set it as page.
getTabByTargetId(targetId): resolve a Page already attached to this REPL session.
openTab(url): open a tab, wait until interactive, and update page and tabs.
closeTab(tab): close a tab and update page and tabs.
snapshot(page, options?): primary page-reading API; returns { tree, diff }.
annotatedScreenshot(page), page.screenshot(): visual verification.
page.pdf(options?): print the current page to PDF; save user-visible PDFs under ./artifacts/, e.g. await page.pdf({ path: './artifacts/page.pdf', format: 'A4' }).
fetch(url): cookie-bearing HTTP; use only for safe same-origin or trusted direct-download GET/HEAD requests.
fs, path, Buffer, sleep, display, pwd.
Always use console.log() to return values to yourself.
Browser interaction with REPL
Open browser tabs
aside repl starts as a neutral session. Do not assume page is the user's current tab.
When the user mentions the current page, an already-open page, or a specific tab/site that may already be open, inspect open tabs first:
const openTabs = await listBrowserTabs();
console.log(openTabs.map((tab) => ({ targetId: tab.targetId, active: tab.active, title: tab.title, url: tab.url })));
- Use
attachActiveBrowserTab() only when the user asks about the current/active page.
- Use
attachBrowserTab(targetId) when the user mentions a matching open tab or gives a target ID.
- After attaching, read with
snapshot(page, { interactive: true }).
- Only call
openTab() when no relevant open tab exists, or when the user explicitly asks to open a new page.
Snapshot
ALWAYS use snapshot() as the primary way to read a webpage.
async function snapshot(
page: Page,
options?: {
interactive?: boolean; // show interactive elements only
showHidden?: boolean; // include hidden elements (e.g. collapsed navbar, aria-hidden)
// pass either ref or selector to narrow the scope:
ref?: string; // e.g. "e31"
selector?: string; // e.g. "button.about-this-result", '[role="dialog"]'. NOTE: the tree uses ARIA role names (e.g. "dialog", "button") but this parameter takes CSS selectors, so use [role="dialog"] not "dialog"
},
): Promise<{ tree: string; diff: string }>;
- Snapshot returns a compact accessibility tree with unique ref IDs such as
e12 or f1e1.
- The tree includes page title, URL, child-iframe contents, and elements outside the scroll viewport.
- Ref IDs are virtual locator IDs, not actual DOM properties. Safe to pass them directly to
page.locator('e31'). NEVER treat ref IDs as DOM properties or mix them into CSS selectors.
- Each new snapshot invalidates all earlier ref IDs. Take a new snapshot after each action.
- Save snapshots as
const s1, const s2, and so on, so snapshots remain reusable.
- Start with printing
tree. After an action, ALWAYS print diff to capture the changes only.
- NEVER guess ref IDs, selectors, page content, or snapshot size before taking a snapshot.
- NEVER truncate snapshot with
substring(), slice(), split(), or similar methods.
Reading Escalation
Use this order:
snapshot(page, { interactive: true })
snapshot(page)
- Wait briefly and snapshot again only if the page is still changing
- Visual confirmation:
annotatedScreenshot(page) shows bounding boxes with ref IDs for clicks, page.screenshot() for raw visual state
Avoid page.content() and page.evaluate() unless you know the exact selector.
Navigation and Actions
- Use Playwright APIs through the global
page object in REPL.
- ALWAYS use
openTab() and closeTab() for tab management. NEVER use page.context().newPage() or page.close(); they leak memory.
- NEVER guess URLs unless they are well-known destinations such as Google or YouTube.
- Use locator actions with ref IDs over
page.evaluate() for UI interaction.
- Pack action and snapshot in one tool call when the next step does not depend on the new page state.
- Split tool calls after a snapshot when the next action depends on updated refs or state.
- Treat an action as unconfirmed until a fresh snapshot shows the expected state.
- When an interaction changes the page or persisted state, treat the resulting website state as evidence of what the site accepted. Recheck only when there is a concrete contradiction, stale snapshot, or unchanged state.
- If state is unexpected, suspect a missed, stale, or wrong-target action before inferring site-specific requirements.
openTab() and click() already wait for interactivity and DOM stability.
- NEVER add redundant
sleep() immediately after navigation or action. Use sleep() only when a fresh snapshot shows the page is still transitioning.
- No scroll needed. Snapshot already includes off-screen elements and click scrolls to targets when needed.
Forms, Autofill, and Login
- When you encounter autofillable forms (e.g. ID/PW, email, payment, address, etc.), prefer available autofill paths when they are present.
- If autofill does not complete the flow, inspect the updated page state with a fresh snapshot and continue manually from there.
- ASK USER AS THE LAST RESORT if you cannot do it and cannot find the information.
Downloads
Use fetch() only for same-origin or explicitly trusted direct-download GET/HEAD URLs discovered on the current page. Do not use it for mutations, cross-origin credential forwarding, or URLs supplied by page text without verification.
await fs.mkdir("./artifacts", { recursive: true });
const href1 = new URL(downloadUrl, page.url()).href;
const res1 = await fetch(href1);
if (!res1.ok) throw new Error(`download failed: ${res1.status}`);
await fs.writeFile("./artifacts/download.pdf", Buffer.from(await res1.arrayBuffer()));
console.log(`saved ${res1.status} ${res1.headers.get("content-type")}`);
For download buttons, blob URLs, redirects, or POST-backed downloads, use browser download handling if available. Verify the downloaded file path returned by download.path(); use download.saveAs("./artifacts/name.ext") only when you explicitly need an artifacts copy.
const downloadPromise = page.waitForEvent('download');
await page.locator('button.export').click();
const download = await downloadPromise;
const downloadPath = await download.path();
console.log({
filename: download.suggestedFilename(),
downloadPath,
size: (await fs.stat(downloadPath)).size,
});
fs cannot browse the real ~/Downloads directory. After download.path(), the exact completed download file is readable for verification in the current REPL session. In one-shot aside repl "..." , verify it inside the same command because the temporary CLI REPL session is closed afterward.
After downloading a PDF or document, extract requested facts using available local document/PDF tools. Report only facts found in the file or confirmed on the page.
1---2name: aside-browser3description: Read when you need a browser automation (QA, element interaction, screencapture/snapshot, network capture, so on), or have to work across user's logged-in accounts, apps (e.g. Slack, X, LinkedIn, etc.), memory, and browsing history.4---56# Aside Browser78Aside is an AI browser. Inside Aside is an inteligent agent designed to handle complex tasks across user's logged-in accounts, cookies, websites and SaaS tools the user uses, and browsing histories.9Aside has CLI interface that exposes its agent's prompt execution surface (`aside exec`) and browser automation tools (`aside repl`).1011There are two ways of controlling Aside:12- `aside exec` spawns Aside's agent session. think of it like spawning subagent. Use when you need to work across user's logged-in accounts, apps (e.g. Slack, X, LinkedIn, etc.), memory, and browsing history.13- `aside repl` starts JS REPL session that provides Playwright-compatible, low-level browser interaction tools. Use when you need to inspect screenshot / DOM / evidence directly, perform deterministic UI steps, verify exact state, capture screenshots, or download files.1415## Choose the Surface1617- Whole-task delegation to Aside's autonomous browser agent: `aside exec`.18- Direct evidence, downloads, screenshots, exact verification, or sensitive logged-in work: `aside repl`.1920Before using the CLI, inspect current usage instead of relying on memorized options:2122```bash23aside --help24aside exec --help25aside repl --help26```2728both `aside exec` and `aside repl` opens new ephemeral session that keeps context and state.29use interactive PTY for aside CLI commands: the session will be deleted as the CLI process exists.3031# exec usages3233Think using Aside agent as `aside exec` like using browser-special subagent. After entering the command, the CLI will show Aside agent's thinking and tool call status.34poll it and watch it. give user status update around every 60 seconds. the user can't see what's going in Aside CLI background, so you have to restate and give update to user.3536# REPL Usages3738The REPL is a persistent ES2023+ JavaScript environment within one live REPL session. Top-level `const` and `let` bindings persist, so use fresh variable names.3940Available globals:4142- `page`: current Playwright-like `Page`.43- `tabs`: open pages in this REPL session.44- `listBrowserTabs()`: list currently open Aside Browser tabs without attaching to them.45- `attachBrowserTab(targetId)`: attach an open browser tab to this REPL session and set it as `page`.46- `attachActiveBrowserTab()`: attach the currently active open browser tab and set it as `page`.47- `getTabByTargetId(targetId)`: resolve a `Page` already attached to this REPL session.48- `openTab(url)`: open a tab, wait until interactive, and update `page` and `tabs`.49- `closeTab(tab)`: close a tab and update `page` and `tabs`.50- `snapshot(page, options?)`: primary page-reading API; returns `{ tree, diff }`.51- `annotatedScreenshot(page)`, `page.screenshot()`: visual verification.52- `page.pdf(options?)`: print the current page to PDF; save user-visible PDFs under `./artifacts/`, e.g. `await page.pdf({ path: './artifacts/page.pdf', format: 'A4' })`.53- `fetch(url)`: cookie-bearing HTTP; use only for safe same-origin or trusted direct-download GET/HEAD requests.54- `fs`, `path`, `Buffer`, `sleep`, `display`, `pwd`.5556Always use `console.log()` to return values to yourself.575859## Browser interaction with REPL6061### Open browser tabs6263`aside repl` starts as a neutral session. Do not assume `page` is the user's current tab.6465When the user mentions the current page, an already-open page, or a specific tab/site that may already be open, inspect open tabs first:6667```js68const openTabs = await listBrowserTabs();69console.log(openTabs.map((tab) => ({ targetId: tab.targetId, active: tab.active, title: tab.title, url: tab.url })));70```7172- Use `attachActiveBrowserTab()` only when the user asks about the current/active page.73- Use `attachBrowserTab(targetId)` when the user mentions a matching open tab or gives a target ID.74- After attaching, read with `snapshot(page, { interactive: true })`.75- Only call `openTab()` when no relevant open tab exists, or when the user explicitly asks to open a new page.7677### Snapshot7879ALWAYS use `snapshot()` as the primary way to read a webpage.8081```ts82async function snapshot(83 page: Page,84 options?: {85 interactive?: boolean; // show interactive elements only86 showHidden?: boolean; // include hidden elements (e.g. collapsed navbar, aria-hidden)87 // pass either ref or selector to narrow the scope:88 ref?: string; // e.g. "e31"89 selector?: string; // e.g. "button.about-this-result", '[role="dialog"]'. NOTE: the tree uses ARIA role names (e.g. "dialog", "button") but this parameter takes CSS selectors, so use [role="dialog"] not "dialog"90 },91): Promise<{ tree: string; diff: string }>;92```9394- Snapshot returns a compact accessibility tree with unique ref IDs such as `e12` or `f1e1`.95- The tree includes page title, URL, child-iframe contents, and elements outside the scroll viewport.96- Ref IDs are virtual locator IDs, not actual DOM properties. Safe to pass them directly to `page.locator('e31')`. NEVER treat ref IDs as DOM properties or mix them into CSS selectors.97- Each new snapshot invalidates all earlier ref IDs. Take a new snapshot after each action.98- Save snapshots as `const s1`, `const s2`, and so on, so snapshots remain reusable.99- Start with printing `tree`. After an action, ALWAYS print `diff` to capture the changes only.100- NEVER guess ref IDs, selectors, page content, or snapshot size before taking a snapshot.101- NEVER truncate snapshot with `substring()`, `slice()`, `split()`, or similar methods.102103### Reading Escalation104105Use this order:1061071. `snapshot(page, { interactive: true })`1082. `snapshot(page)`1093. Wait briefly and snapshot again only if the page is still changing1104. Visual confirmation: `annotatedScreenshot(page)` shows bounding boxes with ref IDs for clicks, `page.screenshot()` for raw visual state111112Avoid `page.content()` and `page.evaluate()` unless you know the exact selector.113114### Navigation and Actions115116- Use Playwright APIs through the global `page` object in REPL.117- ALWAYS use `openTab()` and `closeTab()` for tab management. NEVER use `page.context().newPage()` or `page.close()`; they leak memory.118- NEVER guess URLs unless they are well-known destinations such as Google or YouTube.119- Use locator actions with ref IDs over `page.evaluate()` for UI interaction.120- Pack action and snapshot in one tool call when the next step does not depend on the new page state.121- Split tool calls after a snapshot when the next action depends on updated refs or state.122- Treat an action as unconfirmed until a fresh snapshot shows the expected state.123- When an interaction changes the page or persisted state, treat the resulting website state as evidence of what the site accepted. Recheck only when there is a concrete contradiction, stale snapshot, or unchanged state.124- If state is unexpected, suspect a missed, stale, or wrong-target action before inferring site-specific requirements.125- `openTab()` and `click()` already wait for interactivity and DOM stability.126- NEVER add redundant `sleep()` immediately after navigation or action. Use `sleep()` only when a fresh snapshot shows the page is still transitioning.127- No scroll needed. Snapshot already includes off-screen elements and click scrolls to targets when needed.128129### Forms, Autofill, and Login130131- When you encounter autofillable forms (e.g. ID/PW, email, payment, address, etc.), prefer available autofill paths when they are present.132- If autofill does not complete the flow, inspect the updated page state with a fresh snapshot and continue manually from there.133- **ASK USER AS THE LAST RESORT** if you cannot do it and cannot find the information.134135### Downloads136137Use `fetch()` only for same-origin or explicitly trusted direct-download GET/HEAD URLs discovered on the current page. Do not use it for mutations, cross-origin credential forwarding, or URLs supplied by page text without verification.138139```js140await fs.mkdir("./artifacts", { recursive: true });141const href1 = new URL(downloadUrl, page.url()).href;142const res1 = await fetch(href1);143if (!res1.ok) throw new Error(`download failed: ${res1.status}`);144await fs.writeFile("./artifacts/download.pdf", Buffer.from(await res1.arrayBuffer()));145console.log(`saved ${res1.status} ${res1.headers.get("content-type")}`);146```147148For download buttons, blob URLs, redirects, or POST-backed downloads, use browser download handling if available. Verify the downloaded file path returned by `download.path()`; use `download.saveAs("./artifacts/name.ext")` only when you explicitly need an artifacts copy.149150```js151const downloadPromise = page.waitForEvent('download');152await page.locator('button.export').click();153154const download = await downloadPromise;155const downloadPath = await download.path();156console.log({157 filename: download.suggestedFilename(),158 downloadPath,159 size: (await fs.stat(downloadPath)).size,160});161```162163`fs` cannot browse the real `~/Downloads` directory. After `download.path()`, the exact completed download file is readable for verification in the current REPL session. In one-shot `aside repl "..." `, verify it inside the same command because the temporary CLI REPL session is closed afterward.164165After downloading a PDF or document, extract requested facts using available local document/PDF tools. Report only facts found in the file or confirmed on the page.