Skip to content

feat: add --playground flag to cog serve - #3154

Merged
anish-sahoo merged 3 commits into
mainfrom
playground-cli
Aug 13, 2026
Merged

feat: add --playground flag to cog serve#3154
anish-sahoo merged 3 commits into
mainfrom
playground-cli

Conversation

@anish-sahoo

@anish-sahoo anish-sahoo commented Aug 13, 2026

Copy link
Copy Markdown
Member

Adds --playground to cog serve so it starts the playground alongside the model and prints both URLs:

Serving at http://127.0.0.1:8393
Playground at http://127.0.0.1:9000

The playground binds its own port (--playground-port, default 9000, 0 = free port) and never collides with the model port.

  • pkg/cli/serve.go: new --playground and --playground-port flags; validates the playground port doesn't overlap the model port; binds the playground before the container starts so a bind failure aborts fast; prints the playground URL next to Serving at; runs it with graceful shutdown. cmdServe now cancels its context on signal, so Ctrl+C exits cleanly instead of erroring.
  • pkg/cli/playground.go: pulls the standalone command's startup into a reusable startPlayground(ctx, playgroundConfig) helper. cog playground is unchanged.
  • Tests for the port validation, host overlap, the target URL helper, and the new helper.

Only serve supports --playground for now; predict/run/train run the container headlessly with no public port.

Start the playground alongside the model on a dedicated port, print both
URLs, and shut it down cleanly on Ctrl+C. The playground port never
collides with the model port.
@anish-sahoo
anish-sahoo requested a review from a team as a code owner August 13, 2026 18:01
@ask-bonk

ask-bonk Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

I reviewed the PR changes, focusing on the serve.go file to understand the --playground flag implementation. Based on my review, I found no actionable issues requiring comments.

LGTM

github run

Use the actual serve host instead of hardcoding localhost, so the
playground proxy matches the address the model is really bound to.
@ask-bonk

ask-bonk Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

@markphelps markphelps 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.

Thanks for factoring the playground startup out cleanly. I found two edge cases that need fixing before this is ready.

Comment thread pkg/cli/serve.go
var playgroundSrv *http.Server
var playgroundLn net.Listener
if servePlaygroundFlag {
playgroundURL, playgroundSrv, playgroundLn, err = startPlayground(ctx, playgroundConfig{

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.

This makes async mode unusable for the integrated playground on Linux. playgroundHost is still the standalone command default (127.0.0.1), while the UI tells the model to send webhooks to host.docker.internal. The Linux host-gateway mapping is only added when --upload-url is set, and even with that mapping a container cannot reach a loopback-only listener through the gateway. Could the embedded playground bind on a container-reachable interface and add host.docker.internal:host-gateway whenever --playground is enabled? An end-to-end async webhook test here would catch this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The embedded playground now binds to 0.0.0.0 and adds the host-gateway alias whenever --playground is enabled.

Comment thread pkg/cli/serve.go
// port on overlapping interfaces. A playground port of 0 asks for a free port,
// so it never collides.
func validateServePorts(serveHost string, port, playgroundPort int, playgroundHost string) error {
if playgroundPort == 0 {

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.

Port 0 does not guarantee that the playground avoids the model port: the playground listener is opened before Docker publishes the model port, so for a user-selected model port in the ephemeral range the OS can assign that exact port to the playground. Docker will then fail to start the model. After binding, please compare the resolved playground port with the model port (and retry or fail clearly if they overlap), rather than treating 0 as collision-free.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The bound playground port is now checked before Docker starts, and Cog closes the listener and returns an error if it collides with the model port.

@ask-bonk

ask-bonk Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

@anish-sahoo
anish-sahoo added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit 6ed80bc Aug 13, 2026
49 checks passed
@anish-sahoo
anish-sahoo deleted the playground-cli branch August 13, 2026 19:56
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.

2 participants