Skip to main content
A probe is a bounded check declared with an integration and run against one installed source. It exercises the source through the integration’s own read-only requests, or through temporary records that the run creates and then removes. Each run reports two results separately: whether its checks passed, and whether its cleanup was verified. A probe never promises that nothing happened: reads can use provider quota and appear in audit logs, and deleting a record can’t undo the provider’s audit entries, notifications or downstream reactions. A run promises a checked result and explicit evidence about every record it created.

Declaring a probe

Declare probes in the integration’s probes factory. It receives the integration’s own requests and commands; only GET and HEAD requests that read from the provider are offered as requests, and never an incremental sync request, which reads with the source’s own sync tokens. List the handles a probe uses in reads and writes. This read-only probe checks that a partner connection still authenticates:
The context p offers:
  • p.read(request, parameters?) sends a declared request and resolves to its HTTP outcome, with status and body.
  • p.check(label, actual, expected) compares two values exactly. A different value fails the run at that check.
  • p.create(resource, args, { remove_args }?) creates a declared temporary record. Its removal arguments are fixed when it is created.
  • p.write(command, resource, args) sends a declared command to a record this run created.
  • p.waitFor(resource, expected, { within_ms }?) waits until the source observes the record with those field values; {} waits for it to exist.
  • p.run_id identifies the run.
Every call is a durable step, named from its kind (read.identity.1, create.account.1) or by the check’s label. Await each call before making the next. A run is replayed from its journal, so run must make the same calls in the same order every time, and it has no direct network access, clock or randomness. Declare inputs with args, as for an operation; the deployment checks them when a run starts.

Temporary records

A probe that declares resources may create records. Each resource names the command that creates it and the command that removes it; both must target the same collection, and that collection must declare key_reuse: "never", meaning the provider never gives a deleted record’s key to another record.
bijection/crm.ts
There is no explicit remove: once the exercise ends, the run removes every record it created, whatever the result. The provider’s own create response identifies the record, so a probe can’t point cleanup at anything else. Cleanup is verified only when the source is observed again without the record; an unknown create or delete outcome never counts as removed. Only a signed-in user can start a probe that creates records, and every command it sends must pass that command’s ordinary governing rule. A run allows at most 64 steps, eight records, a 15-minute exercise and a 24-hour cleanup window. The defaults are 32 steps, two minutes and one hour; change them with limits.

Results

A run’s summary reports its assessment and its cleanup separately, and a phase derived from both: closed doesn’t mean passed: read the assessment and the cleanup. An issue is a typed cause such as binding_changed, source_unavailable, command_refused or code_error (the probe’s own code threw). Infrastructure failures are retried and never become issues. The full report adds each step and record with its status, and the controls you may apply now. It never contains provider payloads, credentials or inputs.

Running probes

From the CLI, list a source’s probes, review one’s plan, run it and inspect the result:
plan prints what the probe may do on that source and its fingerprint; --plan <fingerprint> makes run start only under the plan you reviewed, and --args passes inputs as a JSON object. --wait follows the run for up to five minutes; disconnecting doesn’t cancel it. history <source> [probe] pages through past runs, including probes whose declaration was removed. A request whose response was lost stays in a local journal: pending <source> lists those, retry <run> resends one exactly and discard <run> forgets it. See the CLI reference. From your code, use the probes references generated in _generated/integrations:
start() admits the current plan, or only the one you pass as expected_plan. After a lost response, start again with the same run_id, even from another process. client.probes.attach(run_id) observes any run. wait() returns when the run is closed or its cleanup is blocked; its timeout throws ProbeWaitTimeout and never cancels the run. In a browser, the local journal uses encrypted browser storage; in Node, pass fileRequestStore. Refusals are ConnectionRequestErrors with a code, such as ProbeRunUnfinished: a new run of a probe on a source waits until the last one is closed. In a React app rendered under BijectionProvider, IntegrationProbes lists a source’s probes and runs, starts runs, shows each step and record, and offers the controls the selected run allows:
disabled turns off starting and controlling runs; inspection still works. For your own interface, useProbes({ source_id }) returns the same state and a controller.

Controls

Apply them with cancel, resume-cleanup and abandon-cleanup <run> in the CLI, or cancel(), resumeCleanup() and abandonCleanup() on a run. A control applies to the report you reviewed: if the run changed meanwhile, it’s refused with ProbeRevisionChanged, and retrying a control after a lost response returns its original result. A signed-in user sees and controls only the runs they started, and only while they can still use the source’s connection. Deployment operators see every run (--operator in the CLI); with write permission they can also start read-only probes. Probes can’t be started or controlled from a branch.