Deploy Center Docs Guides GitHub Download

Command line: deploys

Last updated · Edit on GitHub

On this page

The app is a window over one bash script, deploys. You can use it on its own. It is inside the app at Deploy Center.app/Contents/Resources/deploys, and ./deploys in this repo. deploys without arguments prints the full help.

Everyday commands#

deploys doctor                          # what is connected
deploys changed                         # what is merged on GitHub and not live: commits and PRs per project
deploys deploy-changed                  # the daily deploy: shows the list; add --yes to start it
deploys plan [--when-green]             # the same list with an estimate per build and the sum (starts nothing)
deploys status                          # what is building now, and what failed last
deploys watch my-project                # follow the newest deploy until live or failed
deploys logs my-project                 # the end of the newest build log
deploys open my-project [--dashboard]   # the site, or its page at Vercel/Render
deploys ignore my-project               # leave it out of changed / deploy-changed

Vercel#

deploys vercel list                     # which projects still deploy on push
deploys vercel autodeploy-off --all     # or one project by name
deploys vercel autodeploy-on my-project # connect Git again (or --all)
deploys vercel deploy my-project        # newest commit to production
deploys vercel deploy my-project --preview
deploys vercel rollback my-project
deploys vercel map my-project me/my-repo main   # where a project deploys from, set by hand
deploys vercel team [<id>]              # show or set the Vercel team

Render#

deploys render list
deploys render autodeploy-off --all     # or one service by name
deploys render autodeploy-on my-service # auto-deploy "On Commit" again (or --all)
deploys render deploy my-service
deploys render rollback my-service
deploys render set-key                  # store the API key in the keychain (reads stdin)
deploys render forget-key

More#

deploys explain my-project              # why a project is (not) counted as changed
deploys diff my-project                 # commits and files between what is live and the branch
deploys notes my-project                # the same as release notes (Markdown)
deploys history my-project [n]          # the last n deploys
deploys costs [days]                    # Vercel charges per day
deploys simulate [--days 30]            # estimate: auto-deploy a month vs. once a day, see SAVINGS.md
deploys ledger                          # estimate: builds and money saved since auto-deploy was off
deploys price set vercel 0.008          # your price of one build minute, where no billing says it (prices.json)
deploys budget set 50 [--strict]        # deploy-changed --yes stops before going over $50 a month
deploys triggers                        # builds nobody started from here, deploying workflows, Blueprints
deploys where                           # config folder, version, key source, logins
deploys autofix [--dry-run]             # see AUTOFIX.md
deploys autofix --only vercel my-project  # this one failure now
deploys autodeploy allow vercel my-project 4   # auto-deploy on for 4 hours (see GUARD.md)
deploys autodeploy allowed | revoke vercel my-project
deploys guard [--dry-run] | status | schedule on|off   # auto-deploy off where it came back on
deploys ai explain|notes|ship my-project   # ask Claude with your own key, see CLAUDE.md
deploys ai ask my-project --question "will this run a migration?"   # your own question; its commits and log go along
deploys ai slow my-project              # why its builds take long (ai risk = ai ship)
deploys autofix --preview --only vercel my-project --json   # what a hand-over would send; sends nothing
deploys team init me/my-repo > deploy-center.json   # a shared config from this Mac's settings (writes nothing itself)
deploys schedule daily 09:00 [--when-green] [--by-rules]   # deploy-changed --yes once a day (launchd, or the cron line)
deploys schedule off | status [--json]
deploys hooks install [<repo>]          # before each push: which builds it would start (integrations/hooks)
deploys hooks uninstall | status [<repo>]
eval "$(deploys completion zsh)"        # tab completion (also: bash; fish: deploys completion fish | source)
deploys deploy --help                   # the help lines of one command

Add --json to any command for the machine answer. A name may be written <provider>:<name> (vercel:web) wherever a project is asked for.

Exit codes#

0 done (also "nothing to deploy"). 1 an error, something failed to start, or the state of some project could not be read (it is named and left out, never counted as current). Per command:

