Skip to content

[Jobs] Add --expose <port> option to expose job ports through the jobs proxy#4316

Merged
Wauplin merged 6 commits into
mainfrom
feat/jobs-cli-expose
Jun 9, 2026
Merged

[Jobs] Add --expose <port> option to expose job ports through the jobs proxy#4316
Wauplin merged 6 commits into
mainfrom
feat/jobs-cli-expose

Conversation

@XciD

@XciD XciD commented Jun 5, 2026

Copy link
Copy Markdown
Member

Summary

Add a repeatable --expose <port> flag on the four job-runner CLI commands and a matching expose: list[int] | None parameter on the Python API:

  • HfApi.run_job(..., expose=None) / hf jobs run --expose 8000 --expose 8001 ...
  • HfApi.run_uv_job(..., expose=None) / hf jobs uv run --expose 8000 ...
  • HfApi.create_scheduled_job(..., expose=None) / hf jobs scheduled run --expose 8000 ...
  • HfApi.create_scheduled_uv_job(..., expose=None) / hf jobs scheduled uv run --expose 8000 ...

When set, the request payload includes expose: { ports: [...] }, which tells the Jobs backend to register each port on the public jobs proxy. The job is then reachable at https://<job_id>--<port>.hf.jobs. Access still requires an HF token with read access to the job's namespace.

Example

hf jobs run --expose 8000 python:3.12 python -m http.server 8000
hf jobs run --expose 8000 --expose 8001 python:3.12 my-multiport-app
from huggingface_hub import run_job
run_job(image="python:3.12", command=["python", "-m", "http.server", "8000"], expose=[8000])

Notes

  • The default is None (omit expose from the payload). Pass a non-empty list to declare ports; an empty list is also accepted and serializes to {"ports": []} (same as no expose).
  • The CLI help / docstrings deliberately don't hard-code the public domain (the helm chart owns it).
  • The parametrized test_serialize_expose covers None, empty list, single port, and multi-port.

Note

Medium Risk
Exposes container ports on a public jobs domain (token-gated); changes job API payloads and JobStatus shape, but behavior is opt-in and scoped to Jobs.

Overview
Adds port exposure for Hugging Face Jobs so workloads can be reached through the jobs proxy instead of only via logs/SSH-style workflows.

The Python API gains an optional expose: list[int] on run_job, run_uv_job, create_scheduled_job, and create_scheduled_uv_job. _create_job_spec sends expose: { "ports": [...] } when the list is non-empty; None and [] leave the field out of the payload. Job responses now surface expose_urls on JobStatus (from API exposeUrls), documented on JobInfo.

The CLI adds a repeatable --expose INTEGER on hf jobs run, hf jobs uv run, hf jobs scheduled run, and hf jobs scheduled uv run. After starting a job, run / uv run print a hint with the public URLs and note that access needs an HF token with read access to the job namespace. CLI reference docs are updated for all four commands.

Tests expect expose=None on existing job CLI mocks and add test_serialize_expose for job spec serialization.

Reviewed by Cursor Bugbot for commit 7eee9d0. Bugbot is set up for automated code reviews on this repo. Configure here.

XciD added 2 commits June 5, 2026 14:57
Adds an `expose` boolean parameter to `run_job`, `run_uv_job`,
`create_scheduled_job`, `create_scheduled_uv_job` and a matching `--expose`
flag on the four `hf jobs (...) run` CLI commands. When set, the Jobs API
exposes every port the container listens on through the public jobs proxy.

The wire payload (`expose: { enabled: true }`) and the auth model (HF token
with read access to the job's namespace) are already supported on the
backend.
@bot-ci-comment

bot-ci-comment Bot commented Jun 5, 2026

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@XciD XciD marked this pull request as ready for review June 5, 2026 14:01
@Wauplin

Wauplin commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

(to be updated once https://github.com/huggingface-internal/moon-landing/pull/18499 is merged -forward list of ports instead of boolean value)

@XciD XciD force-pushed the feat/jobs-cli-expose branch from c359927 to 9395e77 Compare June 9, 2026 13:38
@XciD XciD changed the title [Jobs] Add --expose option to expose job ports through the jobs proxy [Jobs] Add --expose <port> option to expose job ports through the jobs proxy Jun 9, 2026
@XciD XciD force-pushed the feat/jobs-cli-expose branch from 9395e77 to 0e73a22 Compare June 9, 2026 13:50
Backend now expects `expose: { ports: [u16] }` (was `{ enabled: bool }`).
- API: `expose: list[int] | None` on `run_job`, `run_uv_job`,
  `create_scheduled_job`, `create_scheduled_uv_job`.
- Serialization: `expose=[8000, 8001]` -> `{"ports": [8000, 8001]}`.
- CLI: `--expose` is now repeatable (`--expose 8000 --expose 8001`),
  not a boolean.
- Docstrings + CLI reference + parametrized test updated to cover
  the new list/None shape.
@XciD XciD force-pushed the feat/jobs-cli-expose branch from 0e73a22 to 5a2e804 Compare June 9, 2026 13:50
@XciD XciD requested a review from Wauplin June 9, 2026 13:53

@Wauplin Wauplin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally and works fine, thanks!

(I've just added 9f3f4e1 to retrieve exposeUrls from server and add hints when creating a Job with open ports)

@lhoestq

lhoestq commented Jun 9, 2026

Copy link
Copy Markdown
Member

Would be cool to match docker CLI syntac with -p instead of --expose no ?

We designed hf jobs run to match the docker CLI syntax to help user's and agent's intuition

EDIT: ah I get that there is no notion of external port, since the URL is used instead, nvm

@Wauplin

Wauplin commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Would be cool to match docker CLI syntac with -p instead of --expose no ?

We designed hf jobs run to match the docker CLI syntax to help user's and agent's intuition

EDIT: ah I get that there is no notion of external port, since the URL is used instead, nvm

Yeah originally thought the same as well but in the end --expose is more explicit

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7eee9d0. Configure here.

job_spec["volumes"] = [vol.to_dict() for vol in volumes]
# expose ports through the jobs proxy
if expose:
job_spec["expose"] = {"ports": expose}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JobSpec drops expose on read

Medium Severity

_create_job_spec now sends expose in the job spec for scheduled jobs, but JobSpec never reads that field from API responses. After creating a scheduled job with --expose, inspect_scheduled_job / hf jobs scheduled inspect cannot surface the configured ports because the value is discarded during parsing.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7eee9d0. Configure here.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a problem

@Wauplin Wauplin merged commit 0265347 into main Jun 9, 2026
25 of 26 checks passed
@Wauplin Wauplin deleted the feat/jobs-cli-expose branch June 9, 2026 15:02
@huggingface-hub-bot

Copy link
Copy Markdown
Contributor

This PR has been shipped as part of the v1.19.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants