# Crunchbase

<!-- 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. | 28-46 |
| [Use This When](#use-this-when) | Tasks and conditions that belong in this guide. | 47-57 |
| [Do Not Use This For](#do-not-use-this-for) | Boundaries and the correct routes for excluded work. | 58-68 |
| [Mental Model](#mental-model) | Concepts and state boundaries needed for correct operation. | 69-75 |
| [Count First, Then Search](#count-first-then-search) | Always count before the full search. | 76-127 |
| [Provider Pagination Contracts](#provider-pagination-contracts) | Local host-browser `vf.host.crunchbase.search_companies(**filters)` can use `pages` because it drives the operator's browser session directly. | 128-153 |
| [Preflight](#preflight) | State, authority, inputs, and readiness to verify before execution. | 154-164 |
| [Risk And Side Effects](#risk-and-side-effects) | Effects, approvals, cost, privacy, and retry boundaries. | 165-174 |
| [Canonical Operating Pattern](#canonical-operating-pattern) | The normal end-to-end execution sequence. | 175-188 |
| [Core SDK Surfaces](#core-sdk-surfaces) | Exact source-backed callable contracts owned by this guide. | 189-203 |
| [Data Contracts](#data-contracts) | Required identities, fields, evidence, handles, and durable shapes. | 204-215 |
| [Examples](#examples) | Representative usage patterns and code. | 216-231 |
| [Verification](#verification) | Evidence required before reporting success. | 232-239 |
| [Troubleshooting](#troubleshooting) | Failure diagnosis and corrective routes. | 240-384 |
| [Related References](#related-references) | Adjacent boundaries and when to cross them. | 385-394 |
<!-- END GENERATED: guide-map -->

## Purpose

Use this reference for Crunchbase-specific company search workflows. Hosted
`vf.crunchbase.*` calls use Flage's managed pool of ready Pro accounts; users
never connect, select, or inspect those accounts. Use `vf.funding.*` for
structured recent funding discovery through the same pool.
In Local SDK sessions, use `vf.host.crunchbase.*` when you
need the operator's real Chrome session for connection checks, entity
resolution, or local browser-backed pagination.

Managed pool capacity is bounded. Hosted calls can return
`crunchbase_pool_busy` when eligible leases are in use or
`crunchbase_pool_unavailable` when no ready Pro account exists.

The service owns account readiness, bounded account-correlated failover, and
credential isolation. Treat Crunchbase rows as source evidence that
can feed enrichment, row operations, reports, or sequence staging, but keep
those downstream steps in their owning references.

## Use This When

- A run needs hosted Crunchbase-specific search through the managed Pro pool.
- The user asks to validate or connect a local Crunchbase browser session.
- Company, investor, category, category-group, or location names need
  Crunchbase entity resolution before search.
- The task needs a Crunchbase company search with filters such as location,
  industry, category, funding, employee size, investor, or operating status.
- Crunchbase search results should be preserved as source evidence in a
  repeatable workflow or report.

## Do Not Use This For

| Need | Use Instead | Why |
| --- | --- | --- |
| Structured recent funding discovery | `funding.md` | Funding owns the date, round, location, qualification, and evidence contract. |
| Generic web search or page extraction | `web.md` | Web owns provider-neutral public search/page extraction. |
| Browser/session capture and host diagnostics outside Crunchbase | `host_browser.md` | Host browser owns provider-session and managed-browser infrastructure. |
| Company/contact enrichment after Crunchbase rows exist | `enrichment.md` | Enrichment owns canonical factual fields and resolver contracts. |
| Row transforms, joins, qualification, or mapping | `row_operations.md` | Row operations owns deterministic local row work. |
| Sequence staging, publish, or activation | `sequences.md`, `safety.md` | Crunchbase supplies evidence; sequence lifecycle owns audience mutation. |

## Mental Model

Crunchbase has a hard provider pagination ceiling. A broad query can look
successful while silently hiding most of the population. The correct shape is:
resolve entities first, search with narrow true filters, inspect result counts,
then split broad populations into chunks that stay below provider limits.

## Count First, Then Search

Always count before the full search.
Call `vf.host.crunchbase.count_companies(**filters)` before
`vf.host.crunchbase.search_companies(**filters, limit=..., after_id=...)`.
`count_companies` strips `limit`/`after_id` before delegating, so they never
act as filter criteria. The count call issues
one minimal Crunchbase request (limit=1) and returns `provider_count`,
`next_cursor`, and the raw provider search response. It costs the agent roughly
one provider request; the full search can cost minutes of browser-backed
pagination plus CSV shaping. Showing the user the provider count before
committing to the full pull means they can:

- approve a sane-size run instead of an 8000-row surprise,
- see immediately whether the query needs chunking by comparing
  `provider_count` with Crunchbase's roughly 1,000-row pagination ceiling,
- catch a too-broad filter before any meaningful spend.

Pass the same filter criteria to both calls. `limit`/`after_id` are pagination
controls for `search_companies`, not filters, and `count_companies` ignores
them. Hosted filters use Crunchbase provider UUIDs. Resolve human names with
the matching collection before counting or searching. Do not pass human aliases
such as `locations`, `industries`, `category_groups`, or `investors` to hosted
`vf.crunchbase.search_companies`. Use `vf.funding.discover_companies(...)` when
funding date, round, and human location names define the requested universe.

Example:

```python
import verbiflow as vf

location_resolution = vf.crunchbase.resolve_entities(
    ["United States"],
    collection="locations",
)
category_resolution = vf.crunchbase.resolve_entities(
    ["SaaS"],
    collection="category_groups",
)
filters = dict(
    location_uuids=[row["uuid"] for row in location_resolution["matched"]],
    category_group_uuids=[row["uuid"] for row in category_resolution["matched"]],
    last_funding_after="2026-01-01",
    last_funding_types=["seed", "series_a", "series_b"],
    operating_statuses=["active"],
)
preview = vf.crunchbase.count_companies(filters)
print(preview["provider_count"], preview["next_cursor"])
# → user confirms, then:
results = vf.crunchbase.search_companies(filters, limit=100)
```

## Provider Pagination Contracts


Local host-browser `vf.host.crunchbase.search_companies(**filters)` can use
`pages` because it drives the operator's browser session directly. Crunchbase
does not bill per page or per row — pulling 1000 rows costs the same as pulling
50. Do not pass `pages=5` (or any small number) to "save credits" or "be
conservative". The local adapter already caps a single call at 20 pages = 1000
rows = the provider ceiling, so the default behavior is the right behavior.

- **Local default**: omit `pages` (or pass `pages=-1`) on
  `vf.host.crunchbase.search_companies(...)`. The local SDK pulls every matching
  page up to the provider cap.
- **Probe only**: hosted code uses `vf.crunchbase.count_companies(filters)`;
  local host-browser code uses `vf.host.crunchbase.count_companies(**filters)`.
  Use local `search_companies(..., pages=1)` only when you also need a row
  sample.
- **Never** call local `search_companies(..., pages=5)` and present 250 rows as
  the answer to a query that has 8,000 matches. That silently throws away
  coverage.

After every managed-pool search, check `provider_count`, returned `count`, and
`next_cursor`. If `provider_count` is above the Crunchbase pagination ceiling or
`next_cursor` is still present after your page budget, chunk and re-run per the
troubleshooting section below.

## Preflight

1. Verify SDK auth/workspace with `vf.auth.status()` or `vf.session.init()`.
2. Validate the Local Crunchbase browser session with
   `vf.host.crunchbase.connect(...)`.
3. Resolve obscure names, categories, investors, and locations before building
   deep company-search filters.
4. Define the exact row fields and downstream handoff before searching.
5. Bound `pages` and chunk filters so provider caps do not silently truncate
   coverage.

## Risk And Side Effects

| Operation | Risk | Rule |
| --- | --- | --- |
| `vf.crunchbase.search_companies(...)` | Provider read through the Flage-managed Crunchbase Pro pool | Inspect row counts. Retry retryable capacity failures; never request account credentials. |
| `vf.host.crunchbase.connect(...)` | Local/browser validation plus platform-visible session metadata | Print status and local action id. |
| `vf.host.crunchbase.resolve_entities(...)` | Provider read through local session | Preserve resolved ids, URLs, confidence, and unresolved names. |
| `vf.host.crunchbase.search_companies(...)` | Provider read through local session | Bound pages/limit, inspect row counts, and chunk any cap-hit population. |
| Downstream enrichment, reports, or sequence staging | Separate side-effect classes | Leave this file for the owning reference before mutating state or publishing. |

## Canonical Operating Pattern

1. Use `vf.host.crunchbase.count_companies/search_companies` and connect or
   validate the Local Crunchbase session.
2. Use Local page-budget controls only as documented below.
3. Resolve filter entities where names are ambiguous.
4. Run the narrowest true company search.
5. Inspect `row_count`, pagination fields, cap warnings, and sample rows.
6. If the query is too broad, split by funding stage/range, founded year,
   headcount, geography, category, or another real filter.
7. Preserve Crunchbase ids/URLs/domains before joining with enrichment or CRM.
8. Hand rows to `row_operations.md`, `enrichment.md`, `workflow_reports.md`, or
   `sequences.md` only after provider coverage is understood.

## Core SDK Surfaces

<!-- BEGIN GENERATED: core-sdk-surfaces -->
| Function | Use When | Inputs | Output And Handles To Preserve | Side Effect | Source |
| --- | --- | --- | --- | --- | --- |
| `vf.crunchbase.count_companies` | Use Flage's managed Crunchbase Pro pool to count companies matching a provider filter. | <strong>Required</strong>: `filters` (Mapping[str, object]; required): Exact Crunchbase provider filters. Geography, category, industry, and investor filters use UUIDs returned by crunchbase.resolve_entities.<br><strong>Optional</strong>: none | `dict` with `provider_count`, `next_cursor`, and `raw` hosted Crunchbase search response fields. Use `provider_count` as the provider-reported population size. | provider_call | installed SDK: `verbiflow/crunchbase.py:115-140` |
| `vf.crunchbase.iter_companies` | Iterate Crunchbase company matches across opaque cursor pages. | <strong>Required</strong>: `filters` (Mapping[str, object]; required): Exact Crunchbase provider filters. Geography, category, industry, and investor filters use UUIDs returned by crunchbase.resolve_entities.<br><strong>Optional</strong>: `max_results` (int \| None; optional; default `None`): Max results parameter for `crunchbase.iter_companies`.; `page_size` (int; optional; default `100`): Number of rows/results per page. | `crunchbase_company_stream` 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.crunchbase.search_companies` | provider_call | installed SDK: `verbiflow/crunchbase.py:204-251` |
| `vf.crunchbase.resolve_entities` | Resolve human Crunchbase category, company, investor, or location names to provider UUIDs through Flage's managed Pro account pool. | <strong>Required</strong>: `collection` (categories \| category_groups \| locations \| organization.companies \| principal.investors; required): Allowed values: categories, category_groups, locations, organization.companies, principal.investors.; `names` (Sequence[str]; required): Names parameter for `crunchbase.resolve_entities`.<br><strong>Optional</strong>: `limit` (int; optional; default `10`): Maximum number of records, preview rows, or results to request. | `crunchbase_entity_resolution` 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.crunchbase.search_companies`, `vf.crunchbase.count_companies` | provider_call | installed SDK: `verbiflow/crunchbase.py:142-202` |
| `vf.crunchbase.search_companies` | Use Flage's managed Crunchbase Pro pool to search companies with bounded pagination. | <strong>Required</strong>: `filters` (Mapping[str, object]; required): Exact Crunchbase provider filters. Geography, category, industry, and investor filters use UUIDs returned by crunchbase.resolve_entities.<br><strong>Optional</strong>: `after_id` (str \| None; optional; default `None`): Crunchbase pagination cursor returned as `next_cursor`; pass it to fetch the next company-search page.; `limit` (int; optional; default `25`): Maximum number of records, preview rows, or results to request. | `dict` with Crunchbase hosted search rows, CSV text, sample rows, provider count, pagination cursor, and an opaque managed-pool descriptor. | provider_call | installed SDK: `verbiflow/crunchbase.py:84-113` |
| `vf.host.crunchbase.connect` | Use to validate and record a local Crunchbase browser session. | <strong>Required</strong>: none<br><strong>Optional</strong>: `auto_fix_chrome` (bool; optional; default `True`): When true, attempt the local Chrome Apple Events policy fix when browser automation is disabled.; `open_if_missing` (bool; optional; default `True`): When true, open or focus Crunchbase in local Chrome before validating the session. | `dict` with Crunchbase session validation status, browser/profile metadata, user/org hints, and local action id. | platform_write | installed SDK: `verbiflow/host.py:575-646` |
| `vf.host.crunchbase.count_companies` | Use for Verbiflow browser and provider-session workflows through the active host adapter. | <strong>Required</strong>: none<br><strong>Optional</strong>: `category_group_uuids` (array; optional): Category group uuids parameter for `host.crunchbase.count_companies`.; `category_groups` (array; optional): Category groups parameter for `host.crunchbase.count_companies`.; `company_types` (array; optional): Company types parameter for `host.crunchbase.count_companies`.; `employee_sizes` (array; optional): Employee sizes parameter for `host.crunchbase.count_companies`.; `funding_total_max` (number; optional): Funding total max parameter for `host.crunchbase.count_companies`.; `funding_total_min` (number; optional): Funding total min parameter for `host.crunchbase.count_companies`.; `industries` (array; optional): Industries parameter for `host.crunchbase.count_companies`.; `industry_uuids` (array; optional): Industry uuids parameter for `host.crunchbase.count_companies`.; `investor_uuids` (array; optional): Investor uuids parameter for `host.crunchbase.count_companies`.; `investors` (array; optional): Investors parameter for `host.crunchbase.count_companies`.; `label` (string; optional): Label parameter for `host.crunchbase.count_companies`.; `last_funding_after` (string; optional): Last funding after parameter for `host.crunchbase.count_companies`.; `last_funding_before` (string; optional): Last funding before parameter for `host.crunchbase.count_companies`.; `last_funding_total_max` (number; optional): Last funding total max parameter for `host.crunchbase.count_companies`.; `last_funding_total_min` (number; optional): Last funding total min parameter for `host.crunchbase.count_companies`.; `last_funding_types` (array; optional): Last funding types parameter for `host.crunchbase.count_companies`.; `location_uuids` (array; optional): Location uuids parameter for `host.crunchbase.count_companies`.; `locations` (array; optional): Locations to constrain people/company search.; `operating_statuses` (array; optional): Operating statuses parameter for `host.crunchbase.count_companies`. | `dict` with host adapter status, provider-specific payload, stdout/stderr or parsed browser result, runtime metadata, and action/session metadata. | provider_call | installed SDK: `verbiflow/host.py:728-772` |
| `vf.host.crunchbase.resolve_entities` | Use to resolve company/investor names or domains through local Crunchbase access. | <strong>Required</strong>: `names` (array; required): Company, investor, category, or location names to resolve into Crunchbase entity ids.<br><strong>Optional</strong>: `collection` (string; optional): Crunchbase entity collection to resolve against, such as categories, category_groups, locations, or principal.investors.; `limit` (integer; optional): Maximum number of records, preview rows, or results to request. | `dict` with resolved Crunchbase entities, ids/URLs/domains, confidence/provenance, and local action metadata. | provider_call | installed SDK: `verbiflow/host.py:648-683` |
| `vf.host.crunchbase.search_companies` | Use to search Crunchbase companies with local browser-backed state. | <strong>Required</strong>: none<br><strong>Optional</strong>: `after_id` (string; optional): Crunchbase pagination cursor from a previous search result.; `category_group_uuids` (array; optional): Pre-resolved Crunchbase category group UUIDs for company search.; `category_groups` (array; optional): Human-readable Crunchbase category groups to resolve before company search.; `company_types` (array; optional): Crunchbase company-search filter values for company types.; `employee_sizes` (array; optional): Crunchbase company-search filter values for employee sizes.; `funding_total_max` (number; optional): Maximum numeric Crunchbase company-search bound for funding total.; `funding_total_min` (number; optional): Minimum numeric Crunchbase company-search bound for funding total.; `industries` (array; optional): Human-readable Crunchbase industries to resolve before company search.; `industry_uuids` (array; optional): Pre-resolved Crunchbase industry UUIDs for company search.; `investor_uuids` (array; optional): Pre-resolved Crunchbase investor UUIDs for company search.; `investors` (array; optional): Human-readable Crunchbase investors to resolve before company search.; `job_id` (string; optional): Backend job id returned by a start/search/enrichment/qualification call.; `label` (string; optional): Local CSV/result label used for the saved Crunchbase output file.; `last_funding_after` (string; optional): Crunchbase company-search date filter in ISO-like date format.; `last_funding_before` (string; optional): Crunchbase company-search date filter in ISO-like date format.; `last_funding_total_max` (number; optional): Maximum numeric Crunchbase company-search bound for last funding total.; `last_funding_total_min` (number; optional): Minimum numeric Crunchbase company-search bound for last funding total.; `last_funding_types` (array; optional): Crunchbase company-search filter values for last funding types.; `limit` (integer; optional): Maximum number of records, preview rows, or results to request.; `location_uuids` (array; optional): Pre-resolved Crunchbase location UUIDs for company search.; `locations` (array; optional): Human-readable Crunchbase locations to resolve before company search.; `operating_statuses` (array; optional): Crunchbase company-search filter values for operating statuses.; `pages` (integer; optional): Maximum Crunchbase result pages to fetch; SDK caps this for provider safety.; `sleep_ms` (integer; optional): Milliseconds to wait between Crunchbase page requests. | `dict` with Crunchbase company search rows, applied filters, pagination/status, and local action metadata. The hosted adapter delegates to `vf.crunchbase.search_companies` through Flage's managed Pro pool. | provider_call | installed SDK: `verbiflow/host.py:685-726` |
<!-- END GENERATED: core-sdk-surfaces -->

## Data Contracts

| Field | Meaning |
| --- | --- |
| `names` | Entity names or domains to resolve before search. |
| `category_groups`, `industries`, `locations`, `investors` | Human-readable filters that may need resolution before search. |
| `*_uuids` | Pre-resolved Crunchbase ids for exact filtering. |
| `after_id` | Provider pagination cursor from a previous search page. |
| `provider_count` | Provider-reported population size for managed `vf.crunchbase.*` calls. Use this to decide whether chunking is required. |
| `count`, `sample`, `csv_text`, `next_cursor` | Managed search output shape to preserve before handing rows to downstream steps. |
| `row_count`, `pages_fetched`, `pages_requested`, `next_cursor` | Local host-browser coverage and pagination signals to inspect before claiming completeness. |

## Examples

```python
import verbiflow as vf

vf.auth.ensure_logged_in()
results = vf.crunchbase.search_companies(
    {
        "location_uuids": ["<resolved-location-uuid>"],
        "industry_uuids": ["<resolved-industry-uuid>"],
    },
    limit=25,
)
print(results)
```

## Verification

- Connection output indicates a valid Local Crunchbase session.
- Resolved entities include ids/URLs or explicit unresolved rows.
- Search output includes filters, row counts, pagination status, and sample
  companies.
- Broad populations are chunked before the result is used as complete coverage.

## Troubleshooting

### Pagination is capped at 1,000; chunk every query to stay under it

Crunchbase only lets you page through the first roughly 1,000 results of any
search. The UI hits the wall around `951-1,000` and refuses to return rows
past the cap. There is no parameter to override this.

The Local host-browser `vf.host.crunchbase.search_companies(...)` response
reports the cap explicitly. It includes — in this order at the top of the dict,
so the agent reads the headline first:

- `summary`: one-line human-readable string (e.g. `"50 rows pulled · 8,421
  matching · 1 page(s) · stop=no_cursor · ⚠ PROVIDER CAP HIT (8,421 >
  1000): CHUNK & MERGE"`). Skim this first; if it has `⚠`, act on it.
- `warnings`: list of structured warning objects (empty list `[]` when
  clean — always check `if result["warnings"]:`). Each entry has:
  - `code`: `"provider_cap_exceeded"` or `"page_budget_exhausted"`.
  - `severity`: `"high"` (cap exceeded) or `"medium"` (budget exhausted).
  - `message`: human-readable explanation, safe to relay to the user.
  - `action`: `"chunk_and_merge"` or `"resume_or_narrow"`.
  - `suggested_dimensions` (cap warning only): ranked list of filter
    axes to split on first.
  - `total_matching` / `cap` (cap warning) or `pages_fetched` /
    `pages_requested` (budget warning).
- `provider_cap_hit`: `True` when `total_matching > 1000`.
- `total_matching`: population size Crunchbase reports for the query.
- `row_count`: rows actually returned in this call.
- `stop_reason`: `"no_cursor"` (finished naturally), `"pages_reached"`
  (your `pages` budget covered the whole result set), or `"hard_cap"`
  (more pages exist but `pages` ran out — also emits a warning).


When `warnings` is non-empty, do not silently move on. Relay the message
field(s) to the user, then act on the suggested `action`:

- `chunk_and_merge`: do not concatenate a single overflowing search and
  call it complete. Split into chunks where each chunk's `total_matching`
  is below 1,000, then concatenate.
- `resume_or_narrow`: usually prefer narrowing over resuming — the cap
  will bite again past row 1000 anyway.

Useful chunking dimensions:

- Funding date window: split a 6-month range into 6 one-month windows; if
  one month is still over 1000, drop to weekly. Use
  `last_funding_after` / `last_funding_before` (ISO `YYYY-MM-DD`).
- Funding stage: Pre-Seed, Seed, Series A, B, C, late.
- Funding range: `$0-$1M`, `$1M-$5M`, `$5M-$25M`, `$25M-$100M`, `$100M+`.
- Founded year: yearly buckets or bands like `2018-2020`, `2021-2022`.
- Headcount band: `1-10`, `11-50`, `51-200`, `201-1000`, `1001+`.
- Geography: state, metro, or country when one location dominates.
- Category: split a broad category into narrower true categories.


Local host-browser date-window chunking pattern (most common — funding-based
audiences):

```python
from datetime import date
from dateutil.relativedelta import relativedelta  # or hand-roll month math

# User asked: "Series A companies funded in the last 6 months."
# Local discovery call (cheap: pages=1) to learn total_matching:
probe = vf.host.crunchbase.search_companies(
    last_funding_types=["series_a"],
    last_funding_after="2026-01-01",
    last_funding_before="2026-06-30",
    pages=1,
)
if probe["provider_cap_hit"]:
    for w in probe["warnings"]:  # always relay every warning to the user
        print(f"[{w['severity']}] {w['code']}: {w['message']}")
    # Split into 1-month windows. Re-probe a window if it still overflows.
    chunks = []
    cursor_date = date(2026, 1, 1)
    end = date(2026, 6, 30)
    while cursor_date <= end:
        window_end = min(cursor_date + relativedelta(months=1, days=-1), end)
        res = vf.host.crunchbase.search_companies(
            last_funding_types=["series_a"],
            last_funding_after=cursor_date.isoformat(),
            last_funding_before=window_end.isoformat(),
            label=f"series-a-{cursor_date.isoformat()}",
        )
        chunks.append(res)
        cursor_date = window_end + relativedelta(days=1)
    # Merge chunk CSVs and de-dup by Crunchbase uuid before downstream use.
```

Local host-browser pattern:

1. Start with the narrowest true filter set.
2. Probe with `pages=1` to read `total_matching` cheaply.
3. If `result["warnings"]` is non-empty, surface each warning's `message`
   to the user and split into smaller true filter buckets — start with the
   first entry in the warning's `suggested_dimensions` (date windows for
   funding queries, stage for "any-stage" queries, headcount for
   geography-bound queries, etc.).
4. Recurse: if a single bucket still overflows, halve the window again.
5. Merge chunks by Crunchbase uuid (companies dedupe across overlapping
   filter buckets).
6. Inspect `row_count`, `pages_fetched`, `pages_requested`, `stop_reason`,
   `warnings`, and `next_cursor` per chunk before claiming complete coverage.

### Polling search status while a long search runs

A 20-page search can take 30-60 seconds. To watch progress while it
runs (from another shell or a parallel coroutine), pass a `job_id`:

```python
res = vf.host.crunchbase.search_companies(
    last_funding_types=["series_a"],
    job_id="crunchbase-series-a-2026-06",
    pages=10,
)
```

Anywhere else (separate REPL, another agent, monitoring loop) can then poll:

```python
vf.log.status("crunchbase-series-a-2026-06")    # running | succeeded | …
vf.log.progress("crunchbase-series-a-2026-06")  # {done, total, pct, msg}
vf.log.recent("crunchbase-series-a-2026-06", n=20)
for event in vf.log.tail("crunchbase-series-a-2026-06"):
    print(event)
```

The SDK also writes `[crunchbase] INFO …` lines to stderr unconditionally,
so `tail -f` on the calling process's stderr works without a `job_id`.

### Local tab auto-opens; hosted calls never require connect()

`search_companies(...)` and `resolve_entities(...)` both auto-open a
crunchbase.com tab in Chrome if one is missing. You still want to run
`vf.host.crunchbase.connect(...)` once at the start of a session to
verify the user is signed in and capture Pro entitlements, but you do
not need to re-call it before every search.

### Resolve obscure entities before pulling deep fields

`vf.host.crunchbase.search_companies(...)` can return company stubs with no
domain; downstream calls keyed by domain can then drop the row silently. Resolve
entities before joining on domain.

## Related References

| Reference | Use When |
| --- | --- |
| `host_browser.md` | Local browser/session capture, validation, or host action diagnostics. |
| `web.md` | Provider-neutral public search or explicit URL extraction. |
| `enrichment.md` | Canonical company/contact/profile/domain enrichment after Crunchbase source rows exist. |
| `row_operations.md` | Local row transforms, joins, qualification, and mapping. |
| `workflow_reports.md` | Turning Crunchbase source evidence into an inspectable Play report. |
| `sequences.md` | Staging or activating reviewed rows. |
