# Gologin Local Agent Browser CLI

`gologin-local-agent-browser` is an agent-friendly CLI for running **local GoLogin Orbita profiles** through a persistent daemon and a compact shell interface.

It keeps the same basic interaction model as the cloud-oriented `gologin-agent-browser` project:

- open a session
- read the page as a compact snapshot
- act on stable refs like `@e3`
- keep session state across separate CLI calls
- save screenshots and PDFs

The difference is the runtime:

- `gologin-agent-browser` talks to **Gologin Cloud Browser**
- `gologin-local-agent-browser` launches **local GoLogin Orbita** on your machine through the official `gologin` SDK

## Why This Exists

This project is for workflows where local GoLogin is the better runtime:

- profile warmup
- account login flows
- cookie accumulation
- Reddit / social / marketplace actions inside a persistent local profile
- agent loops that should reuse the same local identity across many commands
- future skill wrappers that need deterministic CLI output

The CLI is intentionally line-oriented and shell-friendly so it can be wrapped by another agent skill without extra translation glue.

## Architecture

The system has two parts:

- `gologin-local-agent-browser` CLI
- a persistent local daemon

The daemon owns live sessions, launches local Orbita through the official GoLogin SDK, connects to the returned websocket endpoint with Playwright `connectOverCDP`, and keeps the active page in memory.

That means the higher-level agent features stay the same:

- compact `snapshot` output
- ref-based actions
- session memory across calls
- semantic `find ...` flows
- artifact generation

## Installation

Node.js 20+ is required.

```bash
npm install -g gologin-local-agent-browser-cli
```

If you want to run from source:

```bash
git clone https://github.com/GologinLabs/gologin-local-agent-browser.git
cd gologin-local-agent-browser
npm install
npm run build
```

## Required Credentials

You need a GoLogin dev token.

- `GOLOGIN_TOKEN`

`GOLOGIN_TOKEN` is the canonical env var for this CLI. The older `GOLOGIN_API_TOKEN` name is still accepted as a backward-compatible alias.

## Links

- npm: `gologin-local-agent-browser-cli`
- GitHub: `GologinLabs/gologin-local-agent-browser`

## Environment

- `GOLOGIN_TOKEN`: required for `open`
- `GOLOGIN_PROFILE_ID`: optional default profile id
- `GOLOGIN_DAEMON_PORT`: optional daemon port, default `44778`
- `GOLOGIN_HEADLESS`: optional, `true` or `false`, default `false`
- `GOLOGIN_EXECUTABLE_PATH`: optional Orbita executable path when `doctor` cannot auto-detect a downloaded Orbita binary
- `GOLOGIN_TMPDIR`: optional GoLogin temp/profile directory

Config file path:

```text
~/.gologin-local-agent-browser/config.json
```

Local registry path:

```text
~/.gologin-local-agent-browser/registry.json
```

Example:

```json
{
  "token": "your_gologin_token",
  "defaultProfileId": "profile_id",
  "daemonPort": 44778,
  "headless": false,
  "executablePath": "/Applications/Orbita Browser.app/Contents/MacOS/Orbita",
  "tmpdir": "/tmp/gologin-local"
}
```

## Quickstart

```bash
export GOLOGIN_TOKEN='your_gologin_token'

gologin-local-agent-browser open-background https://example.com
gologin-local-agent-browser snapshot -i
gologin-local-agent-browser click @e3
gologin-local-agent-browser close
```

## Profile Defaults

When the GoLogin API path supports it, `profile-create` now prefers the current machine's OS instead of a hard-coded Windows fingerprint and then refreshes the profile to the latest available browser version. On macOS that means new profiles default to `os=mac` and the newest cached Orbita/Chrome line instead of an older fixed major version.

Proxy behavior is still explicit:

- no proxy unless you pass proxy flags
- `--proxy-country <cc>` for a GoLogin proxy by country
- `--proxy-host ... --proxy-port ...` for a custom proxy

For account warmup or login flows, decide the proxy strategy before creating the profile so the browsing history, cookies, and geo all line up from the first session.

## Use-Case Templates

`profile-create` and `profile-update` now accept `--template <linkedin|ads|facebook|smm|scraping|geo>`.

These templates do not invent hidden fingerprint settings. They only apply deterministic local metadata that the CLI already controls well:

