Your tool names and inputs should not change when you move live.

ConcernMock environmentLive environment
baseUrlMock-backed executorHosted or self-hosted executor
Project keyTest project keyEnvironment-scoped project key
AccountDeterministic fixture selected by userIdProvider connection owned by the same external user
TimeFrozen and controllableWall-clock time
FailuresTrigger tokensReal normalized provider failures
ts
import { Eyeball } from "@eyeball/sdk";

const eyeball = new Eyeball({
  apiKey: process.env.EYEBALL_API_KEY!,
  baseUrl: process.env.EYEBALL_EXECUTOR_URL!,
});

const output = await eyeball.tools.run(
  "gmail.search_emails",
  { query: "reservation", pageSize: 10 },
  { userId: "user_42" },
);
console.log(output);

Only configuration and connected-account state differ. On a self-hosted executor, supply live credentials with EYEBALL_CREDENTIALS=env or local-vault on the stock server — see Connect real providers. Before enabling mutations, replay the same scenario against mocks, preserve idempotency keys across retries, and verify the provider scopes listed in the generated toolkit page.

Next: connect an account.