Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ This file defines how coding agents should work in this repository.
before service RPC, daemon auto-start, stop-all fallback, or daemon ownership
operations. JSON-output commands must return structured `{"error": "..."}`
objects for invalid endpoints, not tracebacks.
- `keep-gpu start` follow-up status/stop/service-stop hints must target the
selected service endpoint while keeping default-endpoint hints concise.
- Shared public endpoint validation belongs in
`src/keep_gpu/utilities/endpoint_validation.py`; CLI and MCP entry points
should only translate those `ValueError`s into their interface-specific error
Expand Down
3 changes: 3 additions & 0 deletions docs/guides/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ keep-gpu start --gpu-ids 0 --vram 1GiB --interval 60 --busy-threshold 25
- follow-up status/stop command hints,
- daemon shutdown hint (`keep-gpu service-stop`).

When `--host` or `--port` selects a non-default endpoint, the printed
status/stop/service-stop hints include the same endpoint flags.

If this invocation auto-starts the service but session creation fails with an
expected startup-unavailable error before a session is created, `start`
best-effort stops the just-created daemon so it does not remain idle.
Expand Down
22 changes: 19 additions & 3 deletions src/keep_gpu/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ def _service_command(host: str, port: int) -> List[str]:
]


def _service_hint_args(host: str, port: int) -> List[str]:
if host == DEFAULT_SERVICE_HOST and port == DEFAULT_SERVICE_PORT:
return []
return ["--host", host, "--port", str(port)]


def _keep_gpu_hint_command(command: str, host: str, port: int, *args: str) -> str:
parts = ["keep-gpu", command, *_service_hint_args(host, port), *args]
return " ".join(shlex.quote(part) for part in parts)


def _print_machine_json(data: Dict[str, Any]) -> None:
console.file.write(f"{json.dumps(data, indent=2, allow_nan=False)}\n")
console.file.flush()
Expand Down Expand Up @@ -1295,11 +1306,16 @@ def start(
f"[bold green]Started keep session[/bold green] job_id={result_job_id}"
)
console.print(f"[cyan]Dashboard:[/cyan] http://{host}:{port}/")
console.print(
f"[dim]Next: keep-gpu status --job-id {result_job_id} | keep-gpu stop --job-id {result_job_id}[/dim]"
status_command = _keep_gpu_hint_command(
"status", host, port, "--job-id", result_job_id
)
stop_command = _keep_gpu_hint_command(
"stop", host, port, "--job-id", result_job_id
)
service_stop_command = _keep_gpu_hint_command("service-stop", host, port)
console.print(f"[dim]Next: {status_command} | {stop_command}[/dim]")
console.print(
"[dim]When all sessions are done, stop daemon with: keep-gpu service-stop[/dim]"
f"[dim]When all sessions are done, stop daemon with: {service_stop_command}[/dim]"
)
except ServiceRPCError as exc:
_rollback_auto_started_service_on_startup_unavailable(
Expand Down
20 changes: 20 additions & 0 deletions tests/test_cli_service_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,26 @@ def fake_rpc(method, params, host, port):
assert "keep-gpu service-stop" in result.output


def test_start_prints_custom_endpoint_in_follow_up_hints(monkeypatch):
monkeypatch.setattr(cli, "_ensure_service_running", lambda *args, **kwargs: True)
monkeypatch.setattr(cli, "_rpc_call", lambda *args, **kwargs: {"job_id": "job-abc"})

result = runner.invoke(cli.app, ["start", "--host", "localhost", "--port", "9999"])

normalized_output = " ".join(result.output.split())
assert result.exit_code == 0
assert "Dashboard: http://localhost:9999/" in normalized_output
assert (
"keep-gpu status --host localhost --port 9999 --job-id job-abc"
in normalized_output
)
assert (
"keep-gpu stop --host localhost --port 9999 --job-id job-abc"
in normalized_output
)
assert "keep-gpu service-stop --host localhost --port 9999" in normalized_output


def test_start_rolls_back_auto_started_service_on_startup_unavailable(monkeypatch):
stopped = []

Expand Down