- `platform`
- `status`
- `tags`
- creation notes for new profiles

Examples:

```bash
gologin-local-agent-browser profile-create "LinkedIn AE 01" --template linkedin --proxy-country us
gologin-local-agent-browser profile-create "FB Buyer 01" --template ads --proxy-country us
gologin-local-agent-browser profile-update your_profile_id --template smm --add-tags handoff-ready
```

Use-case template defaults:

- `linkedin`: warmup-oriented leadgen profile with persistent-session tags
- `ads` and alias `facebook`: ads operator profile with strong account-isolation tags
- `smm`: shared-access social profile for cookie or storage handoffs
- `scraping`: automation-oriented local profile for rendered scraping and session reuse
- `geo`: geo-testing profile where proxy alignment should be verified before use

Templates are intentionally override-friendly. Any explicit `--platform`, `--status`, `--notes`, `--tags`, or proxy flags still win.

## Doctor Use Cases

`doctor` now accepts `--use-case <linkedin|ads|facebook|smm|scraping|geo>`.

This adds use-case-specific guidance on top of the normal daemon and Orbita diagnostics:

- whether a persistent default profile is expected
- whether proxy alignment is optional, recommended, or required
- whether visible mode is better for the first login or warmup checkpoint
- the next CLI steps to take for that workflow

Example:

```bash
gologin-local-agent-browser doctor --use-case linkedin --check-proxy your_profile_id
```

For account workflows, pair `--use-case` with `--check-proxy <profileId>` so the report can compare local registry proxy state against the remote GoLogin profile.

Example `snapshot` output:

```text
session=s1 url=https://example.com/
- heading "Example Domain" [ref=@e1]
- paragraph "This domain is for use in documentation examples without needing permission. Avoid use in operations." [ref=@e2]
- link "Learn more" [ref=@e3]
```

## Command Surface

The goal is to stay as close as possible to the original agent-browser command set.

Supported commands:

- `open <url> [--profile <profileId>] [--session <sessionId>] [--idle-timeout-ms <ms>] [--headless|--background|--headed|--visible]`
- `run <runbook.json> [--session <sessionId>] [--profile <profileId>] [--vars <variables.json>] [--name <jobName>] [--continue-on-error] [--json]`
- `batch <runbook.json> --targets <targets.json> [--concurrency <n>] [--vars <variables.json>] [--name <jobName>] [--continue-on-error] [--json]`
- `jobs [--kind <run|batch>] [--status <running|ok|partial|failed>] [--search <text>] [--limit <n>] [--json]`
- `job <jobId> [--json]`
- `doctor [--json] [--check-proxy <profileId>]`
- `doctor [--json] [--check-proxy <profileId>] [--use-case <linkedin|ads|facebook|smm|scraping|geo>]`
- `profiles [--local|--remote|--all] [--platform <platform>] [--status <status>] [--tag <tag>] [--search <text>] [--json]`
- `profile <profileId> [--local|--remote] [--json]`
- `profile-create <name> [--template <linkedin|ads|facebook|smm|scraping|geo>] [--platform <platform>] [--account <label>] [--region <region>] [--status <status>] [--notes <notes>] [--tags <a,b>] [--proxy-country <country> | --proxy-host <host> --proxy-port <port>]`
- `profile-import <profileId> [--platform <platform>] [--account <label>] [--region <region>] [--status <status>] [--notes <notes>] [--tags <a,b>]`
- `profile-update <profileId> [--template <linkedin|ads|facebook|smm|scraping|geo>] [--name <name>] [--platform <platform>] [--account <label>] [--region <region>] [--status <status>] [--notes <notes>] [--tags <a,b>] [--add-tags <a,b>] [--remove-tags <a,b>] [--proxy-country <country> | --proxy-host <host> --proxy-port <port>]`
- `profile-sync <profileId> [--json]`
- `profile-delete <profileId> [--remote]`
- `tabs [--session <sessionId>]`
- `tabopen [url] [--session <sessionId>]`
- `tabfocus <index> [--session <sessionId>]`
- `tabclose [index] [--session <sessionId>]`
- `cookies [--session <sessionId>] [--output <path>] [--json]`
- `cookies-import <cookies.json> [--session <sessionId>]`
- `cookies-clear [--session <sessionId>]`
- `storage-export [path] [--scope <local|session|both>] [--session <sessionId>] [--json]`
- `storage-import <storage.json> [--scope <local|session|both>] [--clear] [--session <sessionId>]`
- `storage-clear [--scope <local|session|both>] [--session <sessionId>]`
- `eval <expression> [--json] [--session <sessionId>]`
- `snapshot [--session <sessionId>] [--interactive|-i]`
- `click <target> [--session <sessionId>]`
- `dblclick <target> [--session <sessionId>]`
- `focus <target> [--session <sessionId>]`
- `type <target> <text> [--session <sessionId>]`
- `fill <target> <text> [--session <sessionId>]`
- `hover <target> [--session <sessionId>]`
- `select <target> <value> [--session <sessionId>]`
- `check <target> [--session <sessionId>]`
- `uncheck <target> [--session <sessionId>]`
- `press <key> [target] [--session <sessionId>]`
- `scroll <up|down|left|right> [pixels] [--target <target>] [--session <sessionId>]`
- `scrollintoview <target> [--session <sessionId>]`
- `wait <target|ms> [--text <text>] [--url <pattern>] [--load <state>] [--session <sessionId>]`
- `get <text|value|html|title|url> [target] [--session <sessionId>]`
- `find <role|text|label|placeholder|first|last|nth> ...`
- `upload <target> <file...> [--session <sessionId>]`
- `pdf <path> [--session <sessionId>]`
- `screenshot <path> [--annotate] [--press-escape] [--session <sessionId>]`
- `close [--session <sessionId>]`
- `sessions`
- `current`

