Skip to content

Best practices

Updated
Reading time
3 min
Level
intermediate

Design for a system whose execution environment is a browser on a personal computer. Every recommendation here follows from that one fact. An integration that respects it runs unattended for months; one that fights it feels unreliable.

1. Match the workload to the tool

Good fitPoor fit
Batch and scheduled workA chat UI with someone waiting
Background enrichment, summarisation, classificationSub-second interactive features
Content pipelines with a deadline in hoursAnything with a deadline in seconds
Development and prototyping without a billing accountHigh-volume production traffic on one machine

If a person is watching a cursor blink, use a model API. This is not modesty — it is the difference between a happy integration and a support ticket.

2. Prefer asynchronous submission

wait: true is convenient for a script. For anything running unattended, submit with wait: false and a callback_url. It removes your dependency on a connection surviving a minute, it removes the client-timeout bug class entirely, and it turns an offline machine from an error into a delay.

3. Always send an idempotency key

Derive it from your own work item's identity, not from a fresh UUID inside the retry loop. Retrying safely.

4. Spread across providers

Enable more than one provider and let revoye/auto rotate. Three reasons:

  • Throughput. Provider-level hourly caps bind before global ones.
  • Resilience. A provider's web interface changes and an agent breaks. Traffic keeps flowing.
  • Account safety. Rotation is what keeps any single account's usage from concentrating.

Pin a provider only when the answer's quality genuinely depends on which model produces it.

5. Set timeouts deliberately

Prompt shapetimeout_ms
Short question, short answerDefault (180 000) is generous
Long document, long answer300 000–600 000
Anything with deep research or web browsing turned on in the providerToward the ceiling

Set deadline_ms to the point at which the answer stops being useful to you. That is what stops a retry chain outliving its own purpose.

6. Write prompts that survive a chat interface

The prompt goes into a chat product, not a completions API. Two consequences:

  • Ask for the output format explicitly. "Reply with JSON only, no explanation." A chat UI is chatty by default, and the agent returns whatever the page contained.
  • Parse defensively. Strip code fences, tolerate a preamble, and validate before you trust. Treating the response as guaranteed-shaped JSON will break.

7. Instrument the four fields the response gives you

attempts, queue_ms, run_ms, provider. Log all four on every job and you can answer, without guessing:

  • Are jobs waiting (queue_ms high) or running slow (run_ms high)?
  • Is one provider retrying more than the others (attempts by provider)?
  • Is capacity degrading over a week?

8. Monitor from /v1/status, on a schedule

Once a minute is plenty. Alert on devices.online == 0 sustained past your tolerance, and on queue.oldest_queued_at older than your deadline. Do not poll it per request — that is how you hit the ingress limit.

9. Keep the fleet healthy

  • Keep the machine awake when it is meant to be working. Sleep settings are the single commonest cause of "Revoye stopped working".
  • One agent is one browser tab. Six agents on a laptop with 8 GB of RAM will not go well.
  • Stay signed in. An agent whose provider session has expired cannot answer; the extension's agent list is where you see that.
  • Watch for provider redesigns. A sudden run of JOB_FAILED on one provider and not the others usually means an interface changed.

10. Keys: narrow, separate, rotatable

One key per deployment, scoped to what that deployment does, in a secret manager. Write-only for a client, read-only for a monitor. Authentication.