CommandCodes
watch0 live, 1 failed or canceled, 3 the platform could not be asked (or its answer read) five times in a row, 4 still running after --timeout
verify0 healthy, 1 failed and rolled back, 2 failed and not rolled back
ci0 green or no checks, 1 red, 2 still pending or GitHub not reachable (--json: always 0)
window0 open, 1 closed (--json: always 0)
deploy-changed --strictalso 2 when a project was skipped (red or pending CI)
autofix --only2 not failed, 3 handed over already or busy, 4 a cap, 5 no routine, 6 locked
deploy-changed --yes with a budget1 over budget (or, with --strict, spending unknown) without --force "why"
deploy --wait, groups3 the platform accepted the start but named no deploy id, so it was not followed (a group stops there)

Environment variables#

VariableWhat
DEPLOYS_CONFIGthe config folder (default ~/.config/deploys)
DEPLOYS_DIRwhere providers/ (and, without one next to the script, lib/) are
DEPLOYS_READONLYobserver mode: any value but 0, false, no, off turns it on
DEPLOYS_NO_GITHUBask no git host (as status --no-github)
DEPLOYS_JOURNALthe deploy journal file (default: the app's, on Linux in the config folder)
DEPLOYS_NOTIFY0: no macOS notifications from autofix and guard
DEPLOYS_TEAM_TTLseconds a shared deploy-center.json is cached (default 600)
DEPLOYS_AUTOFIX_PER_DAY, DEPLOYS_AUTOFIX_PER_PROJECTautofix caps per 24 h (default 6 and 2)
DEPLOYS_GITLAB_HOSTSself-managed GitLab hosts (docs/GITLAB.md)
DEPLOYS_ANTHROPIC_API_KEYthe key for deploys ai, before ANTHROPIC_API_KEY and the keychain
DEPLOYS_VERCEL_USD_PER_MIN, DEPLOYS_RENDER_USD_PER_MINbuild-minute prices for simulate and ledger
DEPLOYS_TIMEOUTseconds one gh or glab call may take (default 120, 0 = no limit; needs perl)
DEPLOYS_LOG_MAX_BYTESsize past which a launchd job log is renamed to .1 (default 1 MB)
NO_COLORno colour

Budget brake. budget.json (deploys budget set 50) holds dollars a month of Vercel build charges. Before deploy-changed --yes starts anything it adds this month's charges up to yesterday (deploys costs) and the plan's estimate for the run; over the budget it stops unless --force "why", and the reason goes to the journal. When the charges cannot be read (no Vercel, billing down) it warns and goes ahead; with --strict it stops instead. Render has no billing API and is not in the sum. deploys costs --json names days it could not read (missingDays) and sums per month (months).

DEPLOYS_NOW (the time the window rules read) counts only with DEPLOYS_TESTING=1: it is for tests.

deploys hooks install puts a small pre-push into the repo's hooks folder (git's own, or core.hooksPath). A pre-push that was there is kept as pre-push.local and runs first; its "no" still stops the push. deploys hooks uninstall puts it back. With Husky it prints the line to add to .husky/pre-push instead. The check itself reads GitHub remotes only.

window.json may name a time zone: {"tz":"Europe/Berlin","deny":[…]}. deploys window warns about keys and times it does not understand. A rule over midnight ("from":"22:00","to":"06:00") belongs to the day it starts.

Rules#

