Skip to main content
Hosted optimizer runs need a task service they can reach. If that service is running on your machine, synth-optimizers can open a tunnel before submit and keep it alive while the hosted run is active.

Providers

Use one provider flag for both GEPA and GELO:
--tunnel-provider synth_tunnel
Supported values:
ProviderUse whenNotes
synth_tunnelDefault hosted optimizer tunnel.Creates a SynthTunnel lease, starts the local agent, and can refresh backend-owned auth for long runs.
cloudflaredYou want a Cloudflare tunnel URL.Requires the cloudflared binary on your machine. Submits as a public URL.
ngrokYou want an ngrok URL.Requires the ngrok binary on your machine. Submits as a public URL.
autoYou want the SDK default.Currently resolves to synth_tunnel.
cloudflared and ngrok managed leases require a localhost target, such as http://127.0.0.1:8943.

CLI

GEPA:
synth-optimizers gepa submit \
  --config gepa.toml \
  --tunnel-url http://localhost:8765 \
  --tunnel-provider synth_tunnel \
  --follow
GELO:
synth-optimizers gelo submit \
  --preset crafter_smoke \
  --tunnel-url http://localhost:8943 \
  --tunnel-provider synth_tunnel \
  --follow
--follow is required with --tunnel-url; it keeps the tunnel open until the hosted run reaches a terminal status. Without --follow, the CLI refuses to submit a local tunnel run.

Python

from synth_optimizers.gelo import GeloPreset
from synth_optimizers.hosted import HostedOptimizerClient

client = HostedOptimizerClient()

with client.open_tunnel(
    "http://127.0.0.1:8943",
    provider="synth_tunnel",
    requested_ttl_seconds=3600,
) as tunnel:
    config = GeloPreset.crafter_smoke().materialize(
        container_tunnel=tunnel,
    )
    run = client.submit_gelo(config)
    client.wait_for_run(run.run_id, timeout_seconds=3600)
The same open_tunnel(...) lease can be passed to submit_gepa_toml(...) through container_tunnel.

Readiness

Before submit, the SDK checks that the local target is reachable. After a lease is created, it waits for the public tunnel URL to answer before the run is submitted. For best results:
  • expose a /health endpoint on the local task service
  • keep the local process running for the full hosted run
  • use --follow for CLI submits
  • close Python tunnel leases with a context manager

Direct URLs and Pools

You do not need a tunnel if your task service is already reachable from the public internet. Use --container-url or a config-level direct URL instead. You also do not need a tunnel when the task is already registered in a Synth container pool. Use --container-pool and optional --container-task-id.

Common Errors

SymptomWhat to check
401 or 403SYNTH_API_KEY is missing or points at the wrong environment.
Local service unreachableCheck the local host, port, and /health route.
cloudflared or ngrok missingInstall the selected binary or use --tunnel-provider synth_tunnel.
Lease closes earlySubmit with --follow or keep the Python context manager open until the run finishes.
Wrong backendSet SYNTH_BACKEND_URL or pass --base-url to the CLI.