# Remember This Map

> A closing recap: the TUI is the steering wheel, the agent loop is the helper, the browser driver is the remote-control box, and the store plus tests are how the repo remembers and proves what happened.

- Repository: browser-use/terminal
- GitHub: https://github.com/browser-use/terminal
- Human wiki: https://grok-wiki.com/public/wiki/browser-use-terminal-686510dbe50c
- Complete Markdown: https://grok-wiki.com/public/wiki/browser-use-terminal-686510dbe50c/llms-full.txt

## Source Files

- `crates/browser-use-store/src/lib.rs`
- `crates/browser-use-store/migrations/0001_initial.sql`
- `crates/browser-use-protocol/src/lib.rs`
- `tests/golden-events/running-browser-session/events.jsonl`
- `tests/golden-events/running-browser-session/session.json`
- `scripts/verify-terminal-ui.sh`
- `scripts/tui-terminal-smoke.py`
- `docs/terminal-ui-testing.md`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [crates/browser-use-store/src/lib.rs](crates/browser-use-store/src/lib.rs)
- [crates/browser-use-store/migrations/0001_initial.sql](crates/browser-use-store/migrations/0001_initial.sql)
- [crates/browser-use-store/migrations/0002_agent_session_fields.sql](crates/browser-use-store/migrations/0002_agent_session_fields.sql)
- [crates/browser-use-store/migrations/0003_agent_messages.sql](crates/browser-use-store/migrations/0003_agent_messages.sql)
- [crates/browser-use-store/migrations/0004_app_settings.sql](crates/browser-use-store/migrations/0004_app_settings.sql)
- [crates/browser-use-protocol/src/lib.rs](crates/browser-use-protocol/src/lib.rs)
- [crates/browser-use-core/src/lib.rs](crates/browser-use-core/src/lib.rs)
- [crates/browser-use-browser/src/lib.rs](crates/browser-use-browser/src/lib.rs)
- [crates/browser-use-providers/src/lib.rs](crates/browser-use-providers/src/lib.rs)
- [crates/browser-use-tui/src/main.rs](crates/browser-use-tui/src/main.rs)
- [crates/browser-use-tui/src/runtime.rs](crates/browser-use-tui/src/runtime.rs)
- [crates/browser-use-tui/src/render.rs](crates/browser-use-tui/src/render.rs)
- [crates/browser-use-tui/src/settings.rs](crates/browser-use-tui/src/settings.rs)
- [tests/golden-events/running-browser-session/events.jsonl](tests/golden-events/running-browser-session/events.jsonl)
- [tests/golden-events/running-browser-session/session.json](tests/golden-events/running-browser-session/session.json)
- [scripts/verify-terminal-ui.sh](scripts/verify-terminal-ui.sh)
- [scripts/tui-terminal-smoke.py](scripts/tui-terminal-smoke.py)
- [docs/terminal-ui-testing.md](docs/terminal-ui-testing.md)
</details>

# Remember This Map

This page is the closing mental map for `browser-use/terminal`. Think of the app as four simple parts: the TUI is the steering wheel, the agent loop is the helper, the browser driver is the remote-control box, and the store plus tests are the notebook and proof system.

This is not a claim that the repo is tiny. It is a useful first map: when something changes on screen, an event was probably written; when an agent does work, the loop probably appended events; when a browser changes, the browser driver probably emitted browser events; when a maintainer asks whether a TUI change is done, the terminal verification loop is the repo-owned answer.

Generation note: no `STRATEGY.md` or `docs/solutions/**` source was present in this checkout, and no installed local Compound Engineering skill was available to execute. This page applies the requested wiki-shape guidance as portable synthesis while keeping repository code as the source of truth.

## The One-Page Map

```mermaid
flowchart LR
  subgraph UI["TUI: steering wheel"]
    Main["crates/browser-use-tui/src/main.rs<br/>surfaces, commands, state cache"]
    Render["crates/browser-use-tui/src/render.rs<br/>WorkbenchState -> terminal"]
  end

  subgraph Agent["Agent loop: helper"]
    Runtime["tui/runtime.rs<br/>starts an agent thread"]
    Core["browser-use-core<br/>provider turns, tools, events"]
    Providers["browser-use-providers<br/>provider-neutral ModelProvider"]
  end

  subgraph Browser["Browser driver: remote-control box"]
    BrowserCrate["browser-use-browser<br/>CDP session + browser commands"]
    PythonBridge["browser_script bridge<br/>fresh Python page work"]
  end

  subgraph Memory["Store + protocol: memory"]
    Store["browser-use-store<br/>SQLite state.db + artifacts"]
    Protocol["browser-use-protocol<br/>events -> WorkbenchState"]
  end

  subgraph Proof["Proof loop"]
    Golden["golden-events fixtures"]
    Verify["verify-terminal-ui.sh + tmux smoke"]
  end

  Main --> Runtime --> Core
  Core --> Providers
  Core --> BrowserCrate
  BrowserCrate --> PythonBridge
  Core --> Store
  BrowserCrate --> Store
  Store --> Protocol --> Render
  Store --> Golden
  Verify --> Main
```