Aliases are preserved where they existed:

- `goto`, `navigate` -> `open`
- `history` -> `jobs`
- `open-visible` -> `open --visible`
- `open-background` -> `open --background`
- `tabnew` -> `tabopen`
- `tabswitch` -> `tabfocus`
- `js` -> `eval`
- `key` -> `press`
- `scrollinto` -> `scrollintoview`
- `quit`, `exit` -> `close`

Visibility controls:

- `--visible` and `--headed` mean the same thing: start Orbita with a visible window
- `--background` and `--headless` mean the same thing: run without a visible window
- if neither is passed, the CLI uses `GOLOGIN_HEADLESS` or falls back to visible mode
- these flags only control how the CLI-launched Orbita process is shown; they do not change the profile fingerprint or proxy configuration

## Runbooks And Batch Execution

This is the first orchestration layer above the low-level browser commands.

Use `run` when you want one reusable scenario against one profile or session:

```bash
gologin-local-agent-browser run ./examples/runbook-warmup.json \
  --profile your_profile_id \
  --name reddit-warmup
```

Runbook format is plain JSON:

```json
{
  "variables": {
    "url": "https://www.gologin.com"
  },
  "steps": [
    { "command": "open-visible", "args": ["${url}"] },
    { "command": "wait", "args": [1500] },
    { "command": "scroll", "args": ["down", 900] },
    { "command": "close" }
  ]
}
```

Notes:

- `command` can use normal command names or aliases like `open-visible`
- `args` and string-valued `flags` support `${variable}` interpolation
- `run` can inject `--profile` and `--session` automatically from the CLI flags
- every `run` creates a durable local job record, even if a step fails
- `--json` suppresses streamed step output and returns the stored job record instead
- nested `run` or `batch` steps are intentionally blocked for now

Use `batch` when you want to replay one runbook across many profiles:

```bash
gologin-local-agent-browser batch ./examples/runbook-warmup.json \
  --targets ./examples/batch-targets.json \
  --name short-warmup
```

## At-Scale Recipe

For headless local automation at scale, prefer staggered short sessions over one huge run:

```bash
gologin-local-agent-browser batch ./examples/runbook-warmup.json \
  --targets ./examples/batch-targets.json \
  --concurrency 5 \
  --name short-warmup
```

Recommended pattern:

- keep each route to roughly 5-15 minutes
- reuse one profile per account identity
- decide proxy mode before the first login
- use `doctor --use-case ... --check-proxy <profileId>` before large warmup batches
- prefer repeated short runs with pauses over a single deterministic marathon

Batch targets file:

