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:
peachstarts a local HTTP listener on an ephemeral127.0.0.1port.- It opens
https://auth.peach.ebu.io/cli/login?port=…&state=…, which runs the normal GitLab OAuth flow. - 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=…. Thestatenonce is checked on return, so a redirect you did not initiate is rejected. peach— not the browser — exchanges that code for the durable bearer token over a direct HTTPSPOST. The durable token therefore never appears in a URL, in browser history, or in any access log.- 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.
Related
- Decorator tasks —
@peach.task, the environment variables, and running from outside the cluster. - Decorator endpoints —
@peach.endpoint,peach_serve()and the production deployment path. - Python environments — what
py_envselects.