deploy_git
Deploys an app from a Git repository by cloning, building, and running it server-side, with dry-run validation and secure token references.
Instructions
Use when: the app lives in a Git repo. Asynchronous — follow with wait_for_service.
Clones ``repo_url`` server-side (public GitHub by default), then builds
and runs it like ``deploy``. The token reference is resolved server-side
— a raw credential never passes through the tool.
``dry_run=True`` returns the build/config plan diff (env key names only,
values never).
If the repo's ``nerdit.toml`` declares ``[ai.*]`` bindings, each is
injected at launch as ``NERDIT_AI_<NAME>_URL/_KEY/_MODEL``, and the
``default`` binding also sets ``OPENAI_BASE_URL/OPENAI_API_KEY/
OPENAI_MODEL`` — point the app's OpenAI SDK at these; no code change
needed.
``nerdit.toml`` ``[deploy]`` keys — anything else is IGNORED and
reported back in the response ``hints``: ``name``, ``port``, ``gpus``,
``start``, ``health``, ``health_type`` (``http``|``tcp``),
``memory_limit``, ``cpu_limit``, ``volumes``, ``release``, ``cutover``,
``auto_deploy``, ``edge_auth``, ``build_settings``. Generated Node builds run
``scripts.build`` automatically;
override it through ``[deploy.build_settings]`` or use a Dockerfile.
``release`` runs once inside the new image before traffic moves; if it
fails the deploy settles ``failed`` and the image reverts, never the data —
whatever the migration already committed stays, so write idempotent
migrations. ``cutover`` null = zero-downtime swap
when eligible, false = same-port swap.
On a successful non-dry-run deploy the
response carries ``summary`` (app/status/version/public_url), ``hints``
(ordered one-liners, never empty) and ``next_step`` (the structured
follow-up call); a ``dry_run`` plan carries none of the three — read a
plan's advisories from its ``warnings``. On a node in ``path``
proxy mode the app is served at ``/<name>/``, so a frontend must be
built with that base path.
``build_settings`` overrides
preset/install/build/start/node_version/package_manager/subdir/public_env.
``preset`` selects node/nextjs/python/dockerfile; null resets to
repository/default detection.
An existing Dockerfile retains precedence.
Omit it to preserve saved overrides; a null field resets to repository/default,
and ``build: false`` skips compilation.
``public_env`` passes public build-time variables (shown in clear in a dry
run; secret references are refused). Secret mounts are unsupported;
runtime env is unchanged.
SANDBOX: by DEFAULT containers run with all Linux capabilities dropped
(``cap_drop=["ALL"]``) and no-new-privileges — both are operator settings
(``[containers].drop_all_caps`` / ``[containers].no_new_privileges``), so
read the live profile in ``capabilities.sandbox`` rather than assuming: an
operator may have relaxed it. Under that default, an image whose entrypoint
does root work — ``chown``/``chmod`` of its own runtime dirs, dropping
privileges via ``setuid``/``setgid``, writing ``/var/run`` — dies before
your app ever starts. Stock ``nginx`` is the classic trap. Use a non-root
image and a non-root ``USER`` that owns the files it writes: for a static
site, ``nginxinc/nginx-unprivileged`` (listens on **8080**, so set
``port=8080``) or any tiny static server. A crash from this reports
remediation code ``image_needs_privileges`` in ``diagnose_service``. PORT
CONTRACT: the container MUST listen on the declared ``port`` (the tool
argument, else ``nerdit.toml`` ``[deploy].port``, else **8000**) — that is
the only port the daemon publishes and health-checks, so listening anywhere
else fails the health probe with a healthy-looking container. A port below
1024 is NOT the reason a root entrypoint is needed: every container runs on
the docker bridge in its own network namespace (never host networking),
where Docker sets ``net.ipv4.ip_unprivileged_port_start=0``, so binding 80
needs no capability and no root — the chown/setuid work does.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| env | No | Runtime env for the container: values are literal strings, never resolved (a ``${secrets.*}`` reference is passed through as text); a null value deletes that key on redeploy. Secrets go through ``set_secret``, which overrides an ``env`` key of the same name at launch. | |
| ref | No | Branch or tag to clone. Omit for the repository's default branch. Recorded on the app, so ``redeploy_service`` re-clones this ref. | |
| gpus | No | GPUs to reserve for the container (0 = none). Omit to use ``[deploy].gpus``, else the count already recorded on a redeploy, else 0. | |
| name | Yes | App name (lowercase DNS label). A new name creates the app; an existing one redeploys it in place. | |
| port | No | Port the container listens on: the only port published and health-checked. Omit to use ``nerdit.toml`` ``[deploy].port``, else the port already recorded on a redeploy, else 8000. | |
| start | No | Start command run inside the built image (shell syntax). Omit to use ``[deploy].start`` or the buildpack default. | |
| health | No | HTTP health path probed on ``port`` (e.g. ``/health``); the app is ``healthy`` once it answers 2xx. Omit to keep ``[deploy].health`` (or the existing app's probe on redeploy). | |
| subdir | No | Subdirectory of the repo to build (monorepo subtree). Omit to build from the repository root. | |
| vendor | No | GPU vendor to reserve when ``gpus`` > 0 (``nvidia`` or ``amd``); omit to let the daemon choose on a fresh deploy — a redeploy keeps the vendor already recorded. | |
| dry_run | No | true = validate and return the plan (what would change) with zero writes; nothing is built, deployed or audited as a change. | |
| repo_url | Yes | ``https://`` clone URL, on a host the daemon allows (``capabilities.deploy.git_allowed_hosts``, ``github.com`` by default). A URL carrying credentials is refused — pass ``token_ref`` instead. | |
| token_ref | No | Private-repo credential as a *reference*, never a raw token: ``${secrets.KEY}``, ``${secrets.shared.KEY}``, or the literal ``${github.installation}`` on a node linked to an account with the Nerdit GitHub App installed on that repo. Omit for a public repo. | |
| build_settings | No | Build overrides, same keys as ``[deploy.build_settings]`` in ``nerdit.toml``: ``preset`` (node/nextjs/python/dockerfile), ``install``, ``build`` (``false`` skips compilation), ``start``, ``node_version``, ``package_manager``, ``subdir``, ``public_env`` (build-time variables baked into the bundle, never secrets). Commands run inside the build container. | |
| idempotency_key | No | Caller-chosen key: a retry with the same key replays the first result instead of acting twice. Omit and a fresh key is minted per call, so each call acts. |