rules.json in the config folder (the app's rule editor writes it) says "when … then …" for the daily deploy:

{"rules":[{"name":"docs ship by themselves","enabled":true,
           "when":{"projects":["vercel/*"],"paths":["docs/**","*.md"],"onlyPaths":true,"ciGreen":true},
           "then":"deploy"},
          {"name":"api waits a day","when":{"projects":["render/api"],"minAgeHours":24},"then":"hold"}]}

Every condition given must hold. projects are <platform>/<name> (* matches any part). paths are globs (** any folders, * within one; without / the file name anywhere); onlyPaths: true means every changed file matches, otherwise one is enough (GitHub only, up to 300 files). labels: a pull request of the head commit has one. minAgeHours: the oldest waiting commit is that old. ciGreen: CI of the head is green or has no checks.

The first enabled rule that matches a project decides: hold leaves it out of deploy-changed and plan (named, counted as skipped); deploy is what deploy-changed --by-rules starts (the deploy window and the budget still count); notify only shows in rules check. A deploy rule without a condition is ignored. deploys rules check [--json] shows each rule against each waiting project: [{rule, index, project, matched, action, unmet}].

New JSON fields#

Checks, groups and observers in deploy-center.json#

On a server or in CI#

See Deploy from CI for a daily deploy from GitHub Actions.

Settings#

Settings live in ~/.config/deploys/ (or $DEPLOYS_CONFIG):

All commands#

Generated from deploys --help, so it always matches the script.

General commands#

CommandWhat it does
deploys doctorcheck tools and access (JSON)
deploys changed [--json]what has commits on GitHub that are not live
deploys deploy-changed [--yes]deploy all of those (shows the list without --yes) [--by-rules] only what a "deploy" rule matches; "hold" rules always count [--when-green [--wait 30m] [--strict]] only commits whose CI passed; waits for running checks
deploys schedule daily [HH:MM] [--when-green] [--by-rules] [--strict] | off | status [--json]deploy-changed --yes once a day (launchd; else the cron line)
deploys rules check [--json]which rule of rules.json matches which waiting project, and why not
deploys plan [--when-green] [--json]what deploy-changed --yes would start, and an estimate of its cost
deploys deploy <project> [--sha <c>]deploy one project to production (Vercel or Render)
deploys verify <p> [--path /health]after a deploy: ask the site 3 times; on 5xx or no answer [--rollback-after 10] [--no-rollback] count down, then roll back (Ctrl-C stops it) [--expect 200|2xx] [--follow] only that status is healthy; follow up to 3 redirects
deploys risk <project> [--json]green/yellow/red for what waits: migrations, lockfiles, config, size
deploys ci <owner/repo> [<ref>] [--wait 30m]the CI verdict of a commit: green, pending, red, none
deploys window [--json]is the deploy window (window.json) open now? --force "why" deploy inside a closed window; the reason goes to the journal
deploys status [--watch] [--no-github]what is building or failed (--no-github: no GitHub calls)
deploys watch <p> [<id>] [--preview]follow a deploy until it is live or failed [--timeout 30m] give up after that long (exit 4; the deploy goes on)
deploys explain <project>why a project is (not) counted as changed
deploys diff <project>commits and files between what is live and the branch
deploys notes <project> [--json]the same as release notes (Markdown; --json: author as a field)
deploys history <project> [n] [--json]the last n deploys (default 10): when, state, commit, source
deploys logs <project> [lines] [--id <d>]the end of the newest build log (or of deploy <d>), keys masked [--runtime] the running service's log instead (providers with runtimeLogs)
deploys scan start <owner/repo> [branch]Claude Code on this Mac looks for bugs and opens one fix PR (never merges)
deploys scan status [--json] | list | log <id>the newest scans, their PRs and reports
deploys scan start <owner/repo> [branch] --findings <check id>the same, on what a check found
deploys check start <owner/repo> [branch]OSV-Scanner, gitleaks and Semgrep (free, local, read-only)
deploys check show <id>the findings of one check (secrets redacted) (see Autofix)
deploys ai explain|notes|ship <p>ask Claude (your own Anthropic key): why a build failed, plain release notes (--lang en|de), is it safe to ship
deploys ai ask <p> --question "…"your own question about a project (its commits and log go along)
deploys ai slow <p> | risk <p>why its builds take long; risk = ship
deploys ai set-key | verify | model [<id>] | cap [<n>] | status | forget-key(see docs/CLAUDE.md)
deploys open <project> [--dashboard]the site, or its page at Vercel or Render
deploys ignore <p> [--undo] | --listleave a project out of changed and deploy-changed
deploys costs [days] | triggersVercel charges per day; builds nobody started from here
deploys simulate [--days 30] [--json]estimate: what auto-deploy costs a month vs. once a day
deploys ledger [--json]estimate: builds skipped and money saved since auto-deploy was off
deploys price [set <vercel|render> <usd> | unset <p>]your price of one build minute (prices.json)
deploys budget [set <usd a month> [--strict] | off]deploy-changed --yes stops before going over it
deploys whereconfig folder, version, key source, logins
deploys completion zsh|bash|fishtab completion (eval "$(deploys completion zsh)"; fish: deploys completion fish | source)
deploys <command> --helpthe help lines of one command
deploys list [--json]every project on every provider that is on, with its platform
deploys providers [--json]the platforms (providers/*.sh): on or off, set up or not
deploys providers enable|disable <p>switch one on or off (Vercel and Render are on by default)
deploys <p> <verb> ...any provider: json, deploy-json, status, latest, logs, url, ... (docs/PROVIDERS.md); a name may be written <p>:<name>
deploys deploy <p>|<group> [--preview] [--sha <c>] [--wait] [--force "reason"]deploy one project, or a group in its order (docs/TEAM.md)
deploys config [--json] [--refresh]the effective config, and where each value came from
deploys team add|remove <owner/repo> | list | refresh | journalrepos whose deploy-center.json counts
deploys team init <owner/repo>print a deploy-center.json for that repo from this Mac's settings (writes nothing)
deploys hooks install|uninstall|status [<repo>]the pre-push check (integrations/hooks) in a repo, after a pre-push that is there already (core.hooksPath counts)
deploys readonly [on|off]observer mode: commands that change something are refused (a guard against slips, not access control: docs/TEAM.md)
deploys --help | --versionthis help, or the version
deploys autodeploy allow <platform|all> <p>|--all <hours>auto-deploy on for a while (1-168 h)
deploys autodeploy allowed [--json] | revoke <platform|all> <p>|--all
deploys guard [--dry-run]auto-deploy off wherever it is on without an allowance
deploys guard status [--json] | schedule on|off(every 30 minutes; see docs/GUARD.md)
deploys gitlab set-token | forget-tokena GitLab token in the keychain (read from stdin; docs/GITLAB.md)

Vercel commands#

CommandWhat it does
deploys vercel map <p> <owner/repo> [br]say where a project deploys from (GitLab: gitlab.com/group/name, see docs/GITLAB.md)
deploys vercel listprojects and whether a push still deploys them
deploys vercel autodeploy-off <p>|--alldisconnect Git (remembers the repo first)
deploys vercel autodeploy-on <p>|--allconnect Git again from the remembered repo (pushes build again)
deploys vercel rollback <p>production back to the previous deployment
deploys vercel team [<id>]show or set the Vercel team
deploys vercel deploy <p> [--preview] [--sha <c>] [--wait]the newest commit of the remembered repo; --wait follows it until live or failed

Render commands#

CommandWhat it does
deploys render rollback <service>back to the deploy that was live before
deploys render forget-keyremove the Render key from the keychain
deploys render listservices and their auto-deploy setting
deploys render autodeploy-off <s>|--allset auto-deploy to Off for one service, or all
deploys render autodeploy-on <s>|--allauto-deploy "On Commit" again
deploys render deploy <service>deploy the newest commit
deploys render set-keystore the Render API key (read from stdin)

Autofix commands#

CommandWhat it does
deploys autofix [--dry-run] [--only <platform> <p> [--again]]a failed build goes to a Claude Code routine, which opens a fix PR (never deploys)
deploys autofix --preview --only <platform> <p> [--json]what a fire would send (masked log, prompt, routine id); sends nothing
deploys autofix set-token | routine <id> | list | forget-token | prompt | status | sync | schedule on|off