devmachine

CLI Reference

Settings

Every variable the published packages accept, and what each one defaults to.

A setting is written <package>.<name> under a machine’s or a workspace’s settings:, and it reaches the recipe as the variable it already reads. A setting is a default somebody overrode, not a new mechanism — the recipe cannot tell the difference and does not have to.

machines:
  - name: main
    packages: [base, caddy]
    settings:
      base.timezone: Europe/Lisbon
      caddy.email: [email protected]

Or without opening the file:

devmachine workspaces edit alice --set zsh.tmux_config=false

A setting for a package the target does not install is refused. A typo in a package name would otherwise be silent: the value would reach nothing, the recipe would keep its default, and the machine would not be what the configuration says it is.

This page is generated by make settings. Do not edit it by hand.

SettingWhat it doesDefault
base.hostnameThe machine’s hostname. Empty leaves the one it already has.(empty)
base.swapSize of a swapfile at /swapfile, such as 8G. Empty leaves the machine alone.(empty)
base.timezoneThe machine’s timezone, as tzdata spells it. Empty leaves whatever the machine came with.(empty)
base.upgradeUpgrade every package already installed. Off, because that is the owner’s decision and not a side effect of installing base tools.false
caddy.emailThe address the certificate authority writes to about an expiring certificate. Empty means an anonymous account.(empty)
caddy.local_certsSign certificates locally instead of asking Let’s Encrypt. For a machine no name resolves to — a test VM, a private network — where the ACME challenge can never succeed. Off, because a certificate nobody else trusts is not what a public site wants.false
caddy.siteServe a one-page site straight from Caddy, no container behind it. It answers 200, which proves the name, the certificate and the proxy in one request. Off leaves the machine serving only what other packages add.true
caddy.site_domainThe name the one-page site answers to, with its own certificate. Empty serves it on port 80 at the machine’s address, over plain HTTP, because no public authority signs a certificate for a bare address. It creates no DNS record: pointing the name is devmachine dns add.(empty)
claude-code.diff_sidebarOpen the /diff panel. Unset leaves whatever Claude Code has. It is a preference Claude Code keeps in its own state file, so it is amended only where that file, and that preference, already exist.(none)
claude-code.envEnvironment variables every Claude Code session runs with, as a map. It is how a model-specific or terminal-specific workaround is turned on without this package having an opinion about it.map[]
claude-code.expanded_todosShow the task list under the footer. Unset leaves whatever Claude Code has, and the same condition applies.(none)
claude-code.homeWhere the account’s home is./home/<the account>
claude-code.remote_control_at_startupConnect every session to Remote Control as it opens, instead of waiting for somebody to type /rc.false
claude-code.session_name_prefixWhat each Remote Control session is called in the phone app. Empty means the workspace’s name, which is what tells two workspaces’ sessions apart.(empty)
claude-code.status_lineThe command Claude Code runs to draw its status line. Empty leaves the status line alone. It runs outside a login shell, so give it an absolute path.(empty)
claude-plugins.claudeWhere the Claude Code CLI is. It is installed into the account’s own ~/.local/bin, so only a workspace that put it somewhere else says so.<the home>/.local/bin/claude
claude-plugins.homeWhere the account’s home is./home/<the account>
claude-plugins.marketplaceWhere the plugins come from: a GitHub repository written owner/name, a git URL, or a path on the machine. Empty installs nothing.(empty)
claude-plugins.pluginsWhich plugins to install, each written @. The marketplace half is the name the marketplace gives itself, which is what Claude Code installs and reports against.[]
claude-plugins.updateRe-fetch the marketplace and update every plugin on each run. It is off by default because it cannot tell whether anything moved, so a run with it on always reports a change.false
claude-remote-control.homeWhere the account’s home is./home/<the account>
claude-remote-control.restart_secondsHow long to wait before reconnecting. The server gives up on its own after about ten minutes with no network, so the unit restarts for good.30
claude-remote-control.session_nameWhat this session is called in the phone app. Empty means the workspace’s name, which is what tells two workspaces’ sessions apart.(empty)
claude-remote-control.working_directoryThe directory a remote session starts in.<the home>/dev
dev.gh_versionWhich GitHub CLI release to install. It is a release asset rather than a distribution package because most distributions do not carry gh at all.2.63.2
dev.homeWhere the account’s home is./home/<the account>
dev.node_versionWhich Node mise installs globally.lts
fail2ban.bantimeHow long a ban lasts, in seconds.3600
fail2ban.ignoreipThe addresses that are never banned, space separated. Loopback only by default: a wider range exempts everyone who shares it.127.0.0.1/8 ::1
fail2ban.maxretryHow many failures from one address before it is banned.5
firewall.httpOpen 80 and 443. A machine that hosts nothing can turn this off.true
firewall.mosh_interfaceThe one interface mosh’s UDP range is opened on. Empty means it is not opened at all, which keeps the range off a public edge.(empty)
firewall.mosh_portsThe UDP range mosh is given on that interface.60000:61000
git-key.homeWhere the account’s home is./home/<the account>
glab.homeWhere the account’s home is./home/<the account>
glab.versionWhich GitLab CLI release to install. It is a release asset rather than a distribution package because no distribution carries glab.1.111.0
hostinger.zonesDNS zones this provider may manage. Set this when the token has DNS permission without Domains portfolio permission; an empty list asks the account portfolio instead.[]
mise.homeWhere the account’s home is./home/<the account>
sentry.homeWhere the account’s home is./home/<the account>
ssh_hardening.serviceWhat systemd calls sshd. Empty means the name this distribution family uses, which is ssh on Debian and Ubuntu and sshd elsewhere.(empty)
tailscale.exit_nodeAdvertise this machine as an exit node. Off unless asked for.false
workspace.admin_homeThe home of the account the CLI provisions with. Whatever reaches that account over SSH is what reaches this workspace./root
workspace.git_emailThe address on this workspace’s commits.(empty)
workspace.git_nameThe name on this workspace’s commits.(empty)
workspace.groupsExtra Linux groups the account joins. The docker group is one of them and it is effectively root, so nobody joins it by accident.[]
workspace.homeWhere the account’s home is. Debian and Ubuntu put it under /home; a machine whose useradd is configured otherwise says so here./home/<the account>
workspace.known_hostsThe hosts whose SSH host key is trusted in advance, so the first clone does not stop to ask a question nobody is there to answer.[github.com]
workspace.shellThe login shell. Empty means whatever useradd would pick, and the package that installs a shell is the one that sets it.(empty)
workspace.sign_commitsSign every commit and rebase, once a package such as git-key sets up a key.true
zsh.homeWhere the account’s home is./home/<the account>
zsh.tmux_auto_attachOpen a tmux session on every SSH login, so a dropped connection loses nothing. A second connection while the first is live gets a session of its own instead of a second view of the same one.true
zsh.tmux_configWrite the account’s ~/.tmux.conf. Turn it off to keep a config of your own.true