Deploy¶
Deploy creates a Forge app version from a Git ref or commit SHA. Forge snapshots source, reviews the app contract, builds the image, starts the runtime, programs routing records, and records evidence for that version.
A deploy does not publish the clean public URL by itself. Publishing is a
separate operator action after a version has reached Succeeded or Promoted.
Before you deploy¶
Confirm these inputs before asking Forge to fetch source or move traffic:
| Area | Owner | Evidence |
|---|---|---|
| GitHub source access | Operator | GitHub App installation includes the repo, and aegis github status --project-repo <owner/repo> --require --json succeeds. |
| Forge onboarding | Operator | map onboard completed for the same repo and installation ref. Keep the JSON output or command transcript. |
| App contract | Developer | The repo has a root mithran.yaml, a Dockerfile, a process that listens on $PORT, and an HTTP 200 readiness response. |
| App identity | Developer and operator | metadata.app_id, served app ref, identity.project_ref, tenant/account/project/app refs, and hostname expectations match the customer account. |
| App environment | Operator | preview, production, or another app_env value is the intended app target. It does not change account context. |
| Access model | Operator | public_edge.exposure and protected access policy match the intended audience. |
For the app runtime contract, see HTTP app contract. For account context and app-environment naming, see Account context and app environments.
Choose a deploy path¶
Use one deploy path per repo unless the operator has a reason to keep both webhooks and customer-owned CI active.
| Path | Use it when | Trigger | Evidence starts with |
|---|---|---|---|
| Built-in GitHub App webhook | The repo can use the standard main and release/* deploy refs. |
A GitHub App push webhook for a built-in deploy ref. |
Pushed ref, then map versions <app>. |
| Direct deploy request | An operator or automation needs to request one deploy explicitly. | map deploy, which posts to /v1/map-control/deploy/request. |
The command response deployment ref. |
| Optional custom CI | The customer needs GitHub Actions or another CI system to decide when to request deploys. | Customer-owned automation posts to /v1/map-control/deploy/request. |
CI run log and deploy response. |
map onboard uses the built-in webhook path by default. It writes
.github/workflows/map-deploy.yml only when run with --with-ci-workflow.
Most repos should start with the built-in webhook path. Add custom CI only when
another system must decide when a deploy request is sent.
Built-in webhook deploys¶
The built-in webhook path does not run builds in GitHub Actions. GitHub sends a webhook, Forge verifies the installation and repo registration, fetches the source through the GitHub App installation, reviews the manifest and source snapshot, builds the image, starts the runtime, and programs routing records.
Built-in webhook intake creates deploy candidates for these refs:
| GitHub ref | Default app environment |
|---|---|
refs/heads/main |
preview |
refs/heads/release/* |
production |
refs/tags/release/* |
production |
Feature branches and tags such as v1.2.3 are not built-in webhook triggers.
When the reviewed manifest declares app_env.*.auto_deploy_refs, Forge can
refine the app environment for those built-in webhook candidates after it
snapshots the manifest. auto_deploy_refs does not make arbitrary refs
deployable through the built-in webhook path.
Cut a preview deploy by pushing main:
Cut a production release from a release branch:
Or cut a production release from a release tag:
The push command does not print a Forge deployment ref. After the push, list routing records for the app:
Copy the deployment ref from internal versions or aliases, then inspect it:
Forge can project best-effort GitHub Deployment status for the pushed commit
and app environment. Treat map --json status, map watch, and
map --json evidence as the authoritative deploy record.
Manifest app environments¶
app_env records app-environment metadata such as branch_pattern,
auto_deploy_refs, image_tag, replica settings, non-secret overrides, and
review policy. Forge uses image_tag, overrides, replicas, and policy metadata
from the resolved app environment during the deploy lifecycle.
Use direct deploy requests or custom CI when a repo needs a trigger outside the built-in webhook refs.
Direct deploy requests¶
Use map deploy when an operator or automation needs to request a deploy
directly:
map deploy \
--repo <owner/repo> \
--env production \
--ref refs/heads/release/v1 \
--installation-ref <installation-ref>
map deploy posts directly to /v1/map-control/deploy/request with the
logged-in map-control token. It does not dispatch GitHub Actions.
Flag meanings:
| Flag | Meaning |
|---|---|
--repo <owner/repo> |
Normalized to github://<owner/repo>. A full repository ref can also be supplied. |
--env <app-env> |
Selects the app environment, such as preview or production. When omitted, the request targets preview. |
--ref <git-ref> |
Requests a Git ref. Use this or --sha, not both. |
--sha <40-hex-sha> |
Requests an explicit commit SHA as source_sha. Use this or --ref, not both. |
--installation-ref <ref> |
Identifies the GitHub App installation that grants Forge source access. Include it for real source fetches. |
--deployment-ref <ref> |
Supplies a deployment ref; otherwise the control plane mints one. |
The CLI rejects a direct deploy command that omits both --ref and --sha.
When --sha is used, it must be a 40-character Git SHA. For production release
evidence, prefer a reviewed ref or SHA that can be tied back to the release
approval record.
The control-plane response includes the deployment ref when the request is accepted:
In text mode, map deploy prints that deployment ref when the response
contains one. With --json, it prints the full control-plane response
unchanged. For operator evidence, keep the deployment_ref, the deploy status
object, the evidence object when present, and remote_authority when returned.
map watch exits successfully only when the deploy reaches Succeeded. It
exits non-zero for terminal failure states such as ReviewBlocked,
BuildFailed, RuntimeFailed, RouteFailed, Failed, Superseded, or
RolledBack.
Optional custom CI¶
Use custom CI only when the customer wants GitHub Actions or another CI system
to decide when to request deploys. The generated workflow is a thin dispatcher:
it authenticates with GitHub Actions OIDC, exchanges that token with Mithran
auth for a short-lived map-control token, then posts the deploy request.
There is no stored Forge deploy secret.
The generated map-deploy.yml workflow triggers on:
| Workflow trigger | Deploy request |
|---|---|
Push to release/** branch |
Pushed SHA to the production app environment. |
Push to tag v[0-9]+.[0-9]+.[0-9]+ |
Tagged SHA to the production app environment. |
Manual workflow_dispatch |
Provided ref, or the workflow run SHA when ref is empty, to the app environment in the dispatch env input. |
The workflow's dispatch env input is the app environment. The customer
account context is separate and comes from the setup endpoint, GitHub App
installation, and optional tenant/account refs. For custom CI in a customer
account, set MAP_CONTROL_ENDPOINT and MAP_AUTH_ENDPOINT from the account
setup values. The generated workflow has no endpoint defaults; it fails clearly
when required Variables are missing.
The workflow reads non-secret repository variables such as
MAP_INSTALLATION_REF, MAP_APP_REF, MAP_TENANT_REF, MAP_ACCOUNT_REF,
MAP_CONTROL_ENDPOINT, MAP_AUTH_ENDPOINT, and MAP_OIDC_AUDIENCE.
The optional workflow has its own trigger policy. Its tag filter
v[0-9]+.[0-9]+.[0-9]+ is not the built-in webhook tag policy; built-in
webhooks use refs/tags/release/*.
Deploy lifecycle¶
Every deploy path enters the same control-plane lifecycle after the deploy request or webhook candidate is accepted:
| Stage | What Forge does | First thing to check on failure |
|---|---|---|
| Trigger | Accepts a built-in webhook candidate, direct request, or custom-CI request. | Ref, request body, repo registration, and installation ref. |
| Source | Fetches the source snapshot through the GitHub App installation. | GitHub App grant, repo onboarding, requested ref or SHA, and installation ref. |
| Review | Reviews mithran.yaml and the source snapshot before build. |
Manifest syntax, unsupported fields, app identity, app env, public edge, and policy metadata. |
| Build | Builds the repo image from the committed source. | Dockerfile, dependency install, build context, and package metadata. |
| Runtime | Starts the app and waits for readiness at the serving probe path Forge checks. | Startup command, $PORT, serving probe response, and runtime configuration. |
| Route | Programs internal version and app-environment routing records. | App ID, route status, exposure, and edge propagation. |
| Smoke and evidence | Records deploy evidence and final status. | Deployment status and map --json evidence <deployment-ref>. |
A healthy deploy ends with:
| Field | Healthy value |
|---|---|
status |
Succeeded |
build_status |
Succeeded |
runtime_status |
Ready |
route_status |
Ready |
For response shapes and evidence fields, see Deploy status and evidence.
If a deploy request is accepted and then fails, keep the deployment ref and inspect the lifecycle stage before retrying. Retrying a failed deploy without changing the source, manifest, installation grant, app environment, or access input usually reproduces the same failure.
Publish after deploy¶
Deploy creates internal versions and app-environment routing records. It does not move
the clean public URL. Use map versions to compare internal versions,
aliases, and the current published record:
Publish the reviewed version:
map publish resolves --version from internal versions. You can also pass
--deployment-ref <deployment-ref>. Forge rejects publish requests for
versions that have not reached Succeeded or Promoted. When
--expected-sha is supplied, Forge rejects the publish if the version records
a different source SHA.
For rollback and pointer behavior, see Versions and publishing.
See it live¶
After publish succeeds, open the published hostname from map versions <app>
or the publish response:
If the hostname still serves the previous version, compare the published pointer and internal versions:
For protected apps, verify both an allowed and a denied request. For access policy, see App access and sharing.
Troubleshooting¶
| Symptom | Check | Action |
|---|---|---|
| No deployment ref appears after a push | Pushed ref, GitHub App grant, onboarding output, and whether custom CI owns deploy triggering. | Push a built-in webhook ref, run map deploy, or use the custom-CI workflow. |
ReviewBlocked |
mithran.yaml, manifest policy metadata, and source review evidence. |
Fix the manifest or source issue and deploy a new commit. |
BuildFailed |
Dockerfile, dependency install, and build context. | Reproduce the image build locally and deploy the fixed commit. |
RuntimeFailed |
Startup command, $PORT, serving probe response, and runtime evidence. |
Fix the process contract and deploy again. |
RouteFailed |
App ref, exposure, route status, and edge propagation. | Inspect map --json evidence; use the route troubleshooting runbook when the hostname is not recognized. |
| Deploy succeeded but the clean URL still serves the previous version | map versions <app> published record. |
Publish the reviewed version with map publish. |
For detailed failure entries, see Troubleshooting.
Evidence to keep¶
Keep these records for production releases and deploy investigations:
- repo owner/name and repository ref;
- GitHub App installation ref;
- tenant, account, and project/app refs;
- app environment and account context;
- pushed ref, direct deploy ref, or custom-CI run URL;
- source commit SHA;
mithran.yamlat the deployed commit;- deployment ref, status, and evidence;
map versions <app>before and after publish when publishing is involved;- observed hostname and HTTP result.