Harbor is the next-generation agent tunnel service that grows out of LongArm. It is designed around one host-side daemon and one lightweight remote-side agent, so many local agents can share a small number of durable tunnels instead of each opening their own SSH PTY.
The current repository is an early prototype. The first milestone provides:
- a host daemon with a Unix socket JSON-line API;
- local PTY sessions with cursor-based reads;
- owner/lease metadata plus explicit and automatic dead-session cleanup;
- a CLI shaped like LongArm's core commands;
- stdio remote-agent tunnels with remote PTY session routing;
- small-file transfer over the persistent remote-agent tunnel;
- an early SCNet plugin TOML path for user-owned discovery and setup files;
- setup-file manifest checks for user-provided remote environment files;
- optional plugin-owned discovery caching for last-known remote targets.
- an inline remote-agent launch path for targets that do not have Harbor installed yet.
python3 -m harbor start
python3 -m harbor ping
python3 -m harbor remote-ping
python3 -m harbor remote-ping --ssh-target worker --inline-agent
python3 -m harbor tunnel-open worker-agent
python3 -m harbor tunnel-ping worker-agent
python3 -m harbor spawn remote-demo --backend remote --tunnel worker-agent --cmd /bin/sh
python3 -m harbor spawn clean-demo --backend remote --tunnel worker-agent --shell-policy fresh
python3 -m harbor xfer-stage worker-agent ./check.sh /tmp/check.sh
python3 -m harbor xfer-get worker-agent /tmp/check.sh ./check.roundtrip.sh
python3 -m harbor file-op worker-agent ls /tmp
python3 -m harbor git-probe worker-agent github=https://github.com/owner/repo.git
python3 -m harbor git-open worker-agent --session repo-git --cwd /tmp/repo --replace
python3 -m harbor scnet-plugin discover ./scnet.toml --prefer-cache
python3 -m harbor scnet-plugin setup-check ./scnet.toml --tunnel worker-agent
python3 -m harbor scnet-plugin git-open ./scnet.toml --tunnel worker-agent --replace
python3 -m harbor tunnel-close worker-agent
python3 -m harbor spawn demo --cmd /bin/sh
python3 -m harbor send-line demo 'echo hello from harbor'
python3 -m harbor read demo --since 0
python3 -m harbor resize demo --rows 40 --cols 140
python3 -m harbor renew demo --ttl-seconds 300
python3 -m harbor close demo
python3 -m harbor stopThe default state root is ~/.harbor. Override it with HARBOR_HOME.
harbor start runs one host daemon per state root. Hostd writes
hostd.pid, holds hostd.lock, and reports its version, argv, pid,
socket, log, and pidfile in ping/start output.
remote-ping probes a harbor-remote-agent --stdio process. With no options it
starts a local module agent; with --ssh-target HOST it uses SSH stdio without
allocating a TTY. Add --inline-agent when the target has Python but does not
yet have Harbor installed; Harbor embeds its stdlib-only remote agent into the
SSH command and extracts it under /tmp/harbor-agent-<hash> on the target.
Entry probes and tunnel-open retry three times by default; use --retries N
to tune flaky targets. JSON output includes per-attempt status.
After tunnel-open, manage the local persistent tunnel with tunnel-status,
tunnel-ping, and tunnel-close; those commands address hostd state and do not
reconnect to the SSH target.
tunnel-status --check performs an explicit live probe and records the latest
probe result in hostd.
xfer-put, xfer-get, xfer-stage, and xfer-stat move small files through
an existing tunnel. They do not open a separate host-side SFTP PTY.
file-op provides safe remote file operations: ls, mkdir, rm, and
rmdir; use file-op TUNNEL rm PATH --recursive --missing-ok for task-scoped
temporary directories. xfer-cmd and sftp-cmd are aliases for migration, but
the command set is explicit rather than an arbitrary remote shell.
Tunnels can carry metadata. scnet-plugin tunnel-open stores a redacted plugin
and discovery summary in hostd, so tunnel-status can show what an active
tunnel points at.
Remote spawns support explicit shell policies. --shell-policy fresh starts a
clean non-tmux bash; --shell-policy tmux attaches harbor-<name> when tmux is
available; --shell-policy reset-tmux first kills and recreates that named tmux
session, so use it only for sessions you own.
git-probe runs bounded git ls-remote checks on the remote side through the
existing tunnel. Harbor sets GIT_TERMINAL_PROMPT=0; proxy and credentials come
from user-provided plugin setup files or the remote environment.
git-open creates a reusable remote git shell session. It exports
GIT_TERMINAL_PROMPT=0, can source user-provided env files, can cd to a
working directory, and is then driven with normal send-line and read.
Remote sessions are owned by the selected persistent tunnel. Closing a tunnel
also closes and drops its remote session references from hostd. If a tunnel dies
unexpectedly, Harbor reports the affected remote sessions as unavailable and
cleanup-dead can drop the stale host-side references.
SCNet discovery/setup is plugin-owned rather than hardcoded in Harbor core. See
docs/scnet_plugins.md for the TOML shape and commands.
Use scripts/smoke_scnet_plugin.sh scnet-worker for a disposable plugin setup
smoke with fake credentials and a task-scoped remote /tmp directory.
Plugins may opt into last-known discovery caching; Harbor validates the plugin
config hash before using the cache and supports --no-cache for a forced live
discovery.
Setup uploads and checks return per-file expected/actual manifests with content
redacted, so workers can see exactly which file, mode, byte count, or hash
differs without Harbor guessing site policy.
Setup files marked role = "env" are sourced by scnet-plugin git-open.
One setup file marked role = "gitconfig" is exported as GIT_CONFIG_GLOBAL;
credential files are still user-provided setup files, not generated by Harbor.
Idle/LRU cleanup is conservative by default. cleanup-sessions always reaps
dead sessions first, but it does not close running sessions unless
--include-running is passed explicitly.
Harbor will keep the mature LongArm behaviors that proved useful:
- task-scoped named sessions;
- cursor reads and transcripts;
- SCNet worker discovery and runtime environment setup;
- user-provided SCNet discovery/setup plugins;
- staged file transfer;
- git/proxy setup helpers;
- careful side-probe workflows for long-running jobs.
The key architectural change is where PTYs live. LongArm opens host PTYs for
each SSH connection. Harbor will place remote shell PTYs behind
harbor-remote-agent, while harbor-hostd holds a small number of tunnel
connections and multiplexes session traffic.