--remote-host gpubox to praisonai-train llm, put a remote: block in your config file, or pick “A remote server” in the desktop’s fine-tune form — the same instruction, three ways. The run happens on the other box; your laptop can close.
Quick Start
1
Set up key auth once
The runner never accepts a password prompt — it uses your ssh agent and
~/.ssh/config.2
Send it with a flag
3
Or put it in the config file
4
Or pick 'A remote server' in the desktop
Open Fine-tune a model, set Run on → A remote server, and type the SSH alias. The remote python and remote directory fields reveal themselves with sensible defaults.
What Settles What — flag > YAML > default
The presence of a settled host is what routes the run remotely; there is no separate mode flag.
- No
host→ train here, exactly as before. - A flag overrides the file. An absent flag does not erase what the YAML says — only non-empty overrides win.
- A local run in the desktop posts no
remote:block, even if you typed a host and then switched back to “This computer”.
Options
Every key is expressible as a flag, in YAML, and in the desktop. All three drive the same code.workdir is expanded by the remote shell — ~/.praisonai-train lands in the remote user’s home, not yours. It is created with mkdir -p -m 700, so on a shared GPU box the umask does not decide who can read the shipped config and dataset. Only letters, digits, ., _, -, /, and an optional leading ~ are allowed; the runner refuses anything else before any SSH. See PraisonAI PR #4550 for the tilde-expansion fix and the mode-700 hardening.What Is Shipped, and What Is Not
The dispatcher rewrites the config before sending it so the far side does the right thing.1
The remote: block is stripped
The remote host reads a config file too. Leaving
remote: in would make it find a host and dispatch again. The dispatcher removes it before shipping.2
A local dataset is copied; a Hub dataset is not
The dispatcher walks the resolved
dataset — a string or a list-of-mappings — and copies the first local file it finds, whether it was named on the CLI or only inside config.yaml. A HuggingFace id or a path that lives only on the remote host is not a local file, so it is left alone. Name a local file explicitly with data_files when you want name to stay a label.A
dataset: "path.jsonl" string is normalised to [{name: "path.jsonl"}] in the shipped config for the remote trainer.3
Credentials are refused up front
password, passphrase, token, key, secret, identity_file, private_key in the remote: block are refused before any SSH — the file is shipped to the remote host and printed by --dry-run, so a credential in it would leak. Use your ssh agent and ~/.ssh/config.The dispatcher writes to a
NamedTemporaryFile, never to a config.yaml in the directory you launched from — a remote run never rewrites a file where you happen to be standing.Preview Before You Spend the GPU-hours
--dry-run prints the resolved config, including the settled remote: block (credentials redacted), and sends nothing.
remote: block appears in the preview with the host, interpreter, workdir, and GPU count the run would actually use:
remote: block fails here too — --dry-run resolves and validates it, so a malformed block exits 1 with Bad remote settings before dispatch rather than after an hour of rented GPU.
Answers “what am I about to do, and where?” before an hour of rented GPU.
Ctrl-C Stops the Remote Run
Ctrl-C during the log tail is not “just close the local tab”. The dispatcher forwardsSIGINT / SIGTERM to the remote runner, which stops the training process — the same as the desktop Stop button.
A remote run that ends
failed (exit N) now exits 1 locally too, so $? and CI gating see the failure. Earlier the CLI printed the status and then exited 0, reporting success for a run that had died.Common Refusals (all before any SSH)
Each of these exits1 before a connection is opened. The forbidden value is never echoed back.
The credential check runs before the unknown-key check on purpose. A forbidden key like
password is also technically “unknown”, but telling the user “you misspelled it” is the wrong advice — the fix for a typo is to spell it right, which here would mean trying harder to put a password in a file that gets shipped to another machine.Best Practices
Put connection details in ~/.ssh/config
Put connection details in ~/.ssh/config
Name only the alias in PraisonAI; keep host, user, and key in your ssh config:Then
--remote-host gpubox, remote: {host: gpubox}, and the desktop’s alias field all mean the same thing.Dry-run before you rent the GPU
Dry-run before you rent the GPU
--dry-run prints the resolved config with the remote: block and sends nothing. It catches a wrong host or wrong workdir before an hour of rented GPU.Use this for 'kick it off and watch it'
Use this for 'kick it off and watch it'
This shortcut is one command — good for a single job you want to launch and tail. For manual preflight, detached start, reattach later, fetch the adapter, and stop, use the standalone
praisonai-train remote sub-app.Combine with multi-GPU on the remote box
Combine with multi-GPU on the remote box
praisonai-train llm --config config.yaml --remote-host gpubox --remote-gpus 4 sets the GPU expectation for the remote run. See Multi-GPU for the launcher side.Related
praisonai-train Package
The full
praisonai-train CLI including llm, serve, export, and remote.Remote Sub-app
Manual preflight, detached start, reattach, fetch, stop.
Multi-GPU Training
torchrun across every GPU on the host.
Train
Local training flow and full
config.yaml reference.