```json
{
  "concurrency": 2,
  "targets": [
    { "name": "test1", "profileId": "profile_1", "sessionId": "warmup-test1" },
    { "name": "test2", "profileId": "profile_2", "sessionId": "warmup-test2" }
  ]
}
```

Batch behavior:

- each target gets its own fixed `sessionId`, so parallel runs do not fight over the daemon's active session
- `profileId`, `sessionId`, and `targetName` are injected as runbook variables automatically
- output is buffered per target and printed as grouped blocks after each target finishes
- every `batch` is also stored as one local job record with per-target summaries

## Jobs And Local History

`run` and `batch` now persist execution history locally under `~/.gologin-local-agent-browser/jobs/`.

List the most recent jobs:

```bash
gologin-local-agent-browser jobs
gologin-local-agent-browser jobs --kind batch --status failed
gologin-local-agent-browser history --limit 5
```

Inspect one execution in detail:

```bash
gologin-local-agent-browser job job-20260311123000-ab12cd34
gologin-local-agent-browser job job-20260311123000-ab12cd34 --json
```

History notes:

- each job keeps the resolved runbook path, optional targets and vars file paths, status, timing, and summary counts
- stdout/stderr from the orchestration command is saved beside the job record as a `.log` file
- `jobs` and `job` read local state only; they do not need a running daemon

## Doctor And Bootstrap Diagnostics

Subcommand help no longer needs a daemon round-trip:

```bash
gologin-local-agent-browser open --help
gologin-local-agent-browser profile-create --help
```

When bootstrap is flaky, inspect the local setup directly:

```bash
gologin-local-agent-browser doctor
gologin-local-agent-browser doctor --json
gologin-local-agent-browser doctor --check-proxy 69b05c486375d47ab0f12630
```

`doctor` reports whether a token is configured, whether a default profile is configured, which daemon transports are reachable, and where the daemon log lives. With `--check-proxy <profileId>` it also compares the local registry proxy and the remote GoLogin proxy so proxy drift is visible immediately.

`doctor` also reports:

- whether Orbita was resolved from `env`, config, or the downloaded SDK cache
- whether the resolved executable currently exists
- which Orbita paths were checked during auto-detection
- whether a reachable daemon belongs to the current checkout or an older stale build

If Orbita cannot be resolved automatically, set `GOLOGIN_EXECUTABLE_PATH` or add `executablePath` to `~/.gologin-local-agent-browser/config.json`.

## Browser Power Features

The CLI now also covers the browser state primitives that most skills need.

Tabs:

```bash
gologin-local-agent-browser tabs
gologin-local-agent-browser tabopen https://www.iana.org
gologin-local-agent-browser tabfocus 2
gologin-local-agent-browser tabclose 1
```

Cookies:

```bash
gologin-local-agent-browser cookies --output /tmp/reddit-cookies.json
gologin-local-agent-browser cookies-import /tmp/reddit-cookies.json
gologin-local-agent-browser cookies-clear
```

Storage for the current tab origin:

```bash
gologin-local-agent-browser storage-export /tmp/reddit-storage.json
gologin-local-agent-browser storage-import /tmp/reddit-storage.json --clear
gologin-local-agent-browser storage-clear --scope session
```

JavaScript evaluation in the current tab:

```bash
gologin-local-agent-browser eval "document.title"
gologin-local-agent-browser eval "({ url: location.href, ready: document.readyState })" --json
```

Notes:

- `storage-export` and `storage-import` work against the current tab origin only
- imported storage must match the current tab origin exactly
- `cookies` can print line-oriented output, emit JSON with `--json`, or save a JSON file with `--output`
- `eval` expects a JavaScript expression; for multi-line logic, wrap it in an IIFE

## Profiles And Local Registry

The CLI now keeps a local registry of managed profiles so skills do not need to invent their own account metadata store.

Create and register a new profile:

```bash
gologin-local-agent-browser profile-create "reddit-main" \
  --platform reddit \
  --account gedemin \
  --region us \
  --status warming \
  --tags social,reddit
```

Import an existing GoLogin profile into the local registry:

```bash
gologin-local-agent-browser profile-import 69b05c486375d47ab0f12630 \
  --platform reddit \
  --account gedemin
```

List remote GoLogin profiles or only the local registry:

