Gyredocs
Depth Practice
API

Gyre/User Guide

Deployment

In one minuteA deployment is one process tree serving the API, the agent endpoint and the documentation for its own revision, bound to all interfaces so that tailnet machines can reach it. Deploy natively, as a container, or under systemd.

Written at L2 Practice goes to L3 Mechanicsoperators 1398 words Markdown

Native deployment#

bash
python3 tools/deploy.py up --name dev --port 8600     # make deploy
python3 tools/deploy.py status
python3 tools/deploy.py down --name dev

up performs, in order: refuse a name that is still running and a port that is already in use (make serve, the systemd unit and other deployments default to 8600 too) → record the revision (commit, dirty flag) → build the documentation into the deployment directory → start gyre serve --host 0.0.0.0 → wait for health and verify through /api/v1/info that the answer comes from the process just started → run the smoke test against the tailnet address (loopback if the host has none) → write var/deploy/<name>/deployment.json, which records whether the smoke test passed. No record is written if the service has exited by the end of the smoke test.

Health; deployment identity; the documentation home page, search index and llms.txt; presets; a structured error; pipeline definitions (at least one runnable, none unloadable); the MCP tool list; a real solver job with an adjoint gradient, submitted with use_cache: false (an answer from the result cache fails the check); metrics. It uses only the Python standard library and can be run from any tailnet machine:

bash
python3 deploy/smoke.py http://HOST:8600
GYRE_API_TOKEN=... python3 deploy/smoke.py http://HOST:8600     # token-protected deployment

A deployment protected by GYRE_API_TOKEN is tested with the same variable set for the script, or with --token. up passes its environment on to the service (without GYRE_DEVICE, which the service sets per worker) and to the smoke test, so setting the variable for up covers both.

The service binds 0.0.0.0, never loopback only. Every URL below works from another tailnet device with the host’s tailnet name or address:

URL
http://HOST:8600/ documentation built from the deployed revision
http://HOST:8600/api/v1/info which revision and deployment is answering
http://HOST:8600/api/docs interactive API explorer
http://HOST:8600/mcp agent endpoint

Container#

bash
GYRE_COMMIT=$(git rev-parse HEAD) docker compose -f deploy/compose.yaml up -d --build
Name Purpose
GYRE_CONSTRAINTS the tested dependency set to install: constraints/tested-cpu.txt (default; JAX 0.11.2, which also runs on CPUs without AVX2) or constraints/tested-cuda12.txt for NVIDIA GPUs
GYRE_EXTRAS extras of the package to install: service,docs (default), service,docs,gpu with the CUDA set
GYRE_COMMIT revision stamped into the image and its documentation
GYRE_PORT published host port (default 8600, bound on all interfaces)
GYRE_API_TOKEN require a bearer token
GYRE_SERVICE_GPU auto, on or off (default off in the container)
GYRE_PIPELINES_ALLOW_SHELL 1 lets the service start pipelines with shell stages (see Configuration). The compose file forwards it from the environment docker compose is started in (GYRE_PIPELINES_ALLOW_SHELL=1 docker compose … up); nothing needs to be added to the file

The image builds the documentation at image-build time from the verification results present in the build context, so a container and its documentation cannot disagree. Job data and the JIT cache live on the /data volume.

make image (deploy/image_smoke.sh) builds the image and smoke-tests a throw-away container of it on port 8602. On a machine whose Docker build sandbox cannot resolve host names (the package download fails with “Temporary failure in name resolution” although docker run works), set GYRE_BUILD_NETWORK=host for that script, or pass --network host to docker build.

The image also ships the analysis pipeline definitions of its revision (pipelines/ without ci.yaml) and examples/ under /app; the OpenMDAO example needs the mdo extra, which the image does not install. To serve your own pipeline definitions, bind-mount a directory over /app/pipelines (deploy/compose.yaml carries a commented example).

systemd#

bash
cp deploy/gyre.service ~/.config/systemd/user/
systemctl --user enable --now gyre

Configuration#