The arrows show ownership of movement, not a strict call stack for every line. The TUI starts and displays work. The core loop performs model/tool turns. The browser crate owns browser control. The store records the facts. The protocol turns facts into display state. The tests check that the display and saved events still mean what maintainers think they mean.

Sources: [crates/browser-use-tui/src/main.rs:261-322](), [crates/browser-use-tui/src/runtime.rs:12-60](), [crates/browser-use-core/src/lib.rs:699-843](), [crates/browser-use-browser/src/lib.rs:1-7](), [crates/browser-use-store/src/lib.rs:321-378](), [crates/browser-use-protocol/src/lib.rs:1013-1076](), [scripts/verify-terminal-ui.sh:11-43]()

## The TUI Is The Steering Wheel

The terminal UI owns the human-facing surfaces: main, setup, account, API key, telemetry, model, browser, history, and developer. It also owns commands like starting a task, sending a follow-up, reconnecting the browser, changing model, changing browser, and saving settings. That is why “steering wheel” is a good name: it does not do every job itself, but it decides what the user is trying to do next.

The TUI keeps a local cache of sessions and events. It hydrates from the store, refreshes sessions and events after notifications, and projects that stored history into a `WorkbenchState`. Rendering then reads `WorkbenchState` and chooses what to draw: setup, ready, running, result, failed, or cancelled.

Sources: [crates/browser-use-tui/src/main.rs:116-198](), [crates/browser-use-tui/src/main.rs:261-339](), [crates/browser-use-tui/src/main.rs:341-420](), [crates/browser-use-tui/src/main.rs:445-557](), [crates/browser-use-tui/src/render.rs:93-129](), [crates/browser-use-tui/src/render.rs:151-213]()

### What The TUI Does Not Own

The TUI does not directly implement provider calls or browser automation. When it needs work done, it starts an agent thread. That thread opens the store, prepares browser mode and provider config, then calls the core runtime.

Sources: [crates/browser-use-tui/src/runtime.rs:12-50](), [crates/browser-use-core/src/lib.rs:301-338]()

## The Agent Loop Is The Helper

The agent loop is the helper that turns a task into steps. When a new task starts, core creates or loads a session, writes `session.input`, builds provider messages, and enters a turn loop. Inside the loop it records status, model config, provider usage, model deltas, tool calls, terminal results, and failures.

A short version:

1. Start with a stored session and task text.
2. Choose a provider backend and model.
3. Ask the provider for text or tool calls.
4. Dispatch tool calls.
5. Append events after each meaningful thing.
6. Finish with `session.done`, `session.failed`, or cancellation.

```rust
// crates/browser-use-core/src/lib.rs
store.append_event(
    &session.id,
    "session.input",
    serde_json::json!({ "text": task_text }),
)?;
```

The important design detail is that the helper reports its work by writing events. The UI can then recover the story from the store instead of trusting a fragile in-memory screen state.

Sources: [crates/browser-use-core/src/lib.rs:252-269](), [crates/browser-use-core/src/lib.rs:779-843](), [crates/browser-use-core/src/lib.rs:920-1003](), [crates/browser-use-core/src/lib.rs:1035-1088]()

### Provider Neutrality And BYOK

Provider choice is deliberately separated from the loop. `ProviderBackend` includes Codex, OpenAI, Anthropic, OpenRouter, Fake, and None. The provider crate defines a `ModelProvider` trait with `provider_name`, `model_name`, and turn methods. Concrete providers read keys or base URLs from settings or environment variables, which keeps the architecture friendly to BYOK and provider substitution.

This does not mean every provider has identical behavior. It means the core loop talks to a trait and records provider/model metadata, while provider-specific authentication and request formats stay behind provider implementations.

