devmachine

CLI Reference

The network package contract

A network package makes a private network reachable through devmachine without the CLI knowing the product. It declares a network: block and ships up to three scripts. This page says what each one gets and what it must give back.

Every script is Python 3 with no dependencies beyond the standard library, and must run on Python 3.9: that is what macOS ships, and resolve runs on your computer. Every script gets the machine’s settings for its package as one JSON object in the DEVMACHINE_SETTINGS variable: each variable the package declares, with its default, and any <package>.<name> setting of the machine on top.

{"exit_node": false, "login_server": "https://net.example.com"}

resolve

Runs on your computer, every time something needs the machine’s addresses: a connection, devmachine resolve, an SSH alias.

  • Argument: the name, as written after the prefix. tailscale:main gives main. It is an argument, never part of a shell line.
  • Output: the machine’s IP addresses on standard output, one per line, in the order to try them. Anything that is not an IP address is refused.
  • Exit 0: the addresses are good.
  • Exit 3: the network is not reachable from here — the app is not installed, not running, or not signed in. Print why on standard error in a few words (tailscale is not running). The entry is skipped, not reported as a failure.
  • Any other exit: something is wrong with the script or the network. The entry is skipped too, and standard error is shown as the reason.
  • Time: 5 seconds, then it is stopped and skipped.

It runs from the package’s own folder on your computer: the pinned release a sync downloaded, or <config>/packages/<name>/.

join

Runs on the machine, as its admin account, for devmachine login <package>, in a real terminal (ssh -t). It does whatever signing in to the network takes: printing a URL to open, reading an auth key, calling the network’s own command. Exit 0 when the machine joined.

It runs from where sync put the package: /opt/devmachine/roles/<package>/ for a published package, or /opt/devmachine/roles.local/<package>/ for one from your own packages/. So the package has to be synced before login.

self_name

Runs on the machine, as its admin, right after join succeeds. It prints the name the machine answers to on the network, on one line: letters, digits, dots, dashes and underscores. devmachine adds <prefix>:<name> as the first entry of the machine’s hosts in config.yml, unless it is already there. The public address stays as a fallback.

If it fails, or prints something that cannot be a host entry, the login still counts, and devmachine prints the hosts: block to paste by hand.

An example

The tailscale package in the packages repository is the reference: resolve reads tailscale status --json on your computer, join runs tailscale up with --login-server when tailscale.login_server is set, and self_name reads the machine’s own tailscale status --json.