Skip to content

Command line (peach-cli)

peach-cli is a small command-line tool that signs you in with GitLab and caches a token on your machine. Once that token exists, everything else that talks to a Peach cluster from outside it — @peach.task, @peach.endpoint, peach_serve(), your own scripts — picks it up automatically.

peach auth login

In practice that is the whole of it: log in once, then write decorators on your laptop exactly as you would in PEACH Lab.

Inside PEACH Lab and on the cluster you do not need this tool at all. There, Ray is reached over an in-cluster address and there is nothing to authenticate.

Why a CLI at all

A Peach codops' Ray cluster is published at ray-grpc.<codops>.<envDomain>, behind the same GitLab forward-auth that protects the rest of your codops' web endpoints. That works fine for a browser, which has a cookie jar and can be redirected through an OAuth dance. A headless Python process has neither, so peach-cli implements a dedicated one-time-code flow instead and leaves the result on disk for other tools to read.

Install

The tool lives in its own repository, pipe/peach-cli:

git clone https://git.ebu.io/pipe/peach-cli
cd peach-cli
uv sync --extra ray --python 3.11
uv run peach --help

--python 3.11 is not optional

Ray Client requires the client and the cluster to run closely matching Ray and Python versions, and the ray extra is pinned to ray[client]==2.55.1 to match the version on the rayservice head pods. A mismatch does not announce itself as a version problem — it surfaces as a cryptic ConnectionAbortedError: Starting Ray client server failed from the server, or as a ray client connection timeout from a channel that never becomes ready.

Drop --extra ray if you only want peach auth login — to authenticate a machine whose real work is done by the decorators, which bring their own Ray.

Signing in

peach auth login

opens a browser, runs the normal GitLab OAuth flow (2FA included — the default --timeout is 300 seconds to leave room for it), and prints who you now are:

Signed in as Jane Doe (jane.doe@example.org)
Groups: pipe, pipe/algorithms

On a machine with no browser — an SSH session, a CI runner — pass --no-browser and open the printed URL yourself. The callback still has to reach 127.0.0.1 on the machine running peach, so forward that port if the browser lives elsewhere.

Two more commands round it out:

peach auth whoami    # the cached identity, as JSON: user, groups, expires_at
peach auth logout    # revoke the token server-side and delete it locally

whoami is the quickest way to tell an expired session apart from a genuine connectivity problem; it fails with Session expired. Run 'peach auth login' again. rather than anything network-shaped.

Where the token lives

The token is written to ~/.peach/credentials.json with mode 0600, holding the token itself, its expiry, and your GitLab user and groups.

That file is the integration point with the rest of Peach. pipe-algorithms-lib reads it directly rather than importing peach_cli, so the two stay independent — you install the CLI once, and every project on the machine benefits without taking on its dependencies.

Delete the file (or run peach auth logout) to sign out; nothing else caches the token.

How the login flow works

Worth knowing if you are reviewing it, or wondering why a browser login can produce a durable CLI token safely:

  1. peach starts a local HTTP listener on an ephemeral 127.0.0.1 port.
  2. It opens https://auth.peach.ebu.io/cli/login?port=…&state=…, which runs the normal GitLab OAuth flow.
  3. On success the auth service mints a short-lived one-time code and redirects the browser to http://127.0.0.1:<port>/callback?code=…&state=…. The state nonce is checked on return, so a redirect you did not initiate is rejected.
  4. peach — not the browser — exchanges that code for the durable bearer token over a direct HTTPS POST. The durable token therefore never appears in a URL, in browser history, or in any access log.
  5. Subsequent calls send it as Authorization: Bearer <token>, over HTTP for the auth service and as gRPC metadata for Ray.

Using the token

With the decorators

Nothing to wire up. Set your codops, then write the same code you would write in a notebook:

import os
os.environ["CODOPS"] = "sesr"

from pipe_algorithms_lib.compute import peach

@peach.task()
def hello(n: int) -> str:
    import socket
    return f"task #{n} ran on {socket.gethostname()}"