Sources: [crates/browser-use-core/src/lib.rs:56-90](), [crates/browser-use-core/src/lib.rs:301-348](), [crates/browser-use-core/src/lib.rs:426-484](), [crates/browser-use-providers/src/lib.rs:18-45](), [crates/browser-use-providers/src/lib.rs:119-154](), [crates/browser-use-providers/src/lib.rs:205-240](), [crates/browser-use-providers/src/lib.rs:348-408](), [crates/browser-use-tui/src/settings.rs:4-12](), [crates/browser-use-tui/src/settings.rs:60-79]()

## The Browser Driver Is The Remote-Control Box

The browser crate says its split plainly: `browser` controls connection, lifecycle, and debug state; `browser_script` runs fresh Python through the Rust-held CDP connection. That is the remote-control box: it knows how to connect to local Chrome, start managed Chromium, connect to remote CDP, start remote cloud sessions, recover, report status, and expose runtime ownership/log commands.

The browser session keeps mode, owner, endpoint, CDP connection, target/session IDs, managed-browser state, remote browser ID, live URL, profile, errors, and logs. Browser commands then emit browser events when the visible browser state changes.

Sources: [crates/browser-use-browser/src/lib.rs:1-7](), [crates/browser-use-browser/src/lib.rs:56-75](), [crates/browser-use-browser/src/lib.rs:146-188](), [crates/browser-use-browser/src/lib.rs:194-218](), [crates/browser-use-browser/src/lib.rs:412-560](), [crates/browser-use-browser/src/lib.rs:572-617]()

### Browser Scripts Are Isolated Work Bursts

When page interaction needs Python, `run_browser_script` creates an artifact directory, starts a local bridge, builds a prelude, spawns `python3`, waits with a timeout, parses a marked JSON result, and returns text, data, images, artifacts, and browser events. That keeps browser page work as a contained burst while Rust keeps the browser session registry.

Sources: [crates/browser-use-browser/src/lib.rs:220-344](), [crates/browser-use-browser/src/lib.rs:393-410]()

## The Store Is How The Repo Remembers

The store is the durable notebook. Opening a store resolves the state directory, creates the state and artifact directories, opens `state.db`, enables WAL mode and a busy timeout, then applies migrations. The first migration defines `sessions`, `events`, `artifacts`, `runs`, and `agent_edges`. Later migrations add agent metadata, agent messages, and app settings.

| Thing | What It Remembers |
|---|---|
| `sessions` | task identity, parent session, cwd, artifact root, status, timestamps |
| `events` | ordered facts for a session: input, browser state, tool output, result, failures |
| `artifacts` | files/images linked to sessions and event sequences |
| `runs` | process/run lifecycle for a session |
| `agent_edges` and agent fields | parent-child agent relationships |
| `app_settings` | local account, auth, browser, model, and setup choices |

Sources: [crates/browser-use-store/src/lib.rs:16-25](), [crates/browser-use-store/src/lib.rs:104-145](), [crates/browser-use-store/migrations/0001_initial.sql:1-49](), [crates/browser-use-store/migrations/0002_agent_session_fields.sql:1-5](), [crates/browser-use-store/migrations/0003_agent_messages.sql:1-11](), [crates/browser-use-store/migrations/0004_app_settings.sql:1-5]()

### Events Are The Main Memory Shape

`append_event` inserts an event row, updates the session timestamp, updates status when the event implies status, commits, and notifies listeners. The TUI cache listens for those notifications, pulls only new events after the last known sequence, and marks the projected state dirty.

That makes the app event-sourced in the practical sense: the screen is rebuilt from session metadata plus event history.

Sources: [crates/browser-use-store/src/lib.rs:321-378](), [crates/browser-use-store/src/lib.rs:401-435](), [crates/browser-use-store/src/lib.rs:490-517](), [crates/browser-use-store/src/lib.rs:1040-1125](), [crates/browser-use-tui/src/main.rs:362-377](), [crates/browser-use-tui/src/main.rs:445-463]()

## The Protocol Is The Translator

`browser-use-protocol` defines the shared vocabulary: session metadata, session statuses, event records, artifact metadata, tool calls, tool results, model events, browser summaries, telemetry summaries, history rows, transcript turns, and the final `WorkbenchState`.

It also translates raw events into useful UI facts. For example, `browser_summary_from_events` turns `browser.live_url`, `browser.page`, and `browser.state` events into status, URL, title, tab count, viewport, and live URL. `project_workbench` combines current session events, all session events, history, transcript, browser summary, telemetry, result, and failure into one state object for rendering.

