# Host Browser

<!-- BEGIN GENERATED: guide-map -->
## Guide map

Read only the section needed for the next decision. Line ranges are exact
for this generated runtime target.

| Section | What it covers | Lines |
| --- | --- | --- |
| [Purpose](#purpose) | Scope, ownership, and the central operating question. | 26-41 |
| [Use This When](#use-this-when) | Tasks and conditions that belong in this guide. | 42-59 |
| [Do Not Use This For](#do-not-use-this-for) | Boundaries and the correct routes for excluded work. | 60-70 |
| [Mental Model](#mental-model) | Concepts and state boundaries needed for correct operation. | 71-88 |
| [Preflight](#preflight) | State, authority, inputs, and readiness to verify before execution. | 89-105 |
| [Risk And Side Effects](#risk-and-side-effects) | Effects, approvals, cost, privacy, and retry boundaries. | 106-117 |
| [Canonical Operating Pattern](#canonical-operating-pattern) | The normal end-to-end execution sequence. | 118-134 |
| [Core SDK Surfaces](#core-sdk-surfaces) | Exact source-backed callable contracts owned by this guide. | 135-159 |
| [Data Contracts](#data-contracts) | Required identities, fields, evidence, handles, and durable shapes. | 160-227 |
| [Examples](#examples) | Representative usage patterns and code. | 228-271 |
| [Verification](#verification) | Evidence required before reporting success. | 272-286 |
| [Troubleshooting](#troubleshooting) | Failure diagnosis and corrective routes. | 287-298 |
| [Related References](#related-references) | Adjacent boundaries and when to cross them. | 299-310 |
<!-- END GENERATED: guide-map -->

## Purpose

Use this reference for Verbiflow-owned browser and provider-session work across
local and managed hosted adapters: saved provider sessions, provider readiness,
LinkedIn browser reads and scrapes, and interactive provider login/setup.
Local adapters additionally expose Chrome/CDP JavaScript, network evidence, and
host action-history tools.

Do not merge this file into `web.md`. `web.md` owns public/explicit-URL web
search, Bridge page extraction, page capture, screenshots,
markdown/html output, page-load network logs, web row/error contracts, and
Chromium-pool or Browser Use performance. `host_browser.md` owns browser
identity and logged-in provider state.

Local `vf.host.actions.*` is the debug log for the same host/browser system.

## Use This When

- Capturing, validating, refreshing, listing, or reading provider browser
  sessions for LinkedIn.
- Checking whether the active browser adapter can run.
- Deleting Local provider sessions or inspecting/clearing Local action history.
- Running focused JavaScript against the active browser session.
- Running explicit AppleScript against Local Chrome.
- Recording fetch/XHR/resource timing evidence from an authenticated browser
  tab/session.
- Reading LinkedIn browser sessions, inbox threads, thread messages, rendered
  posts, or visible feed content from local Chrome or a LinkedIn Browser Use
  profile.
- Creating or validating a workspace LinkedIn sender account from browser auth
  state.
  Local setup reads the operator-selected browser session. Production sender
  runtime still lands in Unipile.

## Do Not Use This For

| Task | Use Instead |
| --- | --- |
| Bridge-backed public web search, page extraction, explicit URL crawling, screenshots, markdown/html capture, page-load network logs, shared Chromium pool tuning, or web row/error contracts. | Use `web.md` for explicit URL page capture/screenshots. |
| Backend/provider LinkedIn research, relationship reads, chat history, connection requests, direct messages, post publishing, or send status. | `linkedin.md` |
| Clay people or company search. | `clay.md`; it uses the Public API and never a browser session. |
| Crunchbase connect, entity resolution, or company search workflows. | `crunchbase.md` |
| Generic app/browser testing unrelated to Verbiflow provider sessions, workflow evidence, or report artifacts. | Use the host app's browser automation tools, not `vf.host.*`. |
| Sequence staging, publish, send, sender/domain purchase, or activation decisions. | `sequences.md`, `sequence_authoring.md`, `mailboxes.md`, `safety.md` |

## Mental Model

There are three host-browser classes. The public `vf.host.*` API is stable while
the selected host adapter changes underneath it.

| Class | What It Means | Normal Surfaces |
| --- | --- | --- |
| Saved provider session | Local adapters support their documented providers. Hosted `vf.host.sessions.*` is LinkedIn-only and returns redacted connection records. Neither surface returns raw cookies. | `vf.host.sessions.*` |
| LinkedIn browser adapter | LinkedIn-specific browser reads or feed scrapes when backend `vf.linkedin.*` cannot provide needed rendered/session state. Sender sends/sync/replies stay on Unipile. | `vf.host.linkedin_browser.*` |
| Live Chrome/DOM | Local Chrome owns browser transport and session placement. | `vf.host.chrome.*`, `vf.host.web.*` |
| Host action history | Local debug records for browser/provider calls. | `vf.host.actions.*` |

Reusable-profile and DOM-backed flows are different. Session flows
capture or create reusable provider identity. DOM-backed flows need a live
browser tab/session because rendered state, scrolling, client hints, or
interactive UI state matter. Do not substitute one for the other without
checking the owning provider reference.

## Preflight

- Confirm the task is Verbiflow/provider/workflow evidence work, not generic
  browser testing.
- Confirm auth/workspace before any call that can create platform state or start
  credential setup, such as `vf.host.linkedin_browser.connect_from_browser_cookies(...)`.
- Run `vf.host.chrome.status()` before live Chrome, AppleScript, JavaScript, or
  LinkedIn browser work.
- For saved sessions, call `vf.host.sessions.list(...)` or
  `vf.host.sessions.get(...)` first when a session name is ambiguous.
- Validate or refresh saved sessions before long-running provider work.
- Print provider, session name, selected `session_id`, action ids, job ids, row
  counts, output paths, and small previews before using browser evidence
  downstream.
- Keep browser outputs inside the workflow/report root when they should become
  workflow evidence.

## Risk And Side Effects

| Operation | Risk | Required Handling |
| --- | --- | --- |
| `vf.host.sessions.list(...)`, `vf.host.sessions.get(...)` | Read of redacted session/profile state. | Preserve names, providers, validation status, and timestamps. Never expect raw cookies. |
| `vf.host.sessions.capture(...)`, `vf.host.sessions.refresh(...)` | Writes provider profile state and may start interactive login setup. | Print provider and session identity; return the `live_url` when setup requires human login. |
| `vf.host.sessions.validate(...)`, `vf.host.chrome.status(...)` | Profile/browser readiness check. | Preserve status, blocked reason, profile identity, and any interaction URL. |
| `vf.host.sessions.delete(...)`, `vf.host.actions.list(...)`, `vf.host.actions.clear(...)` | Local session or debug-log administration. | Scope the exact session/log records and preserve needed evidence first. |
| `vf.host.chrome.run(...)`, `vf.host.chrome.network_log(...)`, `vf.host.chrome.applescript(...)` | Local browser execution. | Scope the target tab/host and keep sensitive page or request data out of logs. |
| `vf.host.linkedin_browser.list_sessions(...)`, `list_threads(...)`, `get_messages(...)`, `scrape_visible_feed(...)` | LinkedIn browser read/scrape. May read account-specific inbox/feed/session state. | Use only for the intended logged-in account; preserve session/status/counts/captured rows. |
| `vf.host.linkedin_browser.connect_from_browser_cookies(...)` | Creates or validates LinkedIn browser setup from the Local browser session. | Treat as an explicit top-level operation. Confirm workspace, selected sender target, session source, and result ids. |

## Canonical Operating Pattern

1. Classify the need: saved session, managed browser/DOM, or LinkedIn browser
   adapter.
2. If the task is explicit URL capture or public/internal web extraction, leave
   this file and use `web.md`.
3. If the task is Clay execution, leave the host-browser surface and use
   `vf.clay.*`. For Crunchbase execution, open its provider reference.
4. Check Chrome/session readiness.
5. Run the narrowest host call that can produce the needed evidence.
6. Preserve handles: session name, `session_id`, action id, host job id, output
   path or hosted artifact/row handle, row count, and provider-specific ids.
7. Route rows/artifacts to `row_operations.md`, `artifacts_jobs.md`, or
   `workflow_reports.md` before claiming the output is ready.
8. Clear Local action history only after debugging is complete and the useful
   ids or outputs have been recorded elsewhere.

## Core SDK Surfaces

<!-- BEGIN GENERATED: core-sdk-surfaces -->
| Function | Use When | Inputs | Output And Handles To Preserve | Side Effect | Source |
| --- | --- | --- | --- | --- | --- |
| `vf.host.actions.clear` | Use for Verbiflow browser and provider-session workflows through the active host adapter. | <strong>Required</strong>: none<br><strong>Optional</strong>: `provider` (str \| None; optional; default `None`): External provider or host session provider, such as hubspot, linkedin, or crunchbase. | `dict` with count/status for cleared local host/browser action records; hosted audit logs are durable Bridge state. | local | installed SDK: `verbiflow/host.py:1004-1016` |
| `vf.host.actions.list` | Use for Verbiflow browser and provider-session workflows through the active host adapter. | <strong>Required</strong>: none<br><strong>Optional</strong>: `limit` (int; optional; default `50`): Maximum number of records, preview rows, or results to request.; `provider` (str \| None; optional; default `None`): External provider or host session provider, such as hubspot, linkedin, or crunchbase.; `status` (str \| None; optional; default `None`): Status filter for list/action reads. | `dict` list of recorded host/browser actions from local SQLite or hosted Bridge audit state. | read | installed SDK: `verbiflow/host.py:972-1002` |
| `vf.host.chrome.applescript` | Use for Verbiflow browser and provider-session workflows through the active host adapter. | <strong>Required</strong>: `script` (str; required): AppleScript source to execute locally.<br><strong>Optional</strong>: `timeout_ms` (int; optional; default `30000`): Maximum milliseconds the local host command may run before it is terminated. | `dict` with AppleScript exit status, stdout/stderr, executed script summary, and local action id. | host_local | installed SDK: `verbiflow/host.py:113-125` |
| `vf.host.chrome.network_log` | Use when debugging browser-backed workflows that need recent fetch/XHR/resource timing evidence. | <strong>Required</strong>: none<br><strong>Optional</strong>: `action` (start \| drain \| reset; optional; default `'drain'`): Operation mode for this adapter call.; `filter` (str \| None; optional; default `None`): Text or URL substring used to filter captured host network entries.; `host_match` (str \| None; optional; default `None`): Hostname or URL substring used to find the existing Chrome tab to operate on.; `max_body_chars` (int; optional; default `8000`): Maximum response body characters retained per captured network entry.; `record_headers` (bool; optional; default `False`): Whether captured network entries should include request/response headers.; `url` (str \| None; optional; default `None`): URL to parse, open, focus, fetch, or operate on. | `dict` with captured network/resource entries, target tab/session metadata, timing/body/header fields, runtime, and action/session metadata. | host_local | installed SDK: `verbiflow/host.py:192-243` |
| `vf.host.chrome.run` | Use for a focused JavaScript read/action in an existing or opened Chrome tab. | <strong>Required</strong>: `javascript` (str; required): JavaScript source to execute inside the selected Chrome tab.<br><strong>Optional</strong>: `format` (html \| markdown \| both \| json; optional; default `'json'`): Output format requested from the browser adapter.; `host_match` (str \| None; optional; default `None`): Hostname or URL substring used to find the existing Chrome tab to operate on.; `incognito` (bool; optional; default `False`): Whether the Chrome operation should use/open an incognito context when supported.; `url` (str \| None; optional; default `None`): URL to parse, open, focus, fetch, or operate on. | `dict` with selected browser tab/session metadata, JavaScript result in requested format, errors when present, and runtime/action metadata. | host_local | installed SDK: `verbiflow/host.py:127-187` |
| `vf.host.chrome.status` | Use for Verbiflow browser and provider-session workflows through the active host adapter. | No inputs. | `chrome_status` payload returned by the SDK operation. Inspect the documented function reference and `raw`/dictionary fields when debugging provider-specific data.<br><strong>Common next calls</strong>: `vf.host.chrome.run`, `vf.host.sessions.list` | host_local | installed SDK: `verbiflow/host.py:79-111` |
| `vf.host.linkedin_browser.connect_from_browser_cookies` | Use to create or validate LinkedIn browser setup through the active host adapter. | <strong>Required</strong>: none<br><strong>Optional</strong>: `country_code` (str \| None; optional; default `None`): Country code parameter for `host.linkedin_browser.connect_from_browser_cookies`.; `name` (string; optional): Alias for session_name.; `sender_id` (str \| None; optional; default `None`): Verbiflow sender/mailbox identity id.; `session_name` (str \| None; optional; default `None`): Local host session name stored in the SDK SQLite state DB.; `session_path` (str \| None; optional; default `None`): Absolute local filesystem path. | `dict` with LinkedIn sender connection status, sender id when created, redacted cookie/session metadata, and validation state. | platform_write | installed SDK: `verbiflow/host.py:443-495` |
| `vf.host.linkedin_browser.get_messages` | Use to read a LinkedIn browser thread's messages from the intended logged-in local or hosted browser session. | <strong>Required</strong>: `thread_id` (str; required): LinkedIn messaging thread/conversation id.<br><strong>Optional</strong>: `session_id` (str \| None; optional; default `None`): Local host/browser session id. | `dict` with LinkedIn thread id, message rows, participants, timestamps, and local action metadata. | host_local | installed SDK: `verbiflow/host.py:281-301` |
| `vf.host.linkedin_browser.list_sessions` | Use to list available LinkedIn browser sessions before thread or post reads. | No inputs. | `dict` with live Chrome LinkedIn tab sessions or hosted LinkedIn Browser Use profile/session records, opaque session ids, URLs/titles/status, and targeting guidance for follow-up browser calls. | host_local | installed SDK: `verbiflow/host.py:252-264` |
| `vf.host.linkedin_browser.list_threads` | Use to list LinkedIn browser inbox threads for a saved local or hosted LinkedIn browser session. | No inputs. | `dict` with LinkedIn inbox thread rows, participants, unread/status metadata, and local action metadata. | host_local | installed SDK: `verbiflow/host.py:266-279` |
| `vf.host.linkedin_browser.scrape_visible_feed` | Use for live rendered LinkedIn feed extraction where backend `vf.linkedin.*` is insufficient. | <strong>Required</strong>: none<br><strong>Optional</strong>: `host_match` (str \| None; optional; default `None`): Hostname or URL substring used to find the existing Chrome tab to operate on.; `include_content` (bool; optional; default `False`): Whether browser scraping should include post/comment text content.; `lite_mode` (bool; optional; default `False`): Use a smaller browser scrape payload for speed and lower token volume.; `scroll_rounds` (int; optional; default `20`): Number of browser scroll passes for feed/post scraping.; `target_url` (str; optional; default `'https://www.linkedin.com/feed/'`): URL the browser adapter should open or focus before scraping.; `url` (str \| None; optional; default `None`): URL to parse, open, focus, fetch, or operate on.; `wait` (bool; optional; default `False`): If false, return immediately with a job/status handle; if true or a timeout integer, poll until completion or timeout. | `dict` with feed scrape action id, captured post rows, scroll/status metadata, and latest saved result id. | host_local | installed SDK: `verbiflow/host.py:303-402` |
| `vf.host.linkedin_browser.scrape_visible_feed_status` | Use to inspect the latest live LinkedIn feed scrape status and captured rows. | <strong>Required</strong>: `job_id` (str; required): Local host feed-scrape job id returned by `vf.host.linkedin_browser.scrape_visible_feed(...)`.<br><strong>Optional</strong>: `include_pages` (bool; optional; default `True`): Whether status output should include captured page summaries. | `dict` with feed scrape status, finished/failed flags, captured row counts, and saved result references. | host_local | installed SDK: `verbiflow/host.py:404-441` |
| `vf.host.sessions.capture` | Use once to save or create a reusable redacted provider session through the active host adapter. | <strong>Required</strong>: `provider` (linkedin \| crunchbase; required): External provider or host session provider, such as hubspot, linkedin, or crunchbase.<br><strong>Optional</strong>: `browser` (auto \| chrome \| safari; optional; default `'auto'`): Browser source for host session capture. Use auto unless debugging a specific browser.; `chrome_profile` (str \| None; optional; default `None`): Chrome profile name or path to inspect for provider cookies.; `name` (str \| None; optional; default `None`): Name for the SDK profile, host session, provider query, or created platform resource.; `overwrite` (bool; optional; default `True`): Whether capture/save should replace an existing local host session with the same name. | `dict` with redacted local host session or hosted Browser Use profile metadata, validation status, provider, browser/runtime, and session name/id.<br><strong>Common next calls</strong>: `vf.host.sessions.list` | local | installed SDK: `verbiflow/host.py:779-835` |
| `vf.host.sessions.delete` | Use to remove a stale or unwanted saved host provider session/profile. | <strong>Required</strong>: `name` (str; required): Name for the SDK profile, host session, provider query, or created platform resource.; `provider` (str; required): External provider or host session provider, such as hubspot, linkedin, or crunchbase.<br><strong>Optional</strong>: none | `dict` confirming deletion/disconnection of a host session or hosted Browser Use profile. | local | installed SDK: `verbiflow/host.py:872-889` |
| `vf.host.sessions.get` | Use to inspect one redacted saved host session/profile before using it in provider adapters. | <strong>Required</strong>: `name` (str; required): Name for the SDK profile, host session, provider query, or created platform resource.; `provider` (str; required): External provider or host session provider, such as hubspot, linkedin, or crunchbase.<br><strong>Optional</strong>: none | `dict` with redacted local host session or hosted Browser Use profile metadata, validation status, provider, browser/runtime, and session name/id. | read | installed SDK: `verbiflow/host.py:853-870` |
| `vf.host.sessions.list` | Use to list redacted saved host sessions/profiles and choose the session name/id for adapters. | <strong>Required</strong>: none<br><strong>Optional</strong>: `provider` (str \| None; optional; default `None`): External provider or host session provider, such as hubspot, linkedin, or crunchbase. | `dict` list of redacted local host sessions or hosted Browser Use profiles, never raw cookies/secrets. | read | installed SDK: `verbiflow/host.py:837-851` |
| `vf.host.sessions.refresh` | Use when a saved LinkedIn/Crunchbase browser session/profile is stale. | <strong>Required</strong>: `provider` (linkedin \| crunchbase; required): External provider or host session provider, such as hubspot, linkedin, or crunchbase.<br><strong>Optional</strong>: `name` (str; optional; default `'default'`): Name for the SDK profile, host session, provider query, or created platform resource. | `dict` with redacted local host session or hosted Browser Use profile metadata, validation status, provider, browser/runtime, and session name/id.<br><strong>Common next calls</strong>: `vf.host.sessions.validate` | local | installed SDK: `verbiflow/host.py:925-965` |
| `vf.host.sessions.validate` | Use before a provider host adapter call to confirm the saved session is still usable. | <strong>Required</strong>: `provider` (str; required): External provider or host session provider, such as hubspot, linkedin, or crunchbase.<br><strong>Optional</strong>: `name` (str; optional; default `'default'`): Name for the SDK profile, host session, provider query, or created platform resource. | `dict` with redacted local host session or hosted Browser Use profile metadata, validation status, provider, browser/runtime, and session name/id. | host_local | installed SDK: `verbiflow/host.py:891-923` |
<!-- END GENERATED: core-sdk-surfaces -->

## Data Contracts

### Saved Sessions

Saved sessions return redacted metadata, not raw cookies. Preserve:

- `provider`;
- `name`;
- `validation_status`;
- `secret_keys`;
- `storage_kind`;
- `browser` and profile hints when present;
- `updated_at` or validation timestamps when present.

Never print or store raw cookie values outside the SDK-owned encrypted state.

### Chrome And Network Actions

For Chrome actions and network logs, preserve:

- selected URL or `host_match`;
- requested output `format`;
- returned structured result;
- captured `entries` for network drains;
- errors/stdout/stderr when debugging host failures.

Use `vf.host.chrome.network_log(action="start", ...)`, perform the browser
action, then call `vf.host.chrome.network_log(action="drain", ...)`. It can miss
requests that happened before the recorder was installed.

### LinkedIn Browser

For LinkedIn browser sessions, the identifiers returned by
`vf.host.linkedin_browser.list_sessions(...)` are runtime-scoped.
Locally the
opaque `session_id` is shaped like `chrome:<window>:<tab>` and is only
meaningful on the same machine/session, so preserve it for follow-up calls.

For feed scrapes, preserve:

- `job_id`;
- `poll_with`;
- `status`;
- `pages`;
- `people_count`;
- `interactions_count`;
- captured post/interaction rows;
- `target_url`, `window_id`, and `tab_id` when present.

`scrape_visible_feed(...)` opens a dedicated LinkedIn scrape window from
`url`/`target_url`; do not treat `host_match` as proof that it will reuse an
existing tab.

### Host Actions

Host action rows are local debug/audit records. Preserve:

- action id when present;
- `provider`;
- `session_name`;
- `action_kind`;
- `status`;
- metadata;
- timestamps.

They are not durable workspace audit state. Workflow artifacts, reports, and
backend snapshots are the durable record.

## Examples

### Capture And Validate A Session

```python
import verbiflow as vf

vf.auth.ensure_logged_in()
print(vf.host.chrome.status())

session = vf.host.sessions.capture(provider="linkedin", browser="auto", name="default")
validated = vf.host.sessions.validate(provider="linkedin", name=str(session["name"]))
print(validated["provider"], validated["name"], validated["validation_status"])
```

### Scrape Visible LinkedIn Feed Rows From The Browser Adapter

```python
import verbiflow as vf

sessions = vf.host.linkedin_browser.list_sessions()
print(sessions.get("sessions", [])[:3])

job = vf.host.linkedin_browser.scrape_visible_feed(
    target_url="https://www.linkedin.com/feed/",
    scroll_rounds=5,
    include_content=True,
    wait=False,
)
status = vf.host.linkedin_browser.scrape_visible_feed_status(str(job["job_id"]))
print(status.get("status"), status.get("people_count"), status.get("interactions_count"))
```

### Capture Existing-Tab Network Evidence

```python
import verbiflow as vf

vf.host.chrome.network_log(action="start", host_match="linkedin.com")
# Perform the UI action in Chrome, or use a narrow vf.host.chrome.run(...) call.
entries = vf.host.chrome.network_log(action="drain", host_match="linkedin.com")
print(len(entries.get("entries", [])))
```

## Verification

- The selected reference matches the task boundary: browser/session work here;
  explicit URL page capture in `web.md`; Clay Public API and Crunchbase work in
  their provider refs.
- `vf.host.chrome.status()` was checked before Local Chrome or AppleScript work.
- Saved sessions were listed or validated when reused.
- Platform-writing host calls, especially LinkedIn cookie connection, were
  explicit and printed workspace/provider/sender ids.
- Browser evidence includes enough handles to reproduce or debug it:
  `session_id`, action id, `job_id`, output path, row count, and sample rows.
- Sensitive cookie values were not printed.
- Any result used downstream was routed through row/artifact/report validation,
  not treated as correct only because the host call returned.

## Troubleshooting

| Symptom | Likely Cause | Fix |
| --- | --- | --- |
| Chrome status says unavailable | Chrome, AppleScript, or the host runtime is unavailable. | Use a machine with local browser access or switch to Bridge-backed `vf.web.*` / provider SDK calls. |
| Saved session validates as invalid | Cookie/session expired or was captured from the wrong browser/profile. | Refresh or recapture with the intended browser/profile and explicit session name. |
| LinkedIn browser call targets the wrong tab | `session_id` was omitted or came from a stale local Chrome tab list. | Call `vf.host.linkedin_browser.list_sessions()` again and pass the selected `session_id` where supported. |
| Feed scrape already running | Only one local LinkedIn feed scrape job is active for this SDK process. | Poll the existing `job_id` with `scrape_visible_feed_status(...)` or wait for it to finish. |
| Network log is missing early page-load bodies | Chrome recorder was installed after the page loaded. | Use `web.md` and `vf.host.web.capture_pages(..., network_log=True)` when explicit URL page-load capture is the real need. |
| Clay task needs exact provider behavior | `host_browser.md` has no Clay surface. | Use `vf.clay.*` and `clay.md`; no session preflight exists. |
| Crunchbase task needs exact provider behavior | `host_browser.md` is only session/browser infrastructure. | Use `crunchbase.md` after its documented preflight. |

## Related References

| If You Are Doing This | Read Next |
| --- | --- |
| Bridge-backed web search/page extraction or explicit-URL capture, screenshots, markdown/html, page-load network logs, and browser-runtime tuning | `web.md` |
| Backend LinkedIn research, relationship reads, chat history, sends, post publishing, or send status | `linkedin.md` |
| Clay Public API people/company searches | `clay.md` |
| Crunchbase connect, entity resolution, and company search workflows | `crunchbase.md` |
| Row shaping, dedupe, qualification, or variable coverage after host rows exist | `row_operations.md` |
| Durable jobs/artifacts, artifact paging/export, or staging artifact rows | `artifacts_jobs.md` |
| Workflow report/Play UI evidence output | `workflow_reports.md` |
| Customer-visible mutations, send/publish/purchase approval boundaries | `safety.md` |
