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.

source
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.

source
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.

source
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).

source
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.

source
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.

source
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.

source
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.

source
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.

source
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).

source
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).

source
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.

source
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.

source
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.

source
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!).

source
DistSSHRun.terminate! — Method
terminate!(kp::KitProcess; grace=10, interrupt_grace=nothing) -> KitRunResult

Stop 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.

source
DistSSHRun.terminate_run! — Method
terminate_run!(output_dir; grace=10, interrupt_grace=nothing, log_dir=nothing, kind=:go) -> KitRunResult

Like 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.

source
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).

source
Base.wait — Method
wait(kp::KitProcess; timeout=nothing) -> KitRunResult

Block 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.

source
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.

source
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.

source

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

source
DistSSHRun.pool! — Method
pool!(session) -> ResourcePool

Probe 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.

source

Pipeline

pipeline! chains runs. collect! brings the outputs back.

DistSSHRun.PipelineConfig — Type
PipelineConfig

Settings 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.

source
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 (CLI drive --collect-missing)
  • merge=true → collect-overwrite (CLI drive --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.

source
DistSSHRun.pipeline! — Method
pipeline!(driver, workers...; kwargs...) -> PipelineResult
pipeline!(driver, workers::AbstractVector; kwargs...) -> PipelineResult
pipeline!(config::PipelineConfig) -> PipelineResult

Run 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.

source
DistSSHRun.pipeline_config_from_env — Method
pipeline_config_from_env(; driver=...)

Build PipelineConfig from environment variables.

VariableRole
DISTSSHKIT_HOSTSComma-separated placement tokens (parent:N / child:NAME:N)
DISTSSHKIT_HOSTS_FILEHosts file (appended after DISTSSHKIT_HOSTS, same order as CLI)
DISTRIBUTED_REMOTE_PROJECT_ROOTRemote repo root
DISTRIBUTED_PROJECT_ROOTLocal project root
DRIVERDriver script path
SYNC_MODErsync, sync, or off
JULIA_DISTRIBUTED_EXERemote Julia path (same as CLI --julia; auto / unset → detect)
DISTSSHKIT_YES / DISTSSHKIT_QUIET / DISTSSHKIT_PROGRESS / DISTSSHKIT_VERBOSESame as CLI -y / -q / --progress / --verbose
source

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.

source
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.

source
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.

source
DistSSHRun.instantiate! — Method
instantiate!(session::KitSession; julia="auto") -> SyncResult

Run 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=…).

source
DistSSHRun.normalize_remote_confirm_path — Method
normalize_remote_confirm_path(path) -> String

Syntactic 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"
source
DistSSHRun.setup! — Method
setup!(session::KitSession, mode::Symbol; kwargs...) -> SyncResult
setup!(session::KitSession, modes::Symbol...) -> SyncResult

Prepare SSH hosts — same jobs as julia -m DistSSHKit setup --….

modeCLINotes
:delete--deleteDestructive. Requires confirm_path. session.yes does not delete. Refuses a present unowned Ship run.toml
:ship_tree--ship-treeWalk 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--cloneRequires repo=; clone runs on the remote
:sync--syncPush the local branch to origin, then detach each remote at that commit; confirm unless session.yes. A dirty tree is refused
:pull--pullDetach 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--instantiatejulia= (default "auto")
:juliaupupAlign 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_updateup updatejuliaup update on those hosts (no default); confirm unless session.yes
:check--checkignore_julia_version=, check_code_sync=
:runtest--runtestjob Pkg.test() on remotes; julia=
:cleanup--cleanupKill 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-rootremote= 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.

source
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 unless session.yes). Does not run git pull. A dirty tree is refused.
  • mode=:ship_tree — pack the project (each directory's .gitignore) into a tar and extract under runs/<run_id>/src/ (confirm unless session.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.

source

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.

source
DistSSHRun.snapshot — Function
snapshot(local_root; allow_external_symlinks=false, ship_max_bytes=SHIP_MAX_BYTES_DEFAULT) -> ShipSnapshot

Build 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.

source
DistSSHRun.ship — Function
ship(snapshot, hosts, remote_root; confirm=false, record=true) -> ShipTreeResult

Send 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.

source

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/.

source
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.

source
DistSSHRun.allocate_output_dir — Method
allocate_output_dir(kind, script; project=pwd(), job_id=nothing) -> String

Create 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.

source
DistSSHRun.allocate_run_dir — Method
allocate_run_dir(kind, script; project=pwd(), job_id=nothing) -> String

Create 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/….

source
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.

source
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 KitProcess

One 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.

source
DistSSHRun.execute_detached_accepts — Method
execute_detached_accepts(kw; kind) -> Bool

Whether 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.

source
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.

source
DistSSHRun.kit_pid_file_running — Method
kit_pid_file_running(output_dir) -> Bool

Whether 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.

source
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 DIR

main remains for wrappers and tests; prefer -m day-to-day. A .jl path with no command is not implicit go.

source
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.

source
DistSSHRun.push_cache! — Method
push_cache!(session; hashes=nothing) -> SyncResult

Stream 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.

source
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.

source
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.

source
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.

source
DistSSHRun.DistSSHBase.cache_file — Method
cache_file(src; project=pwd()) -> String

Copy 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.

source
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.

source
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")
false
source
DistSSHRun.DistSSHBase.is_sigint — Method
is_sigint(e) -> Bool

True 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.

source
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.

source
DistSSHRun.DistSSHBase.posix_quote — Method
posix_quote(word::AbstractString) -> String

One 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.

source
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.

source
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.

source
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.

source
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.

source
DistSSHRun.DistSSHBase.run_on_host — Function
run_on_host(host, argv; julia=nothing, detect=true, tty=false, wait=true) -> Base.Process

One 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.

source
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.

source
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).

source
DistSSHRun.DistSSHBase.stored_path — Method
stored_path(rel; project=pwd(), output=nothing) -> String

Where 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:

  1. The output directory is set and rel already exists there.
  2. rel already exists under project, even when the output directory is set.
  3. The output directory is set, including when the file does not exist yet.
  4. project, when the output directory is empty.
source
DistSSHRun.DistSSHBase.wait_seconds — Method
wait_seconds(name::Symbol, default::Real) -> Float64

Resolve 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.

source
DistSSHRun.DistSSHBase.with_cli_exit — Method
with_cli_exit(f; report = cli_report, interrupted = cli_interrupted) -> Cint

Run 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.

source
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.

source
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.

source
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[].

source

NO_COMMAND_HINT_LINES and RUN_SUBCOMMAND_EXPECTATION are public and are not exported. print_rejected_command prints them.

shell_status is public on DistSSHBase and is not exported.

DistSSHRun.DistSSHBase.shell_status — Function
shell_status(proc::Base.Process)::Int

Status 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.

source

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.run_identity — Function
run_identity(project::AbstractString) -> Dict{String,String}

This process, plus the Manifest of project.

  • "version" is string(VERSION).
  • "commit" is this Julia's git commit.
  • "julia" is joinpath(Sys.BINDIR, "julia"). identity_mismatches does not compare it.
  • "manifest" is the Manifest path Julia selects for project, or "".
  • "pkg.DistSSHRun", "pkg.DistSSHKit", "pkg.DistSSHQueue", and "pkg.DistSSHBase" are version strings from that Manifest. Loaded pkgversion is not read.

Reads the project tree. Does not activate it, write the depot, set environment variables, or SSH.

source
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=.

source
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.

source