```bash
gologin-local-agent-browser profiles
gologin-local-agent-browser profiles --remote
gologin-local-agent-browser profiles --all
gologin-local-agent-browser profiles --local
gologin-local-agent-browser profiles --platform reddit --status warming
gologin-local-agent-browser profiles --tag marketplace --json
```

Inspect one profile from GoLogin or force the local-registry view:

```bash
gologin-local-agent-browser profile 69b05c486375d47ab0f12630
gologin-local-agent-browser profile 69b05c486375d47ab0f12630 --local
```

Update local metadata and mirrored remote fields:

```bash
gologin-local-agent-browser profile-update 69b05c486375d47ab0f12630 \
  --status active \
  --proxy-country us \
  --add-tags warm,logged-in \
  --notes "reddit account with saved session"
```

Resync the local registry entry from GoLogin:

```bash
gologin-local-agent-browser profile-sync 69b05c486375d47ab0f12630
```

Delete only the local registry entry, or also remove the remote GoLogin profile:

```bash
gologin-local-agent-browser profile-delete 69b05c486375d47ab0f12630
gologin-local-agent-browser profile-delete 69b05c486375d47ab0f12630 --remote
```

Registry notes:

- the registry is local JSON under `~/.gologin-local-agent-browser/registry.json`
- `profiles` defaults to the remote GoLogin view when a token is configured, otherwise it falls back to the local registry
- `profiles --all` merges remote profiles with local-only registry entries
- remote-only profiles are shown as `status=unregistered` until you `profile-import` them
- `name` and `notes` are mirrored to the remote GoLogin profile on `profile-update`
- `profile-update` can also change the remote proxy with the same `--proxy-country` or custom proxy flags used by `profile-create`
- platform, account label, region, status, and tags are local metadata for your own orchestration layer

## Proxy Support

For auto-created temporary profiles you can attach a proxy at open time:

Gologin proxy by country:

```bash
gologin-local-agent-browser open https://example.com --proxy-country us
```

Custom proxy:

```bash
gologin-local-agent-browser open https://example.com \
  --proxy-host 1.2.3.4 \
  --proxy-port 8080 \
  --proxy-mode http \
  --proxy-user user \
  --proxy-pass secret
```

If you already have a prepared GoLogin profile, reuse it directly:

```bash
gologin-local-agent-browser open https://example.com --profile your_profile_id
```

Proxy flags are intentionally blocked together with `--profile`, because mutating an existing profile implicitly is too risky.

For selector discovery on real sites, use the interactive snapshot view:

```bash
gologin-local-agent-browser snapshot -i
```

## Skill-Friendly Use Cases

This CLI is shaped so you can wrap it as a skill later.

Good fits:

- profile warmup
- login automation
- cookie harvesting
- controlled browsing loops
- account maintenance
- moderation / posting / scrolling sequences inside a persistent profile

Why it works well for a skill:

- stable line-oriented stdout
- explicit session ids
- explicit refs from `snapshot`
- daemon-backed continuity between calls
- no need to keep a single long-running shell process

Example flow for a warmup or login-oriented skill:

```bash
gologin-local-agent-browser open https://www.reddit.com --profile your_profile_id
gologin-local-agent-browser snapshot -i
gologin-local-agent-browser click @e4
gologin-local-agent-browser type @e7 "username"
gologin-local-agent-browser type @e8 "password"
gologin-local-agent-browser press Enter
gologin-local-agent-browser wait --text "Home"
gologin-local-agent-browser close
```

## Notes

- The first local run may trigger Orbita download/preparation through the GoLogin SDK.
- Session persistence is daemon-backed. Restarting the daemon clears in-memory refs and active session bookkeeping.
- Profile data persists in GoLogin because the local runtime calls `stopLocal({ posting: true })` on close.
- Auto-created temporary profiles are deleted on cleanup.
- `snapshot` refs are best-effort. After navigation or major DOM updates, run `snapshot` again.

## Development

```bash
npm install
npm run typecheck
npm test
npm run build
```

Live smoke example:

```bash
GOLOGIN_TOKEN='your_gologin_token' node dist/cli.js open-visible https://example.com
GOLOGIN_TOKEN='your_gologin_token' node dist/cli.js snapshot
GOLOGIN_TOKEN='your_gologin_token' node dist/cli.js close
```
