# Core X agent operations

> Measured browser identity and explicit agent leases through the same REST, MCP and CLI catalog.

## Available operations

The discovery catalog of the revision you connect to is authoritative. Core X operations cover readiness (`agent.preflight`), profile-scoped console state (`agent.console_get`), leases (`sessions.ensure`, `sessions.agent_attach`, `sessions.lease_release`, `operations.get`), human handoff (`sessions.handoff_request`, `sessions.handoff_resume`), measured identity (`profiles.effective_fingerprint`, `profiles.consistency_report`), persona creation (`personas.contexts_list`, `profiles.create_from_context`), drift (`profiles.drift_list`, `profiles.drift_accept`), noise (`profiles.noise_status`, `profiles.noise_upgrade`), exit diagnostics (`profiles.exit_diagnostics`), host health/provisioning (`workers.health_get`, `workers.provision_preview`, `workers.provision_run`) and core delivery (`core.freshness_get`, `workers.core_channel_set`). Each reference is generated from the same input/output contract. MCP names replace dots with underscores; the CLI uses `browlix call <operation> key=value --json`. The SDK uses the same catalog, not a separate database connection.

An agent lease reservation is **not** a CDP ticket. Existing `sessions.attach` still issues the same-machine CDP ticket; `sessions.agent_attach` reserves the reader/writer lease. Writer mode also requires `agent.act`. Send the same explicit `idempotency_key` on retries. Ordinary noise/provision commands use `command_id`. Never generate a new retry key after losing a reply.

A measured fingerprint can be null: that means unmeasured, not enforced. Noise upgrade requires `session.start`, a closed profile and `expected_epoch`; drift approval remains required afterwards. Provisioning queues a consented Linux operation, not a completed installation.

## Outcomes and permissions

Agent results preserve `ok`, `operation_id`, `state_version`, `retryable` and `next`. Refusals include `code`, `remediation_key` and `outcome`; REST additionally carries the conventional `error` object for existing clients. `ACTION_OUTCOME_UNKNOWN` returns HTTP 202 and a lookup step: read `operations.get` or resend the **same** retry key. Do not treat 202 as completion. `SESSION_LEASE_HELD`, `SESSION_EPOCH_CHANGED`, `HUMAN_CONTROL_ACTIVE` and `IDEMPOTENCY_KEY_REUSED` are refusals, not reasons to blindly retry. `FORBIDDEN` and `NOT_FOUND` preserve scope boundaries. Revoked keys are refused at request level.

Preflight, handoff, host-health, drift and exit reads are present in the current catalog. Availability is not proof of a completed worker action. Page snapshot/state tools remain unavailable until their worker-backed adapter is integrated; never substitute a null report for a successful observation.

## Feedback

After using tools, report a distinct bug, friction or missing documentation with `feedback_submit`; use `feedback_list`, `feedback_get` and `feedback_comment` to follow up. Include a correlation ID and redacted evidence, never tokens, cookies or credentials. [Agent feedback](https://browlix.com/en/docs/feedback).


## Readiness and human handoff

`agent.preflight` requires `agent.preflight`, not merely `session.read`. A successful response can have `ready=false`; inspect every blocker before starting. Empty, missing or stale measurements are not proof of readiness. The console returns only visible profiles, lease state, operation state and allow-listed budget fields; it never returns request hashes, holder identifiers, stored outcomes or page contents.

Handoff request and resume require explicit `command_id`, `idempotency_key` and the last-read epoch. Retrying retains both keys. `PAUSING` and `RESUME_PENDING` are pending states, not proof of control. Poll the operation and console until signed worker acknowledgement is complete. Returning control currently requires a signed-in human session: an API key is refused with `HUMAN_CONTROL_ACTIVE`, even for its owner. An agent must ask the operator to resume in the console; it cannot forge human verification.

## Persona, drift and host changes

List fresh measured contexts, then use their ID in `profiles.create_from_context`. The database validates that the context belongs to the workspace and is still fresh; never send an invented hardware observation. A drift acceptance identifies an event as well as the profile, preventing a mismatched path from accepting another profile's drift. Noise upgrades require a closed profile and expected epoch. Provisioning preview has no queue side effect; provisioning run requires explicit consent. A queued command means work is accepted, not installed. Stable/beta channel choices remain subject to the core release gate.

## Incomplete observations and recovery

A null fingerprint, health report or exit diagnostic is a successful read of an unmeasured state, not a measured browser result. Page snapshot/state tools are not part of this revision until their worker-backed adapter is integrated. An unknown action outcome remains an error: CLI exit 10, SDK rejection, and an operation lookup next step. Never send a new key to repeat a potentially completed action.

Read-only Core X replies have `operation_id=null`; this is not a fabricated durable receipt. If transport fails before an operation ID arrives, the SDK preserves the explicit `idempotency_key` with `ACTION_OUTCOME_UNKNOWN`. Reconcile by resending that same request, then use the returned operation ID for lookup. Never invent an ID or a new retry key.
