Skip to content

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:

git push origin main

Cut a production release from a release branch:

git switch -c release/v1
git push -u origin release/v1

Or cut a production release from a release tag:

git tag release/v1.0.0
git push origin refs/tags/release/v1.0.0

The push command does not print a Forge deployment ref. After the push, list routing records for the app:

map versions <app>

Copy the deployment ref from internal versions or aliases, then inspect it:

map --json status <deployment-ref>
map watch <deployment-ref>
map --json evidence <deployment-ref>

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:

deployment://<account-context>/<app-env>/<id>

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 <deployment-ref>
map --json evidence <deployment-ref>

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:

map versions <app>

Publish the reviewed version:

map publish <app> --version <version> --expected-sha <sha>

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:

curl https://my-app.apps.mithran.cloud/

If the hostname still serves the previous version, compare the published pointer and internal versions:

map versions <app>

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.yaml at the deployed commit;
  • deployment ref, status, and evidence;
  • map versions <app> before and after publish when publishing is involved;
  • observed hostname and HTTP result.