LAB429/ Cheetah product page ↗

Cheetah / Cheetah documentation

Browser capture runs

Post-command capture enriches one action. The optional browser-capture service coordinates a larger application task: acquire a real browser worker, visit targets, preserve ordered page states, store artifacts, and write a manifest.

It reuses Cheetah commands, identity, policy, worker contexts, client execution, authenticated returns, and history. It does not add a second browser-control protocol or a Playwright dependency.

Authenticated REST surface

create_browser_capture_router() exposes:

  • POST /api/browser-captures/runs;
  • GET /api/browser-captures/runs/{run_id};
  • GET /api/browser-captures/runs/{run_id}/manifest.

The mounting application must supply authenticated_user_dependency. The request body does not accept user_id; the runtime receives the resolved principal separately. A missing auth dependency deliberately returns 500 so an unprotected mount does not appear functional.

An unknown run and a run owned by another principal both return 404. Policy denial returns 403 with the feature policy decision under detail. The policy's details therefore become client-visible data and must be suitable for that boundary. Pydantic request validation uses FastAPI's normal 422; runtime preparation errors exposed as ValueError become 400.

The POST route is synchronous in the current implementation. Its response arrives after the in-process capture attempt has completed or failed. pending and running are valid stored lifecycle states, but the reusable route does not provide a background job queue.

Request contract

{
  "run_label": "product-smoke",
  "targets": [
    {
      "url": "https://example.com/product/42",
      "label": "product",
      "states": [
        {
          "label": "top",
          "scroll_x": 0,
          "scroll_y": 0,
          "settle_strategy": "wait_complete",
          "settle_delay_ms": 5000
        }
      ]
    }
  ],
  "capture": { "screenshot": true, "dom_content": true },
  "requirements": {},
  "max_parallel_targets": 1,
  "auto_provision": false,
  "continue_on_state_error": true
}

targets is required and contains 1-100 entries. Each target needs an absolute HTTP or HTTPS URL and can contain at most 100 ordered states. An empty state list becomes one default state. State coordinates are non-negative. The default settle strategy is wait_complete, and settle_delay_ms defaults to 5,000 with a permitted range of 0-120,000.

Capture defaults both screenshot and DOM to true; at least one must remain true. Requirements are opaque worker-selection hints. auto_provision defaults false. continue_on_state_error defaults true and controls whether later states of the same usable worker are attempted after a state failure.

The outer numeric model accepts up to 32 for max_parallel_targets, but a dedicated validator currently permits exactly 1. Targets therefore execute sequentially. The field reserves the future shape without advertising multi-target scheduling that does not exist.

Unknown fields are rejected throughout the request models.

Worker binding and command reuse

One target stays bound to one acquired browser worker session. The worker navigates once and applies that target's states in request order. This preserves cookies, page memory, and browser state within the real session.

The default adapter uses WorkerContextManager to acquire a browser context and requires an AppNode. Navigation and state capture are normal Cheetah commands. Large capture results are read from the authenticated user's history because RPC completion contains lightweight terminal metadata rather than the full artifacts.

The runtime releases the session in finally on success and handled failures. If the worker is lost during navigation or capture, the affected state fails, remaining states are skipped, and the target is forced to failed. The runtime does not continue that target on another browser and pretend the previous page state survived.

Run, target, and state status

The run record stores run_id, authenticated user_id, lifecycle status, timestamps, the normalized request, optional manifest and manifest key, and run-level errors.

A run is:

  • completed only when every target completes and there is no run-level error;
  • partial when at least one state completes or a failed state still produced a requested screenshot or DOM artifact;
  • failed when no useful state completed or a run-level error prevented execution.

A target is completed, partial, or failed. A state is completed, failed, or skipped. When requested screenshot or DOM data is absent and the client supplied no capture error, the service creates a stable missing-artifact error instead of silently declaring success.

The manifest fixes schema_version to browser_capture_manifest_v1. It records request counts, target URLs and worker identities, ordered state results, page metadata, artifact references, and structured errors.

Artifact keys and retention

Artifact references are opaque, manifest-relative keys. The local store currently writes:

request.json
manifest.json
targets/<target-index>_<label>/states/<state-index>_<label>/screenshot.png
targets/<target-index>_<label>/states/<state-index>_<label>/dom.html
targets/<target-index>_<label>/states/<state-index>_<label>/meta.json

Labels are sanitized before entering path segments. Consumers should still resolve keys through the configured artifact store rather than constructing filesystem paths.

The default run store is in memory, keeps at most 100 records, and expires them after one hour. That lifecycle does not delete artifacts. A process restart can lose the run summary while screenshots, DOM, metadata, and manifests remain on disk.

This is an accepted first-slice limitation. The current service is not a managed-retention or production-ready capture platform. Use disposable storage or an external cleanup policy. A future promotion requires coordinated cleanup across run and artifact stores, active-run protection, crash recovery, durable status, and operator-visible cleanup failures.

The reusable package also does not yet provide a distributed run store, asynchronous queue, artifact-download route, parser artifacts in the run model, or package-facing CLI.

Capture and payloads