Sources: [crates/browser-use-protocol/src/lib.rs:4-23](), [crates/browser-use-protocol/src/lib.rs:56-113](), [crates/browser-use-protocol/src/lib.rs:150-189](), [crates/browser-use-protocol/src/lib.rs:202-260](), [crates/browser-use-protocol/src/lib.rs:433-495](), [crates/browser-use-protocol/src/lib.rs:1013-1076]()

## Golden Fixtures Are Small Recorded Stories

The golden `running-browser-session` fixture is a tiny recorded story: a user asks to open and inspect a live browser, a live URL appears, the browser reports it is connected to `https://example.com/` with title, tab count, and viewport, and then a Python tool starts.

```json
{"type":"session.input","payload":{"text":"Open the live browser and inspect the page"}}
{"type":"browser.live_url","payload":{"live_url":"https://live.browser-use.com/?wss=golden"}}
{"type":"browser.state","payload":{"status":"connected","url":"https://example.com/","title":"Example Domain","tabs":2,"viewport":{"w":1280,"h":720}}}
```

The matching session metadata says the fixture session is `running`. Store tests import all checked-in golden event fixtures and assert expected IDs, so these files are not just examples; they are compatibility checks for the stored event shape.

Sources: [tests/golden-events/running-browser-session/events.jsonl:1-4](), [tests/golden-events/running-browser-session/session.json:1-8](), [crates/browser-use-store/src/lib.rs:1181-1235]()

## Terminal Tests Are The Proof System

The repository does not treat `cargo test` alone as enough for TUI work. The docs say terminal UI changes cross a real terminal boundary, so useful tests must start the app in a terminal, send real keys, capture visible output, and assert both presence and absence: expected UI text should appear, duplicate chrome and raw escape sequences should not.

The full verification script runs formatting, Rust tests, Python tests, deterministic TUI dumps for several states and overlays, and then the real terminal smoke test. The smoke test uses tmux, sends keys, captures panes, writes artifacts under `/tmp/but-design-loop`, and checks for problems like duplicated panels, broken bracketed paste, stale redraws, and ANSI escapes in plain output.

Sources: [docs/terminal-ui-testing.md:1-33](), [scripts/verify-terminal-ui.sh:11-43](), [scripts/tui-terminal-smoke.py:1-7](), [scripts/tui-terminal-smoke.py:80-109](), [scripts/tui-terminal-smoke.py:112-188](), [scripts/tui-terminal-smoke.py:255-257]()

## How To Use This Map When Debugging

| Symptom | First Place To Look | Why |
|---|---|---|
| The screen is wrong but events look right | `crates/browser-use-protocol` and `crates/browser-use-tui/src/render.rs` | Projection or rendering may be translating correctly stored events incorrectly. |
| A task does not finish or records the wrong result | `crates/browser-use-core/src/lib.rs` | The agent loop owns provider turns, tool dispatch, `session.done`, and failure events. |
| Browser status, live URL, or page metadata is wrong | `crates/browser-use-browser/src/lib.rs` | Browser command dispatch and browser event emission live there. |
| History, resume, or session status is wrong | `crates/browser-use-store/src/lib.rs` and migrations | Store inserts events, derives session status, and lists events/sessions. |
| A TUI fix looks fine in dumps but feels broken in a terminal | `scripts/verify-terminal-ui.sh` and `scripts/tui-terminal-smoke.py` | The repo requires real-terminal verification for keyboard, scrollback, paste, redraw, and plain output behavior. |

Sources: [crates/browser-use-protocol/src/lib.rs:1013-1076](), [crates/browser-use-tui/src/render.rs:93-129](), [crates/browser-use-core/src/lib.rs:920-1040](), [crates/browser-use-browser/src/lib.rs:412-617](), [crates/browser-use-store/src/lib.rs:321-435](), [docs/terminal-ui-testing.md:21-33]()

## Closing Summary

Remember the map: the TUI steers, the agent loop helps, the browser driver controls the browser, the store remembers, and the tests prove that the remembered story still renders and behaves correctly in a real terminal. The central design habit is to turn work into events, then rebuild user-facing state from those events through the protocol layer. Sources: [crates/browser-use-store/src/lib.rs:321-378](), [crates/browser-use-protocol/src/lib.rs:1013-1076](), [scripts/verify-terminal-ui.sh:11-43]()