Variable Default Effect
GYRE_DEPLOYMENT dev name reported by /api/v1/info and shown in the documentation footer
GYRE_API_TOKEN unset bearer token for /api/v1 and /mcp (/api/v1/health and /api/v1/info stay open)
GYRE_SERVICE_GPU auto whether workers may use a GPU
GYRE_MAX_SESSIONS 4 concurrent sessions
GYRE_SESSION_IDLE_S 1800 idle time before a session is closed
GYRE_PIPELINES_DIR pipelines directory of the pipeline definitions the service lists, relative to its working directory (/app/pipelines in the image)
GYRE_MESH_MAX_BYTES 67108864 (64 MiB) largest mesh file PUT /api/v1/meshes/{name} accepts (413 MeshTooLarge above it); the arrays of an .npz upload may take up to four times this value uncompressed and must also stay within GYRE_MESH_MAX_EXPANDED_BYTES (422 InvalidMesh). Read at each request. A value that is not a positive integer is replaced by the default
GYRE_MESH_STORE_MAX_FILES 256 number of meshes the mesh store holds (507 MeshStoreFull). A value that is not a positive integer is replaced by the default
GYRE_MESH_STORE_MAX_BYTES 4294967296 (4 GiB) total size of the mesh store in bytes (507 MeshStoreFull). A value that is not a positive integer is replaced by the default
GYRE_MESH_DIR, GYRE_MESH_RESTRICT set by the service while it runs, the service sets GYRE_MESH_DIR to <data>/meshes (absolute path) and GYRE_MESH_RESTRICT=1 in its own environment, whatever they were before; its job workers, session processes and pipeline runs inherit them and open mesh files only by bare name from that directory. Outside a service, GYRE_MESH_DIR is a directory in which the CLI and Python look for a relative mesh path that does not exist as given
GYRE_MESH_MAX_EXPANDED_BYTES 1073741824 (1 GiB) largest uncompressed size of the arrays of an .npz mesh the reader accepts, in any process, the service included (an upload above it is a 422 InvalidMesh). A value that is not a positive integer is an error: every read of an .npz mesh fails with GYRE_MESH_MAX_EXPANDED_BYTES must be a positive integer, got '…'
GYRE_PIPELINES_ALLOW_SHELL unset 1 lets the REST API and the MCP tools start pipelines that contain shell stages (for example ci). Without it such definitions are listed with runnable: false and a reason, and starting one returns 403 PipelineNotRunnable; they stay runnable on the host with gyre pipeline run
GYRE_DEVICE auto device of a solver process (the service sets it per worker)
GYRE_JIT_CACHE ~/.cache/gyre/jit persistent compilation cache directory, or off
GYRE_LOG_LEVEL info uvicorn log level
GYRE_SERVICE_URL http://127.0.0.1:8600 read by the stdio MCP proxy only (python -m gyre.agent): the deployment it forwards to when --service is not given (agent interface)

gyre serve --workers N sets the number of concurrent job workers (GPU jobs are serialised).

  • Identity. GET /api/v1/info returns version, commit, process id, start time and deployment name; the documentation footer shows the same. up accepts the answer only if it reports the deployment’s name and a start time not earlier than the launch; otherwise it stops the process it started. It passes the name and start time on to the smoke test, which stops at once if another process answers.
  • Monitoring. Scrape GET /api/v1/metrics. An unexpected fault is answered 500 InternalError with an incident id; the service log (logger gyre.service) has the exception under the same id.
  • Mesh uploads. Without GYRE_API_TOKEN, anyone who reaches the service can upload meshes up to the limits above. Uploads are validated before they are stored and are addressed by name only; a request cannot make the service read or write a path outside <data>/meshes.
  • Data. The data directory (gyre serve --data, default var/service) holds jobs/<id>/ (request, status, events, artefacts), cache.json, meshes/ (the mesh store: one file per uploaded mesh) and pipelines/ (runs/<id>/ per run and work/, the stage directories and their cache). Deleting a job directory is safe. Mesh files can be copied into meshes/ or removed by hand; a file the reader rejects is listed with an error. The result cache is keyed by the case specification, the requested gradients, error estimates and order selection, the contents of a mesh file the case names, and a fingerprint of the code (version, revision and the package sources). An upgrade can therefore keep its data directory: results computed by other code are not reused, and old job records stay readable but are never served as cache hits. <data>/cache.json is only an index of that cache; the job records are the source of truth.
  • Upgrades. Deploy the new revision under a new name and port, smoke-test it, then stop the old one: tools/deploy.py keeps deployments side by side. up refuses a port that is already in use, so the new revision needs its own --port.

    ↑ ↓ moveEnter open[ ] change depthResults show section and depth level