print(hello(1))

The decorator notices it is off-cluster, resolves ray://ray-grpc.sesr.peach.ebu.io:443, and attaches the cached token as gRPC metadata. Add PEACH_ENV_DOMAIN to reach a dev cluster; the full list of variables is on the Decorator tasks page.

Not logged in? You get a fallback, not an error

Without credentials the decorators fall back to the in-cluster address, which only resolves if you already have network access into the VPC. Set PEACH_ALLOW_CLUSTER_FALLBACK=0 to turn that off and get a clear "not logged in" error instead of an opaque DNS failure.

@peach.endpoint and peach_serve() authenticate the same way — see Decorator endpoints.

A REPL on the cluster

peach ray connect sesr --env prod

connects to that codops' Ray cluster and drops you into a Python prompt. The connection is established for the whole process, so import ray inside the REPL and use it as normal — ray.cluster_resources() is a good first thing to type, since it proves the ingress, the token and the version handshake all agree.

--namespace picks the Ray namespace to connect into. Ctrl-D disconnects.

Environments

--env selects which cluster you are talking to:

--env Domain
prod peach.ebu.io (the default)
dev dev.peach.ebu.io
dev-2 dev-2.peach.ebu.io
dev-3 dev-3.peach.ebu.io

The same names appear as PEACH_ENV_DOMAIN values for the decorators, spelled as the full domain.

Worked examples

The repository's examples/ folder is the fastest way to confirm a working setup end to end:

Example Shows
submit_job.py submitting @peach.task calls that run on real worker pods
submit_endpoint.py deploying an ephemeral @peach.endpoint with peach_serve()
submit_endpoint_with_init.py the same, with an init_fn that runs once per replica

They need pipe-algorithms-lib, which is deliberately not a dependency of peach-cli — it is large, separately versioned, and Ray ships the CLI's directory to the cluster as the job's working directory, where a relative editable path cannot survive the trip. Install it into the venv directly instead:

uv pip install -e /path/to/your/pipe-algorithms --python .venv
uv run --no-sync --python 3.11 python examples/submit_job.py test-dev --env prod

--no-sync matters

Without it, uv run resyncs the venv from pyproject.toml first and silently uninstalls pipe-algorithms-lib again before your script runs.

Troubleshooting

Not logged in. Run 'peach auth login' first. — no credentials file, or it failed to parse. Log in again.

Session expired. — the token outlived expires_at. peach auth login mints a new one; nothing else needs redoing.

ConnectionAbortedError: Starting Ray client server failed, or a connection that times out without ever erroring — almost always a Ray or Python version mismatch rather than anything to do with auth. Check you are on Python 3.11 with the pinned ray extra, and that the pin still matches the cluster.

RuntimeError: Proxy failed to Connect to backend! when running under uv run — Ray detects a uv run driver and tries to replicate your project's dependencies onto the cluster by re-running uv sync on the worker. The rayservice pods have no PyPI access, so it always fails, in a way that looks nothing like the cause. peach-cli sets RAY_ENABLE_UV_RUN_RUNTIME_ENV=0 before importing Ray to disable it; if you connect to Ray yourself, set the same variable before your own import ray.

ModuleNotFoundError for a package your py_env definitely has — this is the module-scope import trap, not a CLI problem. See Running from outside the cluster.

Command reference

Command Does
peach auth login GitLab OAuth in a browser; caches the token. --no-browser prints the URL instead; --timeout (default 300) is how long to wait.
peach auth whoami Prints the cached user, groups and expiry as JSON.
peach auth logout Revokes the token server-side (best effort) and deletes the local file.
peach ray connect <codops> Connects to that codops' Ray cluster and opens a Python REPL. --env selects the cluster, --namespace the Ray namespace.

--auth-server on the peach group itself points at a different peach-gitlab-auth deployment; it defaults to https://auth.peach.ebu.io and can also be set with PEACH_AUTH_SERVER_URL. You should not normally need it.