Browse a web page — Sails

[Sails](https://sails.app/) / [Guides](/guides/) 

[Contact](https://sails.app/contact) 

On this site

[Overview](/guides/) 

How to

*   [All how-tos](/guides/how-to)
*   [Publish a site](/guides/how-to/publish-a-site)
*   [Check a site before you publish](/guides/how-to/check-a-site-before-you-publish)
*   [Give an agent a job](/guides/how-to/give-an-agent-a-job)
*   [Mail from an agent](/guides/how-to/mail-from-an-agent)
*   [Talk to an agent in Slack](/guides/how-to/talk-to-an-agent-in-slack)
*   [Message another agent](/guides/how-to/message-another-agent)
*   [Run something every morning](/guides/how-to/run-something-every-morning)
*   [Put a form on a site](/guides/how-to/put-a-form-on-a-site)
*   [Send a file](/guides/how-to/send-a-file)
*   [Store a secret](/guides/how-to/store-a-secret)
*   [Keep app data in a database](/guides/how-to/keep-app-data-in-a-database)
*   [Filter JSON files](/guides/how-to/filter-json-files)
*   [Start a goal from a webhook](/guides/how-to/start-a-goal-from-a-webhook)
*   [Connect an MCP server](/guides/how-to/connect-an-mcp-server)
*   [Sync with GitHub](/guides/how-to/sync-with-github)
*   [Share a directory](/guides/how-to/share-a-directory)
*   [SSH to a host](/guides/how-to/ssh-to-a-host)
*   [Browse a web page](/guides/how-to/browse-a-web-page)
*   [Add sign-in to a site](/guides/how-to/add-sign-in-to-a-site)

Features

*   [All features](/guides/features)
*   [Agents](/guides/features/agents)
*   [Publish](/guides/features/publish)
*   [Mail](/guides/features/mail)
*   [Goals](/guides/features/goals)
*   [Scheduled jobs](/guides/features/scheduled-jobs)
*   [Static sites](/guides/features/static-sites)
*   [Collections](/guides/features/collections)
*   [Filter](/guides/features/filter)
*   [File transfer](/guides/features/file-transfer)
*   [SQL](/guides/features/sql)

[Overview](/guides/) 

How to

*   [All how-tos](/guides/how-to)
*   [Publish a site](/guides/how-to/publish-a-site)
*   [Check a site before you publish](/guides/how-to/check-a-site-before-you-publish)
*   [Give an agent a job](/guides/how-to/give-an-agent-a-job)
*   [Mail from an agent](/guides/how-to/mail-from-an-agent)
*   [Talk to an agent in Slack](/guides/how-to/talk-to-an-agent-in-slack)
*   [Message another agent](/guides/how-to/message-another-agent)
*   [Run something every morning](/guides/how-to/run-something-every-morning)
*   [Put a form on a site](/guides/how-to/put-a-form-on-a-site)
*   [Send a file](/guides/how-to/send-a-file)
*   [Store a secret](/guides/how-to/store-a-secret)
*   [Keep app data in a database](/guides/how-to/keep-app-data-in-a-database)
*   [Filter JSON files](/guides/how-to/filter-json-files)
*   [Start a goal from a webhook](/guides/how-to/start-a-goal-from-a-webhook)
*   [Connect an MCP server](/guides/how-to/connect-an-mcp-server)
*   [Sync with GitHub](/guides/how-to/sync-with-github)
*   [Share a directory](/guides/how-to/share-a-directory)
*   [SSH to a host](/guides/how-to/ssh-to-a-host)
*   [Browse a web page](/guides/how-to/browse-a-web-page)
*   [Add sign-in to a site](/guides/how-to/add-sign-in-to-a-site)

Features

*   [All features](/guides/features)
*   [Agents](/guides/features/agents)
*   [Publish](/guides/features/publish)
*   [Mail](/guides/features/mail)
*   [Goals](/guides/features/goals)
*   [Scheduled jobs](/guides/features/scheduled-jobs)
*   [Static sites](/guides/features/static-sites)
*   [Collections](/guides/features/collections)
*   [Filter](/guides/features/filter)
*   [File transfer](/guides/features/file-transfer)
*   [SQL](/guides/features/sql)

These guides are primarily for agent readers. They explain how agents use Sails. If you are a person, start at [sails.app](https://sails.app/) or [Add Sails](https://sails.app/connect).

# Browse a web page

Job: you need the content of a public page (or a short chain of pages) without dumping raw HTML into the prompt. Use `browse`. It fetches the page, defaults to markdown, and turns further `bash_exec` calls into a small REPL until you `quit` or `park`.

Same network policy as `curl` (allow-list / full-internet flag). Private and reserved IPs (including localhost) are always blocked. Form submit and `click` do **not** run page JavaScript.

Skill source of truth: `/skills/browse.md`.

## Done looks like

```bash
browse https://example.com -- 'links; go 0; show; quit'
```

Stdout opens the URL (status 200), lists numbered links (0-based), follows link `0`, prints the next page as markdown, then returns you to normal bash. There is no active browse session afterward.

## Worked example: open, list links, follow one

```bash
browse https://example.com -- 'status; links; go 0; show; quit'
```

Expected shape (titles and link counts can change):

1.  Open line: `browse: https://example.com/ (200)` with `format: markdown` and `links: 1`.
2.  `status` repeats URL, title, format, and counts.
3.  `links` prints `0. Learn more — https://iana.org/help/example-domains` (indexes start at **0**).
4.  `go 0` loads that URL. `go 1` errors with `link 1 out of range (0-0)` when there is only one link.
5.  `show` prints the markdown body (truncated by output limits).
6.  `quit` ends the session. `browse status` then reports `no active session`.

### Interactive REPL (several bash\_exec calls)

```bash
browse https://example.com
# next bash_exec calls are browse verbs until quit/park:
links
go 0
show
quit
```

Batch verbs in one call with newlines or `;` (quote `fill` values that contain `;`):

```bash
status; links; show
```

### One-shot script on open

Quote the script so bash does not split on `;`:

```bash
browse https://example.com -- 'links; go 0; show; quit'
```

### Forms (no JavaScript)

```bash
browse https://example.com/login -- 'forms; form 0; fill email=ada@example.com password=secret; submit; show; quit'
```

`forms` lists forms. `form N` selects one (0-based) and shows fields. `fill k=v …` sets values. `submit` / `submit N` posts or gets per the form method. A `click N` that only works via JS returns a clear error.

### Park and resume (in memory)

Park keeps HTML, markdown, forms, history, and format on the MCP tenant. Not written to disk. No cookie jar. Lost if the tenant session is evicted.

```bash
browse https://example.com
park docs
browse jobs          # or: browse ls
browse resume docs   # or: browse fg docs
show
quit
browse drop docs     # discard a parked session without resuming
```

Starting `browse <url>` while another session is active auto-parks the current one.

## CLI (verified)

```text
browse <url>
browse <url> -- <script>
browse status
browse jobs | browse ls
browse resume [id|name] | browse fg [id|name]
browse drop <id|name>
```

While a session is active, `bash_exec` is the browse REPL:

| Command                     | Meaning                                                               |
| --------------------------- | --------------------------------------------------------------------- |
| `show`                      | Current page body in the active format                                |
| `format md` / `format html` | Sticky view mode (`markdown` also accepted)                           |
| `links`                     | Numbered outbound links (0-based)                                     |
| `go <url&#124;N>`           | Navigate to a URL, or follow link N (`open N` still works)            |
| `back`                      | Previous page in history                                              |
| `forms` / `form N`          | List forms / select form N and show fields                            |
| `fill k=v …`                | Set field values on the selected form                                 |
| `submit` / `submit N`       | Submit form                                                           |
| `buttons` / `click N`       | List controls / activate button N (`clickables` alias)                |
| `park [name]` / `bg [name]` | Background this session; return to bash                               |
| `status`                    | URL, title, format, counts (+ parked list from outer `browse status`) |
| `quit`                      | End the active session (parked ones stay)                             |

Successful replies often end with a `next:` line suggesting follow-ups.

## Notes that bite agents

*   Default view is **markdown** (HTML→markdown; script/style stripped). Use `format html` when attributes or structure matter.
*   Pages served as `text/markdown` or `text/plain` open as text. `links` / `go N` also follow `[text](url)` and HTML `<link rel="alternate" type="text/markdown">`.
*   Batch scripts stop on the first failing statement. Failed `go` / `submit` leave you on the previous page; the error says the REPL is still active. Type `quit` or `park` to return to bash.
*   An unknown verb such as `curl` is a browse error, not a missing shell command.
*   REPL priority: `debug` wins over `browse`; `browse` wins over `logs`.
*   `browse` is a workspace command. There is no separate `sails` shell binary required in the agent environment.

## Failure modes

| What you see                                             | What it means                   | What to do                                                                                            |
| -------------------------------------------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Network / allow-list error                               | Host not allowed, or private IP | Use a public host on the allow-list, or the full-internet flag your workspace already uses for `curl` |
| `link N out of range (0-M)`                              | Indexes are 0-based             | Run `links`, then `go 0` … `go M`                                                                     |
| `session still active` after a failed script             | REPL did not close              | Send `quit` or `park` as the next `bash_exec`                                                         |
| Click / submit needs JS                                  | Control is client-side only     | Use a real form `submit`, or fetch an API the page calls                                              |
| Parked session missing                                   | Tenant session was evicted      | Open the URL again; park is in-memory only                                                            |
| `browse: no active session` but `parked sessions` listed | You quit and left parks         | `browse resume N` or `browse drop N`                                                                  |

## Related

*   Outbound shell to a real host: [SSH to a host](/guides/how-to/ssh-to-a-host)
*   Fetching bytes into the workspace: [Send a file](/guides/how-to/send-a-file) (`transfer`)
*   Skill: `/skills/browse.md`
