API
Exported names, grouped by the command they belong to. The longer guide is the DistSSHKit manual.
Run
go! runs a script as-is on one or more slots. drive! runs a driver script on workers. ride! is experimental: it rewrites map and filter in a script onto workers.
DistSSHRun.DriveHostStatus — Type
Live per-host membership during a drive (not the post-run collect outcome).
state is :joined, :alive, :left, or :collect_pending. last_seen is Unix time when this host last appeared in Distributed.workers(), or nothing if it has not been observed since join.
DistSSHRun.DriveResult — Type
Outcome of drive! (and similar CLI steps that return an exit code).
ok is true only when the run finished with exit 0. By default that includes the placement contract: listed parent / child hosts joined, stayed, and collect succeeded (require_all_hosts=true). require_all_hosts=false keeps a partial run as ok=true.
output_dir / log_dir are the directories actually used for this run — resolved the same way drive reports Results: / writes its log, even when drive! was not called with output_dir= / log_dir=. nothing when no real run happened (e.g. built by hand) or, for log_dir, when logging was disabled.
hosts is one HostRunResult per host that joined as a worker, in the order results were collected. Empty when no host-collection step ran (e.g. built by hand, or a run with no remote/local-only hosts).
run_dir is this run's DISTSSHKIT_RUN_DIR when the driver allocated one. Read it with result_run_dir. result_provenance reads run.toml from it. result_content_tree_hash and result_remote_run_id read provenance.shipped in that file.
Result fields and positional constructors are not API. Result structs are not a stable serialization format. serialize and JLD2 of a result are unsupported. The supported record is kit.result.
DistSSHRun.GoResult — Type
Outcome of go!. On failure, failed_step is "sync", "run", or "collect".
run_dir is this run's DISTSSHKIT_RUN_DIR when one is active. Read it with result_run_dir. result_provenance reads run.toml from it. result_content_tree_hash and result_remote_run_id read provenance.shipped in that file. Omitted run_dir uses kit_run_dir, which is nothing outside a run.
Result fields and positional constructors are not API. Result structs are not a stable serialization format. serialize and JLD2 of a result are unsupported. The supported record is kit.result.
DistSSHRun.HostRunResult — Type
Per-host outcome of the drive result-collection step.
ok is false when SSH / find / rsync raises while collecting from host. An empty file list after a successful probe is not an error. error is the message string, or nothing on success. An AbstractString is stored as-is so kit.result round-trips; other values use sprint(showerror, error).
DistSSHRun.KitProcess — Type
Handle to a detached execute! child (detached=true).
process is the julia -m DistSSHKit go|drive|ride subprocess. run_dir is always allocated in the parent before spawn (pid / kit.out / run.toml). Read it with result_run_dir. The field is not API. output_dir is the artifact root when known at spawn (go / ride, explicit output_dir=, or inherited DISTRIBUTED_OUTPUT_DIR). Detached :drive without those leaves output_dir as nothing so the child can honor init_output_dir!. log_dir is nothing for :go / :ride. wait returns a KitRunResult; it does not fill output_dir on this handle.
DistSSHRun.KitRunResult — Type
Shared run outcome (ok, kind, dirs, failed_step, exit_code, hosts, stop).
kind is :go, :drive, :ride, or :pipeline. Convert with kit_run_result. hosts is post-run collect (HostRunResult); empty for go, hung wait, or a drive that never collected.
stop is the terminate! / terminate_run! ladder outcome. nothing on a run that was not stopped that way. :within_grace means one SIGINT was sent and the process was gone before SIGTERM, so workers had that interrupt_grace window. :sigterm and :sigkill mean that window ended and the ladder escalated. :no_sigint means interrupt_grace was 0, so SIGINT was not sent and the ladder went to SIGTERM (then SIGKILL if the process was still alive). The same string is stop in kit.result. When the kit run directory already has this package's run.toml, stop is set there too. schema stays 1. An unknown stop string is ignored.
run_dir is this run's DISTSSHKIT_RUN_DIR when one is known. Read it with result_run_dir. result_provenance reads run.toml from it. result_content_tree_hash and result_remote_run_id read provenance.shipped in that file. A RideResult is not accepted there; convert it with kit_run_result first.
Result fields and positional constructors are not API. Result structs are not a stable serialization format. serialize and JLD2 of a result are unsupported. The supported record is kit.result.
DistSSHRun.RideResult — Type
Outcome of ride!. Experimental.
output_dir is the ride batch directory. run_dir is the DISTSSHKIT_RUN_DIR captured while that run was active. ride! restores the previous directory before it returns. Read the saved directory with result_run_dir. result_provenance does not accept a RideResult; convert it with kit_run_result first.
Result fields and positional constructors are not API. Result structs are not a stable serialization format. serialize and JLD2 of a result are unsupported. The supported record is kit.result.
DistSSHRun.drive! — Method
drive!(session::KitSession, script; plan=nothing, args=[], ...)
drive!(script, workers...; kwargs...)
drive!(script, workers::AbstractVector; kwargs...)Run a driver script on workers. Tokens match the CLI (parent:2, child:user@host:1). Load is the master include. Publish sends definitions to workers (not top-level work). Run is main() when defined. Use go! / ride! when that matches the script.
drive!("job.jl", "parent:2"; args=["8"])
drive!(session, "job.jl") # uses `session.tokens`With sync omitted or false, prepare remotes with setup! or CLI setup first; remotes are checked before execution. Optional sync=:sync / sync=:ship_tree copies, then checks. After :ship_tree, hosts that still lack Manifest deps get instantiate! (same as CLI drive --ship-tree). Git parity is off by default (skip_hash_check=true). With sync=:ship_tree, parity stays off even if skip_hash_check=false (no remote .git/). require_all_hosts=true (the default; CLI --require-all-hosts) fails unless every explicit parent:N / child:NAME:N joined, stayed through the run, and collect succeeded. Pass require_all_hosts=false or CLI --best-effort for a partial run.
A collect root that is the project or a parent of it stops the run before main and before collect, with exit code 1. That includes DISTRIBUTED_COLLECT_DIRS and a default root from DISTRIBUTED_OUTPUT_DIR.
julia sets the remote Julia binary (nothing / "auto" → detect; same as CLI --julia). plan is an optional explicit WorkerPlan. pipeline! syncs separately and does not pass sync= into drive!, so it does not instantiate after rsync.
sync_script=true (CLI --sync-script) re-includes the full driver on workers. The default publishes definitions / using / import / include only, so top-level work on Load is not repeated on workers.
Ctrl-C restores the active project and the DISTRIBUTED_* entries this call changed, then rethrows InterruptException or, when Julia has it, Base.CancellationRequest. drive! does not exit and does not throw the private CLI exception. On Julia 1.14 the caller's task stays cancelled after that exception.
DistSSHRun.drive_host_status — Method
drive_host_status(output_dir) -> Vector{DriveHostStatus}
drive_host_status(kp::KitProcess) -> Vector{DriveHostStatus}Live per-host membership for a running (or recently collecting) drive or ride. Reads kit.hosts.status. Empty when the file is missing (too early, a go run, or a hard death before join). This is not DriveResult hosts (post-run collect); that vector is stored in kit.result as hosts.
DistSSHRun.go! — Method
go!(script, workers...; kwargs...)
go!(script, workers::AbstractVector; kwargs...)Run an as-is complete job on one or more slots (local and/or remote).
[provenance] records this controller under julia.parent and machine.parent. Each slot that ran the script is under workers, grouped by placement token. The manifest hash and the git snapshot are taken when go! starts.
go!("job.jl") # one parent slot
go!("job.jl"; repeat=100) # 100 independent runs on parent
go!("job.jl", "parent:2"; args=["8"])
go!("job.jl", "child:user@h1:1", "child:user@h2:1"; remote="/path/to/project")Each slot gets DISTRIBUTED_OUTPUT_DIR pointing at {script}/.distsshkit/go/<stem>_<UTC>/<slot>/. Override the batch root with output_dir (CLI: --output-dir). For backward compatibility collect_spec::AbstractString also sets the batch root, but passing both output_dir and collect_spec::String is an error. collect_spec === false means "skip collect" and is orthogonal to output_dir.
Default sync is false (no pre-run sync; remotes are checked first — setup is assumed done). Pass sync=:sync or sync=:ship_tree to copy, then check. After :ship_tree, hosts that still lack Manifest deps get instantiate! before the check. go! has no git-parity gate; use drive! with skip_hash_check=false (CLI: drive --require-git) when you need that.
julia sets the Julia binary for each slot (nothing / "auto" → detect; same as CLI --julia).
allow_mismatch (CLI --allow-mismatch) waives Julia version / commit, DistSSH* Manifest versions, and/or Manifest path when a slot does not match the job tree. Default is to error. Same tokens as drive / ride: julia, distssh, manifest.
When workers is empty and hosts_file is omitted, DISTSSHKIT_HOSTS_FILE is still read (API go!("job.jl")). Non-empty workers (CLI host_tokens) does not re-read that ENV.
parent:N and child:NAME:N mean N independent full-job runs (not Distributed workers), started together. repeat=N (CLI --repeat N) is the total number of those runs, spread round-robin across listed hosts (no tokens → all on parent). :N on a token is a per-host cap when repeat is set; omit it to leave that host uncapped. Without repeat, every listed token needs :N (omitting it is not 1). Empty tokens stay one parent slot. path_anchor shortens displayed paths (CLI passes kit project root).
DistSSHRun.kit_result_from_dir — Method
kit_result_from_dir(output_dir) -> Union{Nothing,KitRunResult}Read output_dir/kit.result written by a finished go / ride / drive child. nothing when the file is missing or unreadable (still running, or a hard death).
DistSSHRun.kit_run_result — Method
Build KitRunResult from a kit outcome (:go / :ride / :drive / :pipeline).
DistSSHRun.print_ride — Method
Print a RideResult. Field names match go / drive (Script:, Workers:).
DistSSHRun.report_go_errors — Method
report_go_errors(result::GoResult; io=stderr)Print a short summary when go! failed. Returns result.ok.
DistSSHRun.report_run_errors — Method
report_run_errors(result; io=stderr)Print a short summary when a kit run failed. Accepts KitRunResult or a typed outcome (GoResult / RideResult / DriveResult / PipelineResult). Returns result.ok.
DistSSHRun.result_content_tree_hash — Method
result_content_tree_hash(result) -> Union{Nothing, String}content_tree_hash from this run's controller run.toml (provenance.shipped), or nothing when that ship was not recorded.
Schema stays 1. An absent or empty key means not recorded. result is a DriveResult, GoResult, or KitRunResult. A RideResult goes through kit_run_result first.
A SyncResult from setup! / sync! with :ship_tree, and a ShipTreeResult from ship, return the hash of that ship. Any other SyncResult returns nothing.
DistSSHRun.result_provenance — Method
result_provenance(result) -> Union{Nothing, AbstractDict}Read run.toml from result_run_dir. nothing when that directory is unset or the file is missing.
result is a DriveResult, GoResult, or KitRunResult. A RideResult is not accepted; convert it with kit_run_result first. A KitProcess is not accepted; wait it first.
DistSSHRun.result_remote_run_id — Method
result_remote_run_id(result) -> Union{Nothing, String}Remote runs/<run_id>/ id from this run's controller run.toml (provenance.shipped.run_id), or nothing when that ship was not recorded.
Schema stays 1. An absent or empty key means not recorded. This is not DISTSSHKIT_RUN_DIR. result is a DriveResult, GoResult, or KitRunResult. A RideResult goes through kit_run_result first.
A SyncResult from setup! / sync! with :ship_tree, and a ShipTreeResult from ship, return that remote run_id. Any other SyncResult returns nothing.
DistSSHRun.result_run_dir — Method
result_run_dir(result) -> Union{Nothing, String}This run's DISTSSHKIT_RUN_DIR, or nothing when the result has none.
result is a DriveResult, GoResult, KitRunResult, RideResult, or KitProcess. Result fields and positional constructors are not API.
DistSSHRun.ride! — Method
ride!(script, workers...; args=[], spi_check=false, output_dir=nothing, project=pwd())Experimental. Rewrite map / filter / simple comprehensions / independent indexed for (dest[i] = …) and run the script on Distributed workers (parent and optional SSH child:). Rejects Distributed vocabulary (use drive!).
Worker add for SSH children is the same add_drive_workers! path as drive. The job project is Pkg.activated on the parent first (drive does this before using the app package on every process). The script still runs on the parent (no driver include on workers). Named functions used by map / filter are sent to workers as a prelude.
--spi-check (default off) compares the distributed result to a sequential map / filter. Unknown syntax stays sequential. Listed child: hosts are fail-closed (require_all_hosts=true). Queue: execute! :ride (detached=true writes kit.result like go; SSH child: also writes kit.hosts for terminate!).
DistSSHRun.terminate! — Method
terminate!(kp::KitProcess; grace=10, interrupt_grace=nothing) -> KitRunResultStop a detached run. Omit interrupt_grace and the wait is 30 seconds, or DISTSSHKIT_WAIT_SIGINT_GRACE when that variable is set in this process. The driver host does not read it. An explicit interrupt_grace keyword wins, including 0, which sends no SIGINT. A negative value or NaN is an error. The 30 second default is a constant, chosen from the internal stop budgets, not computed when terminate! runs.
A positive value sends SIGINT once and waits that many seconds. There is no retry. A drive child runs its Ctrl-C path: one kill -INT per SSH host, aimed at the worker julia pid (WorkerConfig.ospid, the worker's getpid()), then a fixed 3 second settle, then rmprocs. That ssh is bounded by the SSH connect timeout and uses ServerAliveInterval=5 and ServerAliveCountMax=1. A write during the settle window is best-effort and should be small. Checkpoint large state during the run, to a temporary file, then rename it. A 1 GiB write in 0.4–0.7 seconds on one Mac mini is a lower bound. On Julia 1.13 a second Ctrl-C forces the driver out of that cleanup. On Julia 1.13, a driver waiting in pmap ignores SIGINT, so this wait runs out and SIGTERM stops it. With the defaults that is 30 seconds plus grace (10) plus one second after SIGKILL, about 41 seconds, and then the tagged pkill below. A process-group SIGINT, as from a terminal Ctrl-C, also misses that path on Julia 1.13: the driver exits 1 and does not send kill -INT. Measured on macOS. On Julia 1.14 the driver exits 130, but a worker can be removed before it sees the interrupt. A go or ride child is julia -m with exit-on-sigint, so SIGINT runs atexit and does not enter catch or finally. Then SIGTERM, wait up to grace seconds (0 sends SIGTERM and does not wait), then SIGKILL if the process is still alive. Then pkill only processes tagged with this run's job_id (from kit.job), never julia.*--worker. Without job_id, only the child is signaled. That pkill is one SSH command per host, in parallel, deduplicated, with its own 15 second bound (SSH connect plus margin). It does not spend interrupt_grace. Worst case for those two stages is interrupt_grace plus that bound. pkill exit 1 means nothing matched and is success. Hosts that cannot be reached are named in one warning, and this still returns. The remote pattern is [d]istsshkit-job:…, so pkill -f does not match the sh -c line that contains the command.
The returned KitRunResult stop is that ladder outcome. The same string is written to kit.result. When run_dir holds this package's run.toml (schema = 1, writer starting with DistSSHRun), stop is set there too. Artifact output_dir / log_dir are not rewritten.
DistSSHRun.terminate_run! — Method
terminate_run!(output_dir; grace=10, interrupt_grace=nothing, log_dir=nothing, kind=:go) -> KitRunResultLike terminate! after losing KitProcess: read kit.pid / kit.job / kit.hosts under output_dir. interrupt_grace is the same SIGINT stage, including the 30 second default and DISTSSHKIT_WAIT_SIGINT_GRACE in this process. kind is only used when kit.result is missing. stop is the ladder outcome, including on that synthetic result. run.toml is stamped in the kit run directory named by kit.run_dir next to kit.pid, or in output_dir when that directory already holds this package's run.toml.
DistSSHRun.worker_pmap — Method
worker_pmap(f, collection)Like Distributed.pmap, but evaluates f with Base.invokelatest on each element.
After drive syncs your driver to workers and loads the project package, plain pmap is usually enough. Use worker_pmap when a callback still hits Julia 1.12+ world-age errors (for example, a function reference or closure captured before package load).
DistSSHRun.worker_seed — Method
Stable worker seed from the job seed and a launch rank. Does not read myid().
Base.wait — Method
wait(kp::KitProcess; timeout=nothing) -> KitRunResultBlock until the detached child exits, then return a KitRunResult.
Does not mutate kp.output_dir / kp.log_dir. After a detached :drive that deferred the artifact leaf, read the returned result (or kit_result_from_dir / read_kit_run_toml on the directory from result_run_dir).
timeout is wall-clock seconds until the child process exits (not the drive worker heartbeat). nothing waits forever. On timeout the child is left running: failed_step is "hung", exit_code is 124, and owned stdio stays open. Call terminate! if the hang is fatal.
If the child wrote kit.result under run_dir or output_dir, that file is the source of truth (including failed_step from go! / ride!). Otherwise failed_step is "go" / "ride" / "drive" on a non-zero exit — the parent cannot recover a more specific in-process step name.
Best-effort: remove kit.pid if it still names this child (pid captured before wait on the OS process; after reap getpid can throw ESRCH). Not on a hung timeout.
DistSSHRun.execute_kwargs_from_parsed — Function
execute_kwargs_from_parsed(parsed; kind) -> Dict{Symbol,Any}Keywords for execute! (detached=true) from parse_go_args / parse_drive_args / DistSSHRun.parse_ride_args. Keys are a subset of execute_detached_accepts.
Does not include hosts_file / --hosts: those tokens belong in host_tokens (kind required). Does not set project, detached, yes, job_id, remote, or stdio. Drive --workers is :workers only when the parser set default_workers. dir, threads, env_allow, and env are copied only when parsed has that property and the value is not nothing. The go / drive / ride parsers do not grow those fields.
DistSSHRun.detached_launch — Function
detached_launch(kp::KitProcess) -> NamedTuple(dir, threads, dropped, sensitive) for a detached execute! child.
dir is the child working directory. threads is the --threads value, or "unset" when that flag was omitted. dropped is the sorted list of parent environment names that were not passed through. sensitive is the sorted list of names the caller set with env_allow or env even though they match the secret-name denylist. Values are not included.
A handle this function did not record returns dir="", threads="unset", and empty lists. Local go slots and local drive workers inherit the child environment, so a kept SSH_AUTH_SOCK reaches them. SSH workers do not receive this process's agent socket.
Placement and host facts
WorkerPlan is explicit parent:N / child:NAME:N. pool! inventories cores and RAM. hostinfo collects via DistSSHBase.collect_host_facts and prints with print_hostinfo (per-host labeled layout; OS product vs kernel kept separate; missing fields are -).
DistSSHRun.HostInventory — Type
One host in a ResourcePool. Missing numbers are nothing, not 0.
DistSSHRun.ResourcePool — Type
Cluster view of listed hosts: totals plus per-host health.
ok is false if any listed host failed the probe (fail-closed). cores and gb sum reachable hosts that reported that field; failed rows stay in hosts. Does not change go / drive --best-effort.
DistSSHRun.WorkerPlan — Type
Explicit worker counts per host (parent_workers + child_workers).
DistSSHRun.pool! — Method
pool!(session) -> ResourcePoolProbe listed hosts for cores and RAM via collect_host_facts. Unreachable hosts stay in the list with ok=false. The pool is ok only when every listed host probed successfully. Does not start workers.
DistSSHRun.print_hostinfo — Method
Print host facts. Always writes io (requested results, including --quiet).
DistSSHRun.print_pool — Method
Print cluster totals first, then per-host health. Always writes io (stdout).
Pipeline
pipeline! chains runs. collect! brings the outputs back.
DistSSHRun.CollectResult — Type
Outcome of collect!.
DistSSHRun.PipelineConfig — Type
PipelineConfigSettings for pipeline!: sync, worker tokens, driver run, and optional collect.
Worker placement uses CLI-style tokens (parent:2, child:user@host:1). Listed tokens need :N. Set sync=false to skip sync. Set collect=false to skip rsync-back. Git parity is off by default; pass skip_hash_check=false (or CLI --require-git) to require matching remote commits.
julia sets the remote Julia binary (nothing / "auto" → detect; same as CLI --julia). Prefer pipeline!(driver, workers...; …) for day-to-day use.
DistSSHRun.PipelineResult — Type
Combined outcome of pipeline!. On failure, failed_step names the step that stopped.
DistSSHRun.collect! — Method
collect!(
session::KitSession,
local_root::AbstractString;
merge=false,
hosts=nothing,
julia=nothing,
)Pull result files from SSH hosts into local_root with stdlib Tar. Remote mtimes are not kept. A non-executable file arrives as mode 0644, and an executable file as 0755. A symlink that points outside the copied tree is refused. julia is the remote executable (nothing auto-detects).
Collect modes:
merge=false→ collect-missing (CLIdrive --collect-missing)merge=true→ collect-overwrite (CLIdrive --collect-overwrite)
Distinct from drive's automatic post-run-new (sentinel / newer-than-run) and go's slot-overwrite. Returns CollectResult.
A root that is the session project or a parent of it is refused (ok=false, exit code 1). Point it at a result directory inside the project.
DistSSHRun.pipeline! — Method
pipeline!(driver, workers...; kwargs...) -> PipelineResult
pipeline!(driver, workers::AbstractVector; kwargs...) -> PipelineResult
pipeline!(config::PipelineConfig) -> PipelineResultRun the usual remote workflow: optional sync, driver, optional collect. Does not call setup!; prepare remotes first.
Worker tokens match the CLI (parent:2, child:user@host:1). Listed tokens need :N. Keyword args are passed to the driver; remote is the remote project path. Default yes=true skips confirm prompts.
pipeline!(driver, "parent:2"; args=["8"])
pipeline!(driver, "child:user@h1:1", "child:user@h2:1"; remote="/path/to/project", args=["8"], collect=true)Remote hosts default to no pre-run sync; set sync=:sync / :ship_tree explicitly. Collect defaults on when remotes are present (collect=false to skip). pipeline! sync=:ship_tree copies only; it does not instantiate missing Manifest deps. Use drive! with sync=:ship_tree, or setup! :instantiate, for that.
Returns PipelineResult; check result.ok or use report_pipeline_errors.
DistSSHRun.pipeline_config_from_env — Method
pipeline_config_from_env(; driver=...)Build PipelineConfig from environment variables.
| Variable | Role |
|---|---|
DISTSSHKIT_HOSTS | Comma-separated placement tokens (parent:N / child:NAME:N) |
DISTSSHKIT_HOSTS_FILE | Hosts file (appended after DISTSSHKIT_HOSTS, same order as CLI) |
DISTRIBUTED_REMOTE_PROJECT_ROOT | Remote repo root |
DISTRIBUTED_PROJECT_ROOT | Local project root |
DRIVER | Driver script path |
SYNC_MODE | rsync, sync, or off |
JULIA_DISTRIBUTED_EXE | Remote Julia path (same as CLI --julia; auto / unset → detect) |
DISTSSHKIT_YES / DISTSSHKIT_QUIET / DISTSSHKIT_PROGRESS / DISTSSHKIT_VERBOSE | Same as CLI -y / -q / --progress / --verbose |
DistSSHRun.report_pipeline_errors — Method
report_pipeline_errors(result::PipelineResult; io=stderr)Print a short summary when pipeline! failed. Returns result.ok.
Setup
setup! prepares a host. sync! and instantiate! are the same jobs as setup --sync and setup --instantiate.
DistSSHRun.ConfirmPathMismatch — Type
ConfirmPathMismatch(mode, given, expected)setup! :delete or :prune received a confirm_path that is not the remote target. mode is :delete or :prune. given is the path that was passed. expected is the target. Do not copy expected into a retry.
DistSSHRun.HostResult — Type
Per-host outcome for sync and similar operations.
DistSSHRun.KitSession — Type
Runtime context for sync!, drive!, collect!.
DistSSHRun.KitSession — Method
KitSession(; project=pwd(), workers=[], remote=nothing, hosts_file=nothing,
quiet=false, verbosity=nothing, yes=true, include_parent_for_size=false)Build a session for drive APIs. workers is a CLI-style host list. setup! / pool! / sync! / collect! accept a bare list (child:user@host). go! / drive! / ride! / pipeline! require :N on listed tokens (parent:2, child:user@host:1).
session.hosts keeps remote SSH names only (for sync / collect). session.tokens keeps the original tokens (including parent:N). remote is the remote project path (DISTRIBUTED_REMOTE_PROJECT_ROOT). A value that starts with ~ stays a remote-shell layout (not expanduser on the kit parent).
hosts_file is appended when given. ENV["DISTSSHKIT_HOSTS_FILE"] is used only when hosts_file is omitted and workers is empty (same as go!). Non-empty workers do not re-read that ENV. verbosity is :verbose | :progress | :quiet (quiet=true implies :quiet). API default yes=true skips confirm prompts.
DistSSHRun.SyncResult — Type
Outcome of sync! (rsync or git sync). cancelled is set when a confirm prompt is aborted.
warnings is empty except for setup!(session, :check), which records each warning it printed. result_content_tree_hash and result_remote_run_id read the ship hash and remote run_id from a :ship_tree result, and return nothing for any other mode. Fields are not API.
DistSSHRun.instantiate! — Method
instantiate!(session::KitSession; julia="auto") -> SyncResultRun Pkg.instantiate on each SSH host in session (parallel).
The worker stops, and names help setup, when it has no reachable registry, when Pkg.is_manifest_current is not true (a Manifest with no project_hash counts), or when Manifest julia_version is missing or its minor differs from that Julia. Otherwise the worker runs Pkg.instantiate(; manifest=true, update_registry=false, julia_version_strict=true).
julia is the remote Julia path ("auto" detects per host, same as setup --instantiate / drive --julia). Returns SyncResult.
Typical first-time remote prep:
session = KitSession(workers=["child:user@h1"], remote="/path/to/project", yes=true)
setup!(session, :ship_tree, :instantiate) # or sync!(…; mode=:ship_tree) then instantiate!Also available as setup!(session, :instantiate; julia=…).
DistSSHRun.normalize_remote_confirm_path — Method
normalize_remote_confirm_path(path) -> StringSyntactic form of a remote confirm path. Strips a trailing / except on /, collapses // and /./, rejects .., and writes a relative path as ~/…. Does not expand ~ and does not call expanduser, abspath, or realpath.
Examples
julia> using DistSSHRun
julia> DistSSHRun.normalize_remote_confirm_path("~/App.jl/")
"~/App.jl"
julia> DistSSHRun.normalize_remote_confirm_path("App.jl")
"~/App.jl"DistSSHRun.setup! — Method
setup!(session::KitSession, mode::Symbol; kwargs...) -> SyncResult
setup!(session::KitSession, modes::Symbol...) -> SyncResultPrepare SSH hosts — same jobs as julia -m DistSSHKit setup --….
mode | CLI | Notes |
|---|---|---|
:delete | --delete | Destructive. Requires confirm_path. session.yes does not delete. Refuses a present unowned Ship run.toml |
:ship_tree | --ship-tree | Walk the ship root and each directory's .gitignore (case-sensitive). No git binary. A gitignored project or Manifest file is omitted with one warning. !LocalPreferences.toml ships that file. Declared inputs do not. Creates a missing remote root when safe (~/… under home, or absolute with an existing parent). Tar into runs/<run_id>/src/, empty out/, DistSSHRun stamp. Does not instantiate |
:clone | --clone | Requires repo=; clone runs on the remote |
:sync | --sync | Push the local branch to origin, then detach each remote at that commit; confirm unless session.yes. A dirty tree is refused |
:pull | --pull | Detach each remote at the local commit. Does not push to origin and does not run git pull; confirm unless session.yes. A dirty tree is refused |
:instantiate | --instantiate | julia= (default "auto") |
:juliaup | up | Align Julia via juliaup on child:NAME and/or parent ($HOME/.juliaup or Homebrew); confirm unless session.yes. Tip if kit parent patch lags channel latest |
:juliaup_update | up update | juliaup update on those hosts (no default); confirm unless session.yes |
:check | --check | ignore_julia_version=, check_code_sync= |
:runtest | --runtest | job Pkg.test() on remotes; julia= |
:cleanup | --cleanup | Kill stale workers (no confirm) |
:prune | --prune | .distsshkit go/drive/setup/runs leaves. Requires confirm_path. session.yes does not delete. older_days=, id= |
:remote_root | --remote-root | remote= must be absolute. Creates that directory only when the parent exists. Confirm unless session.yes |
Confirmations for other modes follow session.yes (CLI -y). :delete and :prune authorize only confirm_path: a String when the session has one SSH host, or a Dict of host alias => path. A host with no key is left in place. An unknown key is an error. A mismatch throws ConfirmPathMismatch. These two modes do not read stdin. Any other mode rejects confirm_path. Multiple modes run in order and stop on the first failure:
session = KitSession(workers=["child:user@h1"], remote="~/proj", yes=true)
setup!(session, :ship_tree, :instantiate)
setup!(session, :check; ignore_julia_version=true)sync! / instantiate! remain as thin aliases for the common deploy steps. Prefer setup! when you want the full CLI vocabulary in one place.
DistSSHRun.sync! — Method
sync!(session::KitSession; mode=:sync)Sync local project to SSH hosts (call explicitly; go/drive do not call this by default).
mode=:sync— push the local branch to origin, then check out that commit on each remote as a detached HEAD (confirm unlesssession.yes). Does not rungit pull. A dirty tree is refused.mode=:ship_tree— pack the project (each directory's.gitignore) into a tar and extract underruns/<run_id>/src/(confirm unlesssession.yes).
Also available as setup!(session, :ship_tree) / setup!(session, :sync).
Returns SyncResult. For :ship_tree, result_content_tree_hash and result_remote_run_id read that ship. Other modes return nothing.
snapshot, ship, and ship_send_list are public and are not exported.
DistSSHRun.ship_send_list — Function
ship_send_list(root) -> Vector{String}Relative paths a ship tar contains for this directory, sorted, with / separators. The same paths with or without a .git directory.
The walk applies each .gitignore at root and below (case-sensitive). .git/info/exclude, core.excludesFile, and a .gitignore above root are not used. The git index is not consulted, and git is not run. .git and .distsshkit are omitted. A tracked file that .gitignore names is omitted. A gitignored LocalPreferences.toml stays out unless a later ! pattern puts it back. Declared inputs and fifos and other unshippable nodes are omitted. Ancestor directories of a kept path are included.
This does not print the gitignored-project warning. That warning stays on ship. rsync_send_list is the git list for --clone, --sync, and --pull.
The first call loads GitIgnore, which can write a compiled cache into the active depot. It does not write the project or run.toml.
DistSSHRun.snapshot — Function
snapshot(local_root; allow_external_symlinks=false, ship_max_bytes=SHIP_MAX_BYTES_DEFAULT) -> ShipSnapshotBuild the ship tar in a temporary directory and record its content_tree_hash.
The caller owns snapshot_directory and deletes it, including the snapshot_tar file (ship.tar). This does not read depot preferences and does not send anything.
DistSSHRun.ship — Function
ship(snapshot, hosts, remote_root; confirm=false, record=true) -> ShipTreeResultSend snapshot's tar to runs/<run_id>/src/ on each host. Does not pack again and does not delete the tar.
The tar is hashed again immediately before sending. A different git-sha1 tree hash, or a missing tar, throws ArgumentError. Depot preferences that would apply and are not in the ship are refused here. confirm=false does not prompt. record=false does not keep this ship for controller run.toml in this process.
DistSSHRun.ShipSnapshot — Type
Tar built by snapshot and sent by ship.
snapshot_directory is the temporary directory the caller deletes. snapshot_tar is the ship.tar inside it. content_tree_hash is the git-sha1 tree hash recorded when the tar was built. Fields are not API.
DistSSHRun.ShipTreeResult — Type
Result of ship and ship_project_to_hosts!.
result_content_tree_hash and result_remote_run_id read the ship hash and the remote runs/<run_id>/ id. Fields are not API.
DistSSHRun.snapshot_directory — Function
Temporary directory that holds a ShipSnapshot tar. The caller deletes it.
DistSSHRun.snapshot_tar — Function
ship.tar inside snapshot_directory.
DistSSHRun.content_tree_hash — Function
git-sha1 tree hash recorded by snapshot.
Hosts, cache, and run directories
Names the commands above call: host tokens and SSH, the file cache, run directories, and help text. Every other public name is in this list too, including DistSSHBase and DistSSHUp.
DistSSHRun.DistSSHRun — Module
DistSSHRun — the DistSSHKit execution layer moved into this package.
One SSH run (setup, go, ride, drive, hostinfo, pool, demo, progress) and the bang API (go!, ride!, pool!, drive!, pipeline!).
DistSSHKit depends on DistSSHRun and DistSSHQueue and reexports their public names. Users add DistSSHKit and run julia -m DistSSHKit. This package can still be added on its own. The command is then julia -m DistSSHRun.
Package entry: exports, version, includes, main (@main on Julia 1.13+). CLI entries live under src/cli/; argv parsers under src/DistSSHRun/argv/.
DistSSHRun.SPINNER_FRAMES — Constant
Frames for the kit TTY spinner (kit_spin!) and matching queue chrome.
DistSSHRun.SetupWarning — Type
One warning printed by setup!(session, :check).
host is PARENT_HOST_NAME for a local warning. kind names the check. message is the same text warn printed.
DistSSHRun.allocate_output_dir — Method
allocate_output_dir(kind, script; project=pwd(), job_id=nothing) -> StringCreate a unique output directory for a later detached execute! and return its path. kind is :go, :drive, or :ride (the same values as execute!). The directory is created; pass it as output_dir=.
Layout is {script dir}/.distsshkit/<kind>/<script-stem>_<UTC-stamp>/. When job_id is set it is appended after the stamp (same charset as execute! job_id). The leaf is created with exclusive mkdir; if it already exists (same-second collision), a nanosecond suffix is retried so two allocations do not share a directory.
This matches omitted in-process defaults for go, ride, and drive: {script}/.distsshkit/<kind>/<stem>_<UTC>/. Drive still honors output_dir / --output-dir and a driver's init_output_dir! (DISTRIBUTED_OUTPUT_DIR) when those are set. Detached execute!(:drive) does not pin --output-dir unless output_dir= or inherited DISTRIBUTED_OUTPUT_DIR is set.
DistSSHRun.allocate_run_dir — Method
allocate_run_dir(kind, script; project=pwd(), job_id=nothing) -> StringCreate a unique Kit run directory (cancel / logs / run.toml), not the artifact output_dir.
Layout: {script dir}/.distsshkit/runs/<kind>/<script-stem>_<UTC-stamp>/. When job_id is set it is appended after the stamp (same charset as execute! job_id).
If that parent tree is not writable (read-only pkgdir / Registry install), the same leaf is created under {project}/.distsshkit/runs/…, then under tempdir()/distsshkit-runs/….
DistSSHRun.cache_remote_dir — Method
cache_remote_dir(remote_root) -> StringJoin remote_root with .distsshkit/cache/sha256 (same layout as local cache_relpath).
DistSSHRun.check_input_manifest — Method
Check manifest against root.
A regular file is the SHA-256 of its bytes. A symlink is the SHA-256 of its link text and is not followed. sha256sum -c follows a symlink and normally reports FAILED, and it opens paths literally so it can miss an NFD directory entry that matches an NFC manifest path. Use this function to verify both.
DistSSHRun.execute! — Function
execute!(kind, script, tokens=String[]; output_dir=nothing, args=String[], project=pwd(), sync=nothing, julia=nothing, detached=false, source=nothing, kwargs...) -> KitRunResult or KitProcessOne seam over go! / ride! / drive! for callers that pick the kind at runtime (kind ∈ (:go, :ride, :drive)), returning the shared KitRunResult instead of GoResult / RideResult / DriveResult.
execute!(:go, "job.jl", ["parent:2"]; args=["8"])
execute!(:ride, "job.jl", ["parent:2"])
execute!(:drive, "job.jl", ["parent:2"]; args=["8"])
wait(execute!(:go, "job.jl", ["parent:1"]; detached=true, args=["8"]))output_dir, args, project, sync, julia are the keywords go! and drive! already share (ride! ignores sync). With detached=false (default), any other keyword is forwarded to the chosen function.
detached=true spawns julia -m DistSSHKit go|ride|drive and returns a KitProcess. --project= is always the job project= when that tree has a Project.toml. The job must list DistSSHKit or DistSSHRun in [deps]; otherwise this throws instead of using serve's active project. Keywords are then an allow-list (unknown names throw): output_dir, args, project, sync, julia, quiet, verbosity, yes, remote, hosts_file, job_id, source, allow_mismatch, and drive-only log_dir, enable_log, package, require_all_hosts, skip_hash_check, workers, sync_script, allow_external_symlinks, dir, threads, env_allow, and env. source is a provenance dict for every kind. Detached passes it as DISTSSHKIT_SOURCE_*. Go-only repeat. Ride: spi_check (default false). Detached argv passes --spi-check when true and --no-spi-check when false, so an older child whose default is on still skips the compare. Neither go nor ride takes sizing flags. yes must be true (the default): an unattended child cannot answer a prompt. remote that starts with ~ is stored in DISTRIBUTED_REMOTE_PROJECT_ROOT as a layout path (not expanduser on the kit parent). Child stdio defaults to kit.out / kit.err in run_dir. Pass stdout / stderr (IO) to override; stdout=stdout inherits the parent. Parent redirect_stdout does not apply to the subprocess. Detached :drive omits --output-dir unless output_dir= or inherited DISTRIBUTED_OUTPUT_DIR is set, so init_output_dir! can choose the artifact root.
job_id, if given, is passed to the child as DISTSSHKIT_JOB_ID, which adds job=<id> to every progress: log line. DISTSSHKIT_PROGRESS=1 is --progress verbosity, not a watcher; read lines with DistSSHRun.parse_progress_line / DistSSHRun.kit_progress_latest. Omitted entirely when unset.
The detached child starts in dir (default: the project directory) and passes --history-file=no. threads defaults to 1, passed as --threads=1 (Threads.nthreads(:interactive) is 0 on Julia 1.13). threads=:inherit passes this process's resolved --threads spec. threads=:unset omits the flag. The child environment keeps an allowlist (PATH, HOME, JULIA_DEPOT_PATH, DISTSSHKIT_*, DISTRIBUTED_*, and the other baseline names). env_allow adds names to that baseline. :all copies every non-empty parent variable except the drops below. env sets values on the child and does not write this process. Names containing COOKIE, JULIA_LOAD_PATH, and the CLI include guards are never copied. A recognized proxy value that contains userinfo (http_proxy, https_proxy, all_proxy, no_proxy, and the uppercase names) is dropped unless that name is in env_allow or env. A case-sensitive substring denylist (SECRET, PASSWORD, PASSWD, TOKEN, API_KEY, APIKEY, ACCESS_KEY, PRIVATE_KEY, CREDENTIAL) drops baseline, prefix, and :all copies. An explicit env_allow or env name wins and is recorded as sensitive. A count of dropped names is logged. The names, not the values, are in detached_launch, run.toml [launch], and the debug log (JULIA_DEBUG=DistSSHRun). schema stays 1.
Local go slots and local drive workers inherit that environment, including SSH_AUTH_SOCK when it was kept. SSH workers do not receive this process's agent socket. A drive --isolated grandchild inherits the filtered environment. In-process execute! and julia -m DistSSHKit do not use this policy.
execute!(kind, script, tokens; detached=true, dir=pwd(), threads=:unset, env_allow=:all)That restore still drops JULIA_LOAD_PATH, the CLI include guards, names that contain COOKIE, names that contain a denylist substring, and a recognized proxy value that contains userinfo. Set a denylisted name or such a proxy value with env, or name it in an env_allow list. The list keeps the baseline and those names. It does not copy the rest of the parent environment. JULIA_LOAD_PATH, the CLI include guards, and names that contain COOKIE cannot be passed that way.
DistSSHRun.execute_detached_accepts — Method
execute_detached_accepts(kw; kind) -> BoolWhether execute!(kind, ...; detached=true) accepts keyword kw. Uses the same tables as the detached throw path, plus the named parameters (output_dir, args, project, sync, julia, detached, source, dir, threads, env_allow, env). source is a provenance dict. Detached passes it to the child as DISTSSHKIT_SOURCE_*. It is not a go! / ride! / drive! keyword. dir, threads, env_allow, and env are detached launch policy, not go! / ride! / drive! keywords.
DistSSHRun.explain_script_not_found — Method
Full script/driver-not-found message (headline + optional demo-related hint).
The demo tip stays here because it knows the bundled examples.
DistSSHRun.git_source_snapshot — Method
Git record of project, or nothing when git is missing or this is not a work tree.
Keys: commit, dirty, diff_sha256, captured, untracked. captured is "run". dirty is a Bool. untracked is an Int. Schema 1 run.toml / provenance.toml omit diff_sha256; the snapshot dict still has it for Queue. .distsshkit/ and .distsshqueue/ are not uncommitted changes.
DistSSHRun.kit_pid_file_running — Method
kit_pid_file_running(output_dir) -> BoolWhether kit.pid names a still-running child of this run. Requires DistSSHRun.kit_pid_alive and, when a start key is in the file, a match with kit_process_start_key. A leftover after SIGKILL whose pid was reused is false. One-line (pid-only) files keep the old probe. Missing file is false.
DistSSHRun.kit_run_dir — Method
ENV["DISTSSHKIT_RUN_DIR"] when set and non-blank, else nothing.
DistSSHRun.main — Function
main(args::Vector{String}=copy(ARGS))CLI entry. Prefer Julia 1.13+ and julia -m DistSSHKit SUBCOMMAND …:
julia --project=. -m DistSSHKit setup --clone child:host1 child:host2
julia --project=. -m DistSSHKit go SCRIPT.jl
julia --project=. -m DistSSHKit ride parent:2 SCRIPT.jl
julia --project=. -m DistSSHKit drive parent:2 script.jl
julia --project=. -m DistSSHKit hostinfo parent child:host1
julia --project=. -m DistSSHKit pool parent child:host1
julia --project=. -m DistSSHKit progress DIRmain remains for wrappers and tests; prefer -m day-to-day. A .jl path with no command is not implicit go.
DistSSHRun.no_command_message — Method
The .jl rejection sentence. name is the word the caller reports.
DistSSHRun.parse_drive_args — Method
Parse drive CLI arguments (same shape as other kit CLI parsers).
DistSSHRun.parse_go_args — Method
Parse go CLI arguments (same shape as other kit CLI parsers).
DistSSHRun.parse_ride_args — Method
Parse ride CLI arguments (same shape as other kit CLI parsers).
DistSSHRun.print_cli_error — Method
CLI user error on stderr (no stacktrace).
DistSSHRun.print_rejected_command — Method
Print the shared rejection lines. The caller prints the usage page.
script is the .jl sentence and NO_COMMAND_HINT_LINES. Otherwise this prints unknown_subcommand_message and RUN_SUBCOMMAND_EXPECTATION. DistSSHKit prints its Queue line after that expectation, then its own page.
DistSSHRun.println_kit_version — Function
Print DistSSHRun <version> (same as julia -m DistSSHKit --version).
DistSSHRun.push_cache! — Method
push_cache!(session; hashes=nothing) -> SyncResultStream local .distsshkit/cache/sha256/ blobs onto each SSH host with stdlib Tar. Does not delete remote blobs that were not in this push. Hosts run at most DISTSSHKIT_JOBS at a time (default 1). Host result order matches session.hosts. Project setup --ship-tree still excludes .distsshkit/; this call is the dedicated transfer.
hashes limits the push to those digests. nothing pushes every local blob. No SSH hosts → error. Empty cache → success with no host rows.
DistSSHRun.read_kit_run_toml — Method
Read run.toml from a run directory (or the file itself). nothing if missing.
DistSSHRun.resolved_placement_tokens — Method
Resolved parent:N / child:NAME:N lines from a WorkerPlan.
DistSSHRun.rsync_send_list — Method
rsync_send_list(local_root, env; warn=false) -> Union{Nothing, Vector{String}}Git send list for a work tree, relative to local_root. --clone, --sync, and --pull still use this list. setup --ship-tree does not: it walks the ship root and applies each directory's .gitignore there and below. A gitignored preference file is not added back.
Returns nothing outside a git work tree. An empty list throws ArgumentError. warn=true prints the ancestor-.gitignore warning once for this git list (files left out). The default does not print it, so a second call does not repeat the warning.
A 0.x patch does not change the paths this function returns.
DistSSHRun.show_drive_usage — Method
Print drive --help (same chrome as julia -m DistSSHKit drive -h).
DistSSHRun.show_go_usage — Method
Print go --help (same chrome as julia -m DistSSHKit go -h).
DistSSHRun.unknown_subcommand_message — Method
Unknown subcommand: plus name. DistSSHKit prints this sentence too.
DistSSHRun.DistSSHBase — Module
Host naming, SSH, paths, and help chrome shared by the DistSSH packages.
Internal to the DistSSH family. Not registered. DistSSHRun includes this source as DistSSHRun.DistSSHBase. Names marked public are a contract inside the DistSSH family. A 0.x patch does not change them.
DistSSHRun.DistSSHBase.PARENT_HOST_NAME — Constant
Reserved token for this job's parent (not an SSH host).
DistSSHRun.DistSSHBase.CliUsageError — Type
Usage rejected before the command ran. with_cli_exit returns 2.
DistSSHRun.DistSSHBase.HostFacts — Type
One requested host. Missing fields are nothing, never 0 or 0.0.
reachable is false when SSH (or the local probe) failed as a whole. A reachable host may still omit fields. Julia executable/version is optional: absence is a missing field, not a host failure. julia_version is the julia --version text (not a VersionNumber; it does not promise a commit).
os is the kernel family from uname -s (for example Darwin or Linux). os_version is a product/release id when available (sw_vers -productVersion or /etc/os-release VERSION_ID), never a kernel release. os_pretty is a product display name when available (sw_vers -productName or PRETTY_NAME). kernel_release is uname -r. Do not treat os_version as kernel_release. arch is uname -m. cpu_model is best-effort brand/model text.
DistSSHRun.DistSSHBase.cache_file — Method
cache_file(src; project=pwd()) -> StringCopy src into .distsshkit/cache/sha256/<digest> if that blob is missing or stale. Same contents share one file (no second copy). Returns the cache path. Does not rsync by itself; .distsshkit/ is excluded from project sync.
DistSSHRun.DistSSHBase.cache_path — Method
Absolute cache path under project for hash.
DistSSHRun.DistSSHBase.cache_relpath — Method
Project-relative cache path for digest hash (64 hex chars).
DistSSHRun.DistSSHBase.canonical_local_path — Method
Absolute local path with ~ expanded (canonical form for file I/O and comparisons).
DistSSHRun.DistSSHBase.cli_entry — Method
Package after julia -m. DistSSHKit until an outermost main sets one.
DistSSHRun.DistSSHBase.cli_heading — Method
Help title: DistSSHQueue setup.
DistSSHRun.DistSSHBase.cli_m — Method
julia -m DistSSHKit or the package that owns this CLI entry.
DistSSHRun.DistSSHBase.cli_m_project — Method
julia --project=. -m <entry>.
DistSSHRun.DistSSHBase.cli_parse — Method
cli_parse(f)Run a parser. An ArgumentError from f becomes CliUsageError. Any other exception propagates, including an ArgumentError the command throws after parsing.
DistSSHRun.DistSSHBase.cli_qhost — Method
Leading qhost for Kit's queue-host commands.
Empty when the entry is DistSSHQueue (julia -m DistSSHQueue setup).
DistSSHRun.DistSSHBase.cli_qhost_heading — Method
Help title for a queue-host command. Kit keeps the qhost word.
DistSSHRun.DistSSHBase.collect_host_facts — Method
Collect facts for one host (parent is local). Does not start jobs.
DistSSHRun.DistSSHBase.collect_host_facts — Method
Collect facts for each requested identity. One row per name, in order.
DistSSHRun.DistSSHBase.file_sha256 — Method
SHA-256 hex digest of file contents at path.
DistSSHRun.DistSSHBase.format_placement_token — Function
Format a go/drive/hostinfo token (parent[:N] or child:NAME[:N]).
DistSSHRun.DistSSHBase.get_remote_julia_version — Method
Get the Julia version on a remote host by running julia_path --version over SSH. Returns nothing on any failure (SSH, missing binary, unparseable output).
DistSSHRun.DistSSHBase.get_remote_julia_version_full — Method
Remote julia --version, keeping prerelease and build.
Same host and path as get_remote_julia_version. nothing on failure.
DistSSHRun.DistSSHBase.host_tokens — Method
host_tokens(hosts::AbstractVector{<:AbstractString}) -> Vector{String}
host_tokens(hosts::AbstractVector{Tuple{String,Union{Int,Nothing}}}; parent_workers=0)
host_tokens(parsed; kind::Symbol) -> Vector{String}Rebuild CLI host tokens for execute!.
Go tokens are the parser strings. Ride uses the same shape. Drive tuples plus parent_workers emit parent:N then child:NAME:N. kind must be :go, :drive, or :ride.
DistSSHRun.DistSSHBase.is_parent_host_name — Method
Whether host denotes this job's parent in drive/go/hostinfo.
Only parent matches. parenthost is rejected by parse_placement_token. A token local / localhost / l is an ordinary SSH child (child:local).
Examples
julia> using DistSSHRun
julia> DistSSHRun.is_parent_host_name("parent")
true
julia> DistSSHRun.is_parent_host_name("parenthost")
false
julia> DistSSHRun.is_parent_host_name("local")
false
julia> DistSSHRun.is_parent_host_name("worker1")
falseDistSSHRun.DistSSHBase.is_sigint — Method
is_sigint(e) -> BoolTrue when e is Ctrl-C delivered as an exception. Julia 1.13 throws InterruptException. Julia 1.14 throws Base.CancellationRequest when exit_on_sigint is off. include wraps either in LoadError, a task wraps it in TaskFailedException, and a worker wraps it in RemoteException (captured / ex). Those wrappers are opened here.
DistSSHRun.DistSSHBase.julia_project_rel — Method
--project value relative to resolve_pkg_env env_dir (. when they match).
DistSSHRun.DistSSHBase.manifest_path — Method
manifest_path(project::AbstractString) -> Union{Nothing,String}Absolute path of the Manifest file Base would use for project, or nothing when that lookup finds no file.
project is a directory or a project file (JuliaProject.toml or Project.toml). The file is whatever Base.project_file_manifest_path returns: the workspace Manifest, an explicit manifest entry, then the first existing name in Base.manifest_names (JuliaManifest-v*, Manifest-v*, JuliaManifest.toml, Manifest.toml).
DistSSHQueue submit should call this so a versioned Manifest counts as present. A directory with no project file returns nothing.
DistSSHRun.DistSSHBase.parse_julia_version_full — Method
Parse julia --version, keeping prerelease and build.
julia version 1.14.0-alpha1 is v"1.14.0-alpha1". Unreadable text is nothing. parse_julia_version still returns major.minor.patch only.
DistSSHRun.DistSSHBase.parse_placement_token — Method
Classify a go/drive/hostinfo placement token.
Returns (role, name, n) where role is :parent or :child, name is parent or the SSH host, and n is the explicit count or nothing.
DistSSHRun.DistSSHBase.posix_quote — Method
posix_quote(word::AbstractString) -> StringOne POSIX single-quoted word for a remote sh command.
A ' inside word becomes '\''. Every other byte is copied, including newline. NUL throws ArgumentError (a remote process cannot carry it). A path goes through _remote_shell_path_word, which rejects a control character. A host goes through validate_ssh_host, which rejects a name that starts with - and a control character.
DistSSHRun.DistSSHBase.print_colored — Function
Print msg with color when the kit would use ANSI (TTY, no NO_COLOR).
DistSSHRun.DistSSHBase.print_help_blank — Function
One blank line in kit --help output.
DistSSHRun.DistSSHBase.print_help_chrome — Method
Kit help chrome — every overview / --help starts here:
DistSSHQueue setup
──────────────────Exported for family callers. The signature is stable. Glyphs and colors are not.
DistSSHRun.DistSSHBase.print_help_lines — Method
One or more verbatim help body lines.
DistSSHRun.DistSSHBase.print_help_section — Method
Section heading (dim) with a trailing blank line so body lines follow immediately.
Section
<blank>
body…DistSSHRun.DistSSHBase.remote_env_project_root — Method
Layout path for DISTRIBUTED_REMOTE_PROJECT_ROOT (kit parent ENV / execute!).
~… stays a remote-shell layout (do not expanduser on the kit parent). Absolute paths are canonical_local_path.
DistSSHRun.DistSSHBase.resolve_controller_julia — Function
Resolve the Julia binary on this kit parent (nothing / "auto" / empty → the running process). Explicit paths are kept as given after usability check.
Throws ArgumentError when the binary is missing or --version does not parse.
DistSSHRun.DistSSHBase.resolve_pkg_env — Method
Pkg environment for project (a directory, or a project-file path).
project_dir is the directory of the project file Base would use (--project). manifest is manifest_path, or nothing when that lookup finds no file. env_dir is the directory of manifest, or project_dir when there is no lock. That is the tree setup --rsync sends.
Queue: default_queue_env (no dedicated ~/.distsshqueue/env) should return env_dir. stage_job_tree! should rsync env_dir, and set DISTRIBUTED_PROJECT_ROOT to the staged project_dir (relative to that tree). Serve --queue-env is env_dir. A job's --project stays project_dir, because env_dir as --project misses [deps] that exist only on the member.
DistSSHRun.DistSSHBase.resolve_pkg_project_dir — Method
Walk upward from start_dir to find the directory that should be passed to Pkg.activate on workers.
If the first Project.toml found is a vendored DistSSHKit, DistSSHQueue, or DistSSHRun stub (name is one of those) and the parent directory also has a Project.toml, skip it and keep walking. Scripts next to that stub then use the application project root. The folder name does not matter.
DistSSHRun.DistSSHBase.resolve_remote_julia — Function
Resolve Julia on SSH host.
nothing / "auto" / empty → detect_julia_path. Explicit path must pass remote --version. Returns nothing when auto-detect fails (no bare "julia" fallback).
DistSSHRun.DistSSHBase.resolve_remote_project_root — Method
Worker --project path for local_project_root.
Same override rules as remote_deploy_root. When the Manifest lives in a parent of the member, this is deploy_root plus that relative path once (julia_project_rel). A single-project tree returns the deploy root unchanged. Does not abspath tilde paths.
DistSSHRun.DistSSHBase.run_on_host — Function
run_on_host(host, argv; julia=nothing, detect=true, tty=false, wait=true) -> Base.ProcessOne SSH connection: resolve remote Julia the same way as resolve_remote_julia / detect_julia_path, then exec it with argv (Julia flags / script / args). Does not replace resolve_remote_julia when the caller only needs the path.
julia=nothing / "auto" with detect=true probes candidates on the remote. detect=false requires an explicit path. tty=true adds ssh -t. Process-local detect cache is not used (a new CLI process never hits it).
SSH is ignorestatus: a non-zero remote or ssh exit returns the Process (.exitcode) instead of throwing ProcessFailedException. Missing ssh on PATH throws ArgumentError.
DistSSHRun.DistSSHBase.shield_sigint — Method
shield_sigint(f)Run f so Ctrl-C reaches the main task, not this background task. Call it inside the task. On Julia 1.14 this is without_cancel. On 1.13 it is disable_sigint.
DistSSHRun.DistSSHBase.short_path — Method
Shorten absolute paths by replacing the home directory prefix with ~.
DistSSHRun.DistSSHBase.ssh_opts — Method
ssh_opts(; request_tty=false) -> Vector{String}SSH argv flags for ssh / scp.
Reads DISTRIBUTED_SSH_OPTS live (not frozen at package precompile). Prefer this over a const so E2E / ProxyJump overrides apply in the same process.
A non-empty DISTRIBUTED_SSH_OPTS replaces the default vector (it is not merged). It is split with Base.shell_split, so a quoted value that contains spaces stays one argument. An unmatched quote throws ArgumentError. request_tty only changes the default vector: false includes -o RequestTTY=no; true omits it so a caller may put ssh -t before or after these flags. The ENV replacement is unchanged (if it contains RequestTTY=no, put -t after the vector). Use -o RequestTTY=no, not ssh -T: these flags are also passed to scp (scp -T is unrelated). Does not insert -t (that flag is ssh-only).
DistSSHRun.DistSSHBase.stored_path — Method
stored_path(rel; project=pwd(), output=nothing) -> StringWhere rel is stored. output=nothing reads DISTRIBUTED_OUTPUT_DIR. A passed string is used as given and does not read that variable. "" means no output directory.
An absolute rel, after expanding a leading ~ on this machine, is returned as a canonical local path. The output directory is not consulted.
A relative rel uses the first match:
- The output directory is set and
relalready exists there. relalready exists underproject, even when the output directory is set.- The output directory is set, including when the file does not exist yet.
project, when the output directory is empty.
DistSSHRun.DistSSHBase.wait_seconds — Method
wait_seconds(name::Symbol, default::Real) -> Float64Resolve a named wait. default is the caller's seconds. This module does not choose them.
:until_exit returns Inf and ignores default. For any other known name, DISTSSHKIT_WAIT_<NAME> wins when it is a finite number ≥ 0. An unreadable value is ignored. DISTSSHKIT_WAIT_SCALE then multiplies :child_reply, :go_job, and :drive_job only. Scale 1 is used when that variable is missing, unreadable, or 0.
DistSSHRun.DistSSHBase.with_cli_entry — Method
Set the CLI entry for f when none is set.
An inner main does not replace the outer one, and does not clear it.
DistSSHRun.DistSSHBase.with_cli_exit — Method
with_cli_exit(f; report = cli_report, interrupted = cli_interrupted) -> CintRun f()::Cint.
A CliUsageError calls report(msg) and returns 2. Ctrl-C (is_sigint) calls interrupted() and returns that Cint. An EPIPE IOError returns 141 and prints nothing. Any other exception, including a bare ArgumentError, is showerror on stderr and returns 1.
report and interrupted run inside without_cancel. On Julia 1.13 a second Ctrl-C can still stop them. On 1.14 they finish.
DistSSHRun.DistSSHBase.without_cancel — Method
without_cancel(f)Run f outside the Ctrl-C that is already being handled. On Julia 1.14 the cancelled scope makes every later wait, write, and flush throw again, so cleanup after Ctrl-C runs here. On 1.13 this is f(), and a second Ctrl-C still stops the cleanup.
DistSSHRun.DistSSHUp — Module
juliaup verbs on hosts (up add, up default, up update, up status).
Names marked public are a contract inside the DistSSH family. A 0.x patch does not change them.
DistSSHRun.DistSSHUp.juliaup_add_host! — Method
juliaup add on parent or one SSH host. Does not change the default.
DistSSHRun.DistSSHUp.juliaup_default_host! — Method
juliaup default on parent or one SSH host.
A missing channel fails. Success drops the cached Julia path for that host, so the next lookup sees the new default.
DistSSHRun.DistSSHUp.juliaup_default_patch — Method
Installed patch of the juliaup default on host, or -.
parent is this machine. Anything else is an SSH host. Missing juliaup, a failed status, or no Version column is -.
DistSSHRun.DistSSHUp.juliaup_status_lines — Method
Installed juliaup status rows on host. Optional channel keeps that row.
strict throws when juliaup is missing, status fails, or SSH fails. An empty status from a juliaup that did run is still an empty vector. The default stays quiet: those failures are String[].
DistSSHRun.DistSSHUp.juliaup_update_host! — Method
juliaup update on parent or one SSH host. Does not change the default.
channel === nothing updates every installed channel. A channel updates that one.
NO_COMMAND_HINT_LINES and RUN_SUBCOMMAND_EXPECTATION are public and are not exported. print_rejected_command prints them.
DistSSHRun.NO_COMMAND_HINT_LINES — Constant
Three hint lines print_rejected_command prints under no_command_message.
DistSSHRun.RUN_SUBCOMMAND_EXPECTATION — Constant
Expected-command sentence print_rejected_command prints under unknown_subcommand_message.
shell_status is public on DistSSHBase and is not exported.
DistSSHRun.DistSSHBase.shell_status — Function
shell_status(proc::Base.Process)::IntStatus of a child that has exited, using the shell's 128 + signal rule.
A signaled process (termsignal > 0) returns 128 + termsignal. Unix records that child as exitcode == 0 with success false. SIGINT is 130, SIGPIPE is 141, SIGKILL is 137, and SIGTERM is 143. Any other exit returns exitcode unchanged, including 0, 3, 127, and 255.
Throws ArgumentError when proc has not exited. Does not print, and does not fold a signal into 1 or 255.
Identity
run_identity, identity_mismatches, and parse_allow_mismatch are public and are not exported. go!, ride!, and drive! keep --allow-mismatch and these lines. Add DistSSHKit. These names are not a command.
DistSSHRun.ALLOW_MISMATCH_FIELDS — Constant
ALLOW_MISMATCH_FIELDS--allow-mismatch tokens: :julia, :distssh, and :manifest.
DistSSHRun.run_identity — Function
run_identity(project::AbstractString) -> Dict{String,String}This process, plus the Manifest of project.
"version"isstring(VERSION)."commit"is this Julia's git commit."julia"isjoinpath(Sys.BINDIR, "julia").identity_mismatchesdoes not compare it."manifest"is the Manifest path Julia selects forproject, or""."pkg.DistSSHRun","pkg.DistSSHKit","pkg.DistSSHQueue", and"pkg.DistSSHBase"are version strings from that Manifest. Loadedpkgversionis not read.
Reads the project tree. Does not activate it, write the depot, set environment variables, or SSH.
DistSSHRun.identity_mismatches — Function
identity_mismatches(parent, other; allow=Symbol[], shipped_manifest="") -> Vector{String}Same lines as go!, ride!, and drive!. An empty vector matches. This does not throw, print, or read DISTSSHKIT_QUIET.
:julia in allow skips both "version" and "commit". :distssh skips pkg.*. :manifest skips the Manifest path. Any other symbol does not throw and waives nothing. Parse a CLI list with parse_allow_mismatch.
A pkg.* key is compared only when parent has it and other has a non-empty value. Keys that exist only on other are ignored. The expected Manifest path is shipped_manifest when that is non-empty, otherwise parent["manifest"]. An empty expected path is not a mismatch. "julia" is not compared.
Line text uses parent= and worker=.
DistSSHRun.parse_allow_mismatch — Function
parse_allow_mismatch(raw::AbstractString) -> Vector{Symbol}Comma-separated --allow-mismatch list. Spaces are ignored and duplicates are dropped. An unknown token throws ArgumentError.