cold is a tiny C CLI for running build commands on one remote machine and pulling build output back.
It is intentionally boring: no daemon, no hosted service, no agent install. If you can SSH to the machine, cold can use it. Tailscale works by using the machine's Tailscale name or IP as the host.
The point is not to be another SSH wrapper or a tiny GitHub Actions clone. cold is meant to make the good path obvious: pick a machine once, run the same local command remotely, and get the files you care about back without thinking about CI YAML, runners, daemons, or deploy infrastructure.
make
make installcold initThis opens an interactive CLI setup flow with arrow-key choices and line prompts. By default it creates .cold for the current project. Use cold init --global for ~/.config/cold/config. It asks for:
- server name
- connection style: plain SSH, Tailscale over SSH, or custom SSH host
- host or Tailscale name/IP
- ssh user
- ssh port
- remote directory
- mode
- artifact paths
Modes:
remote: run the command in an existing remote directoryupload: rsync the current project to the remote directory first
cold run <server> <command>Example:
cold run mini "bun run build"Set a default server and command in .cold when you run the same build every time:
default_server = "mini"
run = "bun run build"Then run it with either spelling:
cold run
cold buildYou can still override the machine or command for one run:
cold run mini "bun run test"
cold build mini --uploadShorthand:
cold mini "bun run build"You can also pass command words directly:
cold mini bun run buildUpload before building:
cold mini --upload bun run buildPull extra files for one run:
cold mini --get dist --get build bun run buildRemote commands receive the local machine target as environment variables:
COLD_LOCAL_OS=macos
COLD_LOCAL_ARCH=arm64
COLD_LOCAL_TARGET=macos-arm64Use those in your build command when the remote can cross-compile for the local machine.
If a server has a Docker builder image configured, pass a target before the command to run the command inside that image on the remote machine:
cold mini sys bun run build
cold mini macos-arm64 bun run buildsys means the current local system target. For targeted builds, cold resolves a Docker image by checking exact config, then builder_image, then built-in safe defaults for Linux targets. It runs Docker on the remote machine with --pull missing, so the image is pulled automatically when needed. macOS builder images must be provided by the user because macOS SDK redistribution has licensing constraints.
List servers:
cold listAdd or replace a server:
cold server add
cold server add --global
cold server add --projectProject config lives at .cold. Global config lives at ~/.config/cold/config. cold loads global first, then project config, so a project server overrides a global server with the same name.
Either file uses the same format:
default_server = "mini"
run = "bun run build"
[server "mini"]
transport = "ssh"
host = "mini.tailnet-name.ts.net"
user = "nico"
port = "22"
remote_dir = "~/cold/my-app"
mode = "upload"
run = "bun run build"
builder = "docker"
builder_image = "ghcr.io/you/builders/{target}:latest"
builder_image_macos_arm64 = "your-osxcross-image:latest"
artifacts = "dist", "build"cold stays dependency-light while keeping the Bubble Tea-style feel where it matters:
- Flags, options, subcommands: small built-in parser for now
- Colors/styles: small ANSI UI layer with
NO_COLORsupport - Interactive prompts: raw terminal arrow-key selector plus line prompts
- Progress: small custom step reporter
- Tables: fixed-width custom formatting
- Config files: tiny INI-like parser/writer
- JSON output: not added yet because v1 has no machine-output command
- C compiler
makesshrsync
make format
